From c9ee6e467c16254c450da84973b8fa1833e5c1f7 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Fri, 11 Mar 2022 19:04:27 +0800 Subject: [PATCH 001/405] refactor: import jest as global; unify import style of some modules (#6898) * refactor: import jest as global * fix react --- .eslintrc.js | 13 +++- __tests__/validate-package-json.test.ts | 1 - .../src/__tests__/index.test.ts | 1 + .../transformImage/__tests__/index.test.ts | 1 + .../__tests__/index.test.ts | 12 ++-- .../src/__tests__/migration.test.ts | 1 + .../src/__tests__/feed.test.ts | 1 + .../src/__tests__/index.test.ts | 1 + .../src/__tests__/linkify.test.ts | 1 + .../src/__tests__/cli.test.ts | 1 + .../src/__tests__/docs.test.ts | 1 + .../src/__tests__/index.test.ts | 5 +- .../src/__tests__/lastUpdate.test.ts | 1 + .../src/__tests__/versions.test.ts | 1 + .../src/markdown/__tests__/linkify.test.ts | 1 + .../src/sidebars/__tests__/generator.test.ts | 1 + .../src/sidebars/__tests__/processor.test.ts | 1 + .../src/theme/MDXComponents/index.tsx | 4 +- .../src/theme/Tabs/index.tsx | 3 +- .../src/components/Collapsible/index.tsx | 2 +- .../src/components/Details/index.tsx | 4 +- .../src/utils/announcementBarUtils.tsx | 7 +- .../src/utils/colorModeUtils.tsx | 3 +- .../DocsPreferredVersionProvider.tsx | 7 +- .../src/utils/docsUtils.tsx | 6 +- .../src/utils/mobileSecondaryMenu.tsx | 7 +- .../src/utils/scrollUtils.tsx | 5 +- .../src/utils/tabGroupChoiceUtils.tsx | 3 +- .../__tests__/update.test.ts | 1 + .../src/__tests__/validationUtils.test.ts | 5 +- .../src/__tests__/emitUtils.test.ts | 1 + .../src/__tests__/jsUtils.test.ts | 1 + .../docusaurus/src/client/LinksCollector.tsx | 4 +- .../__tests__/normalizeLocation.test.ts | 1 + .../docusaurus/src/client/clientEntry.tsx | 5 +- .../src/client/exports/Interpolate.tsx | 4 +- .../exports/__tests__/BrowserOnly.test.tsx | 1 + .../exports/__tests__/useBaseUrl.test.ts | 5 +- .../commands/swizzle/__tests__/index.test.ts | 1 + packages/docusaurus/src/deps.d.ts | 2 +- .../src/server/__tests__/brokenLinks.test.ts | 3 +- .../server/__tests__/duplicateRoutes.test.ts | 1 + .../src/server/__tests__/i18n.test.ts | 3 +- .../docusaurus/src/server/themes/alias.ts | 1 + .../__tests__/translations.test.ts | 3 +- .../__tests__/translationsExtractor.test.ts | 1 + .../src/webpack/__tests__/base.test.ts | 1 + .../src/webpack/__tests__/client.test.ts | 7 +- .../src/webpack/__tests__/server.test.ts | 7 +- .../src/webpack/__tests__/utils.test.ts | 6 +- .../src/webpack/plugins/ChunkAssetPlugin.ts | 4 +- .../lqip-loader/src/__tests__/lqip.test.ts | 4 +- .../lqip-loader/src/__tests__/utils.test.ts | 47 ++++++------- .../_dogfooding/_pages tests/link-tests.tsx | 4 +- .../_pages tests/markdownPageTests.md | 2 +- website/src/components/APITable/index.tsx | 70 +++++++++---------- website/src/data/__tests__/user.test.ts | 2 - .../_components/ShowcaseCard/index.tsx | 4 +- .../_components/ShowcaseTagSelect/index.tsx | 6 +- 59 files changed, 170 insertions(+), 132 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 5fd41c1f8a8f..0b18a8ab9c8f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -166,7 +166,12 @@ module.exports = { // selector: // @ 'ExportDefaultDeclaration > Identifier, ExportNamedDeclaration[source=null] > ExportSpecifier', // message: 'Export in one statement' - // } + // }, + ...['path', 'fs-extra', 'webpack', 'lodash'].map((m) => ({ + selector: `ImportDeclaration[importKind=value]:has(Literal[value=${m}]) > ImportSpecifier[importKind=value]`, + message: + 'Default-import this, both for readability and interoperability with ESM', + })), ], 'no-template-curly-in-string': WARNING, 'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}], @@ -312,5 +317,11 @@ module.exports = { '@typescript-eslint/explicit-module-boundary-types': OFF, }, }, + { + files: ['*.test.ts', '*.test.tsx'], + rules: { + 'import/no-extraneous-dependencies': OFF, + }, + }, ], }; diff --git a/__tests__/validate-package-json.test.ts b/__tests__/validate-package-json.test.ts index 2f9031833aca..9eab91288f5b 100644 --- a/__tests__/validate-package-json.test.ts +++ b/__tests__/validate-package-json.test.ts @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -/* eslint-disable import/no-extraneous-dependencies */ import {Globby} from '@docusaurus/utils'; import fs from 'fs-extra'; diff --git a/packages/docusaurus-logger/src/__tests__/index.test.ts b/packages/docusaurus-logger/src/__tests__/index.test.ts index 5ae55907b774..e78571a0f210 100644 --- a/packages/docusaurus-logger/src/__tests__/index.test.ts +++ b/packages/docusaurus-logger/src/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import logger from '../index'; describe('formatters', () => { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts index dc1ed9e1710c..9ab5161441ec 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import remark from 'remark'; import mdx from 'remark-mdx'; diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts index fa49602667c5..d18b4634e0f8 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts @@ -5,22 +5,20 @@ * LICENSE file in the root directory of this source tree. */ -import {join} from 'path'; +import path from 'path'; import remark from 'remark'; import mdx from 'remark-mdx'; import vfile from 'to-vfile'; import plugin from '..'; -const processFixture = async (name) => { - const path = join(__dirname, '__fixtures__', name); - const file = await vfile.read(path); +const processFixture = async (name: string) => { + const file = await vfile.read(path.join(__dirname, '__fixtures__', name)); const result = await remark().use(mdx).use(plugin).process(file); return result.toString(); }; -const processFixtureAST = async (name) => { - const path = join(__dirname, '__fixtures__', name); - const file = await vfile.read(path); +const processFixtureAST = async (name: string) => { + const file = await vfile.read(path.join(__dirname, '__fixtures__', name)); return remark().use(mdx).use(plugin).parse(file); }; diff --git a/packages/docusaurus-migrate/src/__tests__/migration.test.ts b/packages/docusaurus-migrate/src/__tests__/migration.test.ts index d3b6bd631554..8129bab62030 100644 --- a/packages/docusaurus-migrate/src/__tests__/migration.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migration.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {migrateDocusaurusProject} from '../index'; import path from 'path'; import fs from 'fs-extra'; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index bd77b29115fd..6ac05193ce32 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import fs from 'fs-extra'; import {createBlogFeedFiles} from '../feed'; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index b3fad925a6c4..2f7668091330 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import pluginContentBlog from '../index'; import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types'; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts index d745399331a3..bdfffa7ffbe8 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import fs from 'fs-extra'; import path from 'path'; import {linkify, type LinkifyParams, getSourceToPermalink} from '../blogUtils'; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 25f438bbe114..c9235e35cfac 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import {cliDocsVersionCommand} from '../cli'; import type { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 0c1d36d50a40..5348c845c6b1 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import {loadContext} from '@docusaurus/core/src/server/index'; import { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index bcbaa522a8a5..885916099cd7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import {isMatch} from 'picomatch'; import commander from 'commander'; @@ -29,7 +30,7 @@ import type { } from '../sidebars/types'; import {toSidebarsProp} from '../props'; -import {validate} from 'webpack'; +import webpack from 'webpack'; import {DefaultSidebarItemsGenerator} from '../sidebars/generator'; import {DisabledSidebars} from '../sidebars'; @@ -311,7 +312,7 @@ describe('simple website', () => { undefined, content, ); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts index 01356ccdcb05..2ec2a16e4caf 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import fs from 'fs-extra'; import path from 'path'; import shell from 'shelljs'; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index 3ac367db6860..aed0e9ec2591 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import { getVersionsFilePath, diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index 79c2fc91f58c..56ed2072fad0 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import fs from 'fs-extra'; import path from 'path'; import {linkify} from '../linkify'; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts index 73c2357cd932..5491b18e67de 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {DefaultSidebarItemsGenerator} from '../generator'; import type {SidebarItemsGenerator} from '../types'; import {DefaultNumberPrefixParser} from '../../numberPrefix'; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts index 68d65a2d3a2c..f5021fd8d941 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {processSidebars} from '../processor'; import type { SidebarItem, diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx index 2cdcf65db410..8f9605c2a5a1 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx @@ -6,8 +6,8 @@ */ import React, { - type ComponentProps, isValidElement, + type ComponentProps, type ReactElement, } from 'react'; import Head from '@docusaurus/Head'; @@ -52,7 +52,7 @@ const MDXComponents: MDXComponentsObject = { const shouldBeInline = React.Children.toArray(props.children).every( (el) => (typeof el === 'string' && !el.includes('\n')) || - (React.isValidElement(el) && inlineElements.includes(el.props.mdxType)), + (isValidElement(el) && inlineElements.includes(el.props.mdxType)), ); return shouldBeInline ? : ; diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx index 6036ffad40e8..efaae4c05501 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx @@ -8,7 +8,6 @@ import React, { useState, cloneElement, - Children, isValidElement, type ReactElement, } from 'react'; @@ -40,7 +39,7 @@ function TabsComponent(props: Props): JSX.Element { groupId, className, } = props; - const children = Children.map(props.children, (child) => { + const children = React.Children.map(props.children, (child) => { if (isValidElement(child) && isTabItem(child)) { return child; } diff --git a/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx b/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx index f1af0aa2932f..a608d03772fc 100644 --- a/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx @@ -11,11 +11,11 @@ import React, { useEffect, useRef, useCallback, + useLayoutEffect, type RefObject, type Dispatch, type SetStateAction, type ReactNode, - useLayoutEffect, } from 'react'; const DefaultAnimationEasing = 'ease-in-out'; diff --git a/packages/docusaurus-theme-common/src/components/Details/index.tsx b/packages/docusaurus-theme-common/src/components/Details/index.tsx index 541568432c20..d5b1b77f5a15 100644 --- a/packages/docusaurus-theme-common/src/components/Details/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Details/index.tsx @@ -6,10 +6,10 @@ */ import React, { - type ComponentProps, - type ReactElement, useRef, useState, + type ComponentProps, + type ReactElement, } from 'react'; import useIsBrowser from '@docusaurus/useIsBrowser'; import clsx from 'clsx'; diff --git a/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx b/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx index 0983cca16756..93eb7cbeff2e 100644 --- a/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx @@ -10,9 +10,8 @@ import React, { useEffect, useCallback, useMemo, - type ReactNode, useContext, - createContext, + type ReactNode, } from 'react'; import useIsBrowser from '@docusaurus/useIsBrowser'; import {createStorageSlot} from './storageUtils'; @@ -96,7 +95,9 @@ const useAnnouncementBarContextValue = (): AnnouncementBarAPI => { ); }; -const AnnouncementBarContext = createContext(null); +const AnnouncementBarContext = React.createContext( + null, +); export function AnnouncementBarProvider({ children, diff --git a/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx b/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx index c955206c1a63..d662fb4caf8f 100644 --- a/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx @@ -11,6 +11,7 @@ import React, { useEffect, useContext, useMemo, + useRef, type ReactNode, } from 'react'; import {ReactContextError} from './reactUtils'; @@ -96,7 +97,7 @@ function useColorModeContextValue(): ColorModeContextValue { // be reset to dark when exiting print mode, disregarding user settings. When // the listener fires only because of a print/screen switch, we don't change // color mode. See https://github.com/facebook/docusaurus/pull/6490 - const previousMediaIsPrint = React.useRef(false); + const previousMediaIsPrint = useRef(false); useEffect(() => { if (disableSwitch && !respectPrefersColorScheme) { diff --git a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx index fb9c534ef4c6..49c74aa7b09c 100644 --- a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx @@ -6,12 +6,11 @@ */ import React, { - createContext, - type ReactNode, useContext, useEffect, useMemo, useState, + type ReactNode, } from 'react'; import {useThemeConfig, type DocsVersionPersistence} from '../useThemeConfig'; import {isDocsPluginEnabled} from '../docsUtils'; @@ -131,7 +130,9 @@ function useContextValue() { type DocsPreferredVersionContextValue = ReturnType; -const Context = createContext(null); +const Context = React.createContext( + null, +); export function DocsPreferredVersionContextProvider({ children, diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index be21b456b30d..f6863ce2ded5 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {createContext, type ReactNode, useContext} from 'react'; +import React, {type ReactNode, useContext} from 'react'; import { useActivePlugin, useAllDocsData, @@ -29,7 +29,7 @@ export const isDocsPluginEnabled: boolean = !!useAllDocsData; // Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx const EmptyContextValue: unique symbol = Symbol('EmptyContext'); -const DocsVersionContext = createContext< +const DocsVersionContext = React.createContext< PropVersionMetadata | typeof EmptyContextValue >(EmptyContextValue); @@ -69,7 +69,7 @@ export function useDocById(id: string | undefined): PropVersionDoc | undefined { return doc; } -const DocsSidebarContext = createContext< +const DocsSidebarContext = React.createContext< PropSidebar | null | typeof EmptyContextValue >(EmptyContextValue); diff --git a/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx b/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx index 94cccc2aed65..ed898a903317 100644 --- a/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx +++ b/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx @@ -7,12 +7,11 @@ import React, { useState, - type ReactNode, useContext, - createContext, useEffect, - type ComponentType, useMemo, + type ReactNode, + type ComponentType, } from 'react'; import {ReactContextError} from './reactUtils'; @@ -46,7 +45,7 @@ function useContextValue() { type ContextValue = ReturnType; -const Context = createContext(null); +const Context = React.createContext(null); export function MobileSecondaryMenuProvider({ children, diff --git a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx index 7c4fa3003373..74e372a1d999 100644 --- a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx @@ -6,14 +6,13 @@ */ import React, { - createContext, - type ReactNode, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, + type ReactNode, } from 'react'; import {useDynamicCallback, ReactContextError} from './reactUtils'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; @@ -57,7 +56,7 @@ function useScrollControllerContextValue(): ScrollController { ); } -const ScrollMonitorContext = createContext( +const ScrollMonitorContext = React.createContext( undefined, ); diff --git a/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx b/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx index 4348a74a986a..02ad080f8c19 100644 --- a/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx @@ -9,7 +9,6 @@ import React, { useState, useCallback, useEffect, - createContext, useMemo, useContext, type ReactNode, @@ -24,7 +23,7 @@ type TabGroupChoiceContextValue = { readonly setTabGroupChoices: (groupId: string, newChoice: string) => void; }; -const TabGroupChoiceContext = createContext< +const TabGroupChoiceContext = React.createContext< TabGroupChoiceContextValue | undefined >(undefined); diff --git a/packages/docusaurus-theme-translations/__tests__/update.test.ts b/packages/docusaurus-theme-translations/__tests__/update.test.ts index b76e11d33a65..23778fb85445 100644 --- a/packages/docusaurus-theme-translations/__tests__/update.test.ts +++ b/packages/docusaurus-theme-translations/__tests__/update.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {extractThemeCodeMessages} from '../update'; import path from 'path'; import fs from 'fs-extra'; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts index 8da4c3d1ed28..f52ec99b0bea 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import Joi from '../Joi'; import {JoiFrontMatter} from '../JoiFrontMatter'; import {validateFrontMatter} from '../validationUtils'; @@ -21,7 +22,9 @@ describe('validateFrontMatter', () => { }); test('should reject bad values', () => { - const consoleError = jest.spyOn(console, 'error').mockImplementation(); + const consoleError = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); const schema = Joi.object<{test: string}>({ test: Joi.string(), }); diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index da0273cc7a4d..8f10d21b1a7e 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {genChunkName, readOutputHTMLFile, generate} from '../emitUtils'; import path from 'path'; import fs from 'fs-extra'; diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index d2b9aea23117..acba208ffbc0 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import { removeSuffix, removePrefix, diff --git a/packages/docusaurus/src/client/LinksCollector.tsx b/packages/docusaurus/src/client/LinksCollector.tsx index 70009f093c9a..33580a6e8240 100644 --- a/packages/docusaurus/src/client/LinksCollector.tsx +++ b/packages/docusaurus/src/client/LinksCollector.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode, useContext, createContext} from 'react'; +import React, {type ReactNode, useContext} from 'react'; type LinksCollector = { collectLink: (link: string) => void; @@ -26,7 +26,7 @@ export const createStatefulLinksCollector = (): StatefulLinksCollector => { }; }; -const Context = createContext({ +const Context = React.createContext({ collectLink: () => { // noop by default for client // we only use the broken links checker server-side diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts index bb6e92738921..478c1f146a5c 100644 --- a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts +++ b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import normalizeLocation from '../normalizeLocation'; describe('normalizeLocation', () => { diff --git a/packages/docusaurus/src/client/clientEntry.tsx b/packages/docusaurus/src/client/clientEntry.tsx index db766906b996..bb5ecdf3e966 100644 --- a/packages/docusaurus/src/client/clientEntry.tsx +++ b/packages/docusaurus/src/client/clientEntry.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import {hydrate, render} from 'react-dom'; +import ReactDOM from 'react-dom'; import {BrowserRouter} from 'react-router-dom'; import {HelmetProvider} from 'react-helmet-async'; @@ -30,7 +30,8 @@ if (ExecutionEnvironment.canUseDOM) { // first-load experience. // For development, there is no existing markup so we had to render it. // We also preload async component to avoid first-load loading screen. - const renderMethod = process.env.NODE_ENV === 'production' ? hydrate : render; + const renderMethod = + process.env.NODE_ENV === 'production' ? ReactDOM.hydrate : ReactDOM.render; preload(routes, window.location.pathname).then(() => { renderMethod( diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx index 323369b3bac4..8b894f7032f7 100644 --- a/packages/docusaurus/src/client/exports/Interpolate.tsx +++ b/packages/docusaurus/src/client/exports/Interpolate.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode} from 'react'; +import React, {isValidElement, type ReactNode} from 'react'; import type { InterpolateProps, InterpolateValues, @@ -49,7 +49,7 @@ export function interpolate( const value = values?.[key]; if (typeof value !== 'undefined') { - const element = React.isValidElement(value) + const element = isValidElement(value) ? value : // For non-React elements: basic primitive->string conversion String(value); diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index 89161383b5ed..c1264c22161b 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import React from 'react'; import renderer from 'react-test-renderer'; import BrowserOnly from '../BrowserOnly'; diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts index 2aec76be8ad9..e6c8dbc612f8 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts @@ -5,12 +5,13 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl'; import useDocusaurusContext from '../useDocusaurusContext'; -jest.mock('../useDocusaurusContext', () => jest.fn(), {virtual: true}); +jest.mock('../useDocusaurusContext'); -const mockedContext = useDocusaurusContext; +const mockedContext = useDocusaurusContext as jest.Mock; const forcePrepend = {forcePrependBaseUrl: true}; diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts index f1bf3de6c580..37504725f299 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import fs from 'fs-extra'; import {ThemePath, createTempSiteDir, Components} from './testUtils'; diff --git a/packages/docusaurus/src/deps.d.ts b/packages/docusaurus/src/deps.d.ts index 8d4bb2d8ad5f..fc3a7287ff55 100644 --- a/packages/docusaurus/src/deps.d.ts +++ b/packages/docusaurus/src/deps.d.ts @@ -62,7 +62,7 @@ declare module '@slorber/static-site-generator-webpack-plugin' { } declare module 'webpack/lib/HotModuleReplacementPlugin' { - import {HotModuleReplacementPlugin} from 'webpack'; + import type {HotModuleReplacementPlugin} from 'webpack'; export default HotModuleReplacementPlugin; } diff --git a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts index 45ad7cb3f840..8e923a24818f 100644 --- a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts +++ b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import _ from 'lodash'; import {handleBrokenLinks} from '../brokenLinks'; @@ -157,7 +158,7 @@ describe('handleBrokenLinks', () => { test('no-op for ignore', async () => { // In any case, _.mapValues will always be called, unless handleBrokenLinks // has already bailed - const lodashMock = jest.spyOn(_, 'mapValues').mockImplementation(); + const lodashMock = jest.spyOn(_, 'mapValues'); await handleBrokenLinks({ allCollectedLinks, onBrokenLinks: 'ignore', diff --git a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts b/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts index 8da06f2da2af..61308eef0207 100644 --- a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts +++ b/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {handleDuplicateRoutes} from '../duplicateRoutes'; import type {RouteConfig} from '@docusaurus/types'; diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index a78e5fbf3f93..d78679ff70e3 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import {loadI18n, localizePath, getDefaultLocaleConfig} from '../i18n'; import {DEFAULT_I18N_CONFIG} from '../configValidation'; import path from 'path'; @@ -79,7 +80,7 @@ describe('defaultLocaleConfig', () => { }); describe('loadI18n', () => { - const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); beforeEach(() => { consoleSpy.mockClear(); }); diff --git a/packages/docusaurus/src/server/themes/alias.ts b/packages/docusaurus/src/server/themes/alias.ts index c3f7a5952ef7..0a63d80a832d 100644 --- a/packages/docusaurus/src/server/themes/alias.ts +++ b/packages/docusaurus/src/server/themes/alias.ts @@ -20,6 +20,7 @@ export function sortAliases(aliases: ThemeAliases): ThemeAliases { const entries = _.sortBy(Object.entries(aliases), ([alias]) => alias); // @theme/NavbarItem should be after @theme/NavbarItem/LocaleDropdown entries.sort(([alias1], [alias2]) => + // eslint-disable-next-line no-nested-ternary alias1.includes(`${alias2}/`) ? -1 : alias2.includes(`${alias1}/`) ? 1 : 0, ); return Object.fromEntries(entries); diff --git a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts index 6c3273e45fed..305c5a8aeb54 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import { ensureTranslationFileContent, writeTranslationFileContent, @@ -560,7 +561,7 @@ describe('getPluginsDefaultCodeTranslationMessages', () => { }); describe('applyDefaultCodeTranslations', () => { - const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); beforeEach(() => { consoleSpy.mockClear(); }); diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index ae482052e3dd..dd333ebde359 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import fs from 'fs-extra'; import tmp from 'tmp-promise'; import { diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts index 8e2ccb9703dc..397781eb84d8 100644 --- a/packages/docusaurus/src/webpack/__tests__/base.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import { diff --git a/packages/docusaurus/src/webpack/__tests__/client.test.ts b/packages/docusaurus/src/webpack/__tests__/client.test.ts index 17f7815a2ec5..e5e526a915d4 100644 --- a/packages/docusaurus/src/webpack/__tests__/client.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/client.test.ts @@ -5,7 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {validate} from 'webpack'; +import {jest} from '@jest/globals'; +import webpack from 'webpack'; import createClientConfig from '../client'; import loadSetup from '../../server/__tests__/testUtils'; @@ -15,7 +16,7 @@ describe('webpack dev config', () => { console.log = jest.fn(); const props = await loadSetup('simple'); const config = await createClientConfig(props); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); @@ -23,7 +24,7 @@ describe('webpack dev config', () => { console.log = jest.fn(); const props = await loadSetup('custom'); const config = await createClientConfig(props); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); }); diff --git a/packages/docusaurus/src/webpack/__tests__/server.test.ts b/packages/docusaurus/src/webpack/__tests__/server.test.ts index 9c612f492c4e..6be134ac5faf 100644 --- a/packages/docusaurus/src/webpack/__tests__/server.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/server.test.ts @@ -5,7 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {validate} from 'webpack'; +import {jest} from '@jest/globals'; +import webpack from 'webpack'; import createServerConfig from '../server'; import loadSetup from '../../server/__tests__/testUtils'; @@ -15,7 +16,7 @@ describe('webpack production config', () => { console.log = jest.fn(); const props = await loadSetup('simple'); const config = await createServerConfig({props}); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); @@ -23,7 +24,7 @@ describe('webpack production config', () => { console.log = jest.fn(); const props = await loadSetup('custom'); const config = await createServerConfig({props}); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); }); diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index e6fdb6d3297f..1dc3fb7fb259 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {validate, type Configuration, type RuleSetRule} from 'webpack'; +import webpack, {type Configuration, type RuleSetRule} from 'webpack'; import path from 'path'; import { @@ -86,7 +86,7 @@ describe('extending generated webpack config', () => { filename: 'new.bundle.js', }, }); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); @@ -116,7 +116,7 @@ describe('extending generated webpack config', () => { filename: 'new.bundle.js', }, }); - const errors = validate(config); + const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); diff --git a/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts b/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts index ea2f4fd349db..b1eaf0f527eb 100644 --- a/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts +++ b/packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {Template, type Compiler} from 'webpack'; +import webpack, {type Compiler} from 'webpack'; const pluginName = 'chunk-asset-plugin'; @@ -48,7 +48,7 @@ export default class ChunkAssetPlugin { chunkNameToId, )}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`, ); - return Template.asString(buf); + return webpack.Template.asString(buf); }); }); } diff --git a/packages/lqip-loader/src/__tests__/lqip.test.ts b/packages/lqip-loader/src/__tests__/lqip.test.ts index 22f7f1ce5646..180be8b0f046 100644 --- a/packages/lqip-loader/src/__tests__/lqip.test.ts +++ b/packages/lqip-loader/src/__tests__/lqip.test.ts @@ -13,7 +13,9 @@ describe('lqip library', () => { const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg'); it('should reject unknown or unsupported file format', async () => { - await expect(lqip.base64(invalidPath)).rejects.toBeTruthy(); + await expect(lqip.base64(invalidPath)).rejects.toThrow( + /Error: Input file is missing or uses unsupported image format, lqip v.*/, + ); }); it('should generate a valid base64', async () => { diff --git a/packages/lqip-loader/src/__tests__/utils.test.ts b/packages/lqip-loader/src/__tests__/utils.test.ts index 960cfaa98420..f0bd6d021f91 100644 --- a/packages/lqip-loader/src/__tests__/utils.test.ts +++ b/packages/lqip-loader/src/__tests__/utils.test.ts @@ -11,36 +11,35 @@ import type {Palette} from 'node-vibrant/lib/color'; import {toPalette, toBase64} from '../utils'; -describe('lqip-loader', () => { - describe('toBase64', () => { - test('should return a properly formatted Base64 image string', () => { - const expected = 'data:image/jpeg;base64,aGVsbG8gd29ybGQ='; - const mockedMimeType = 'image/jpeg'; - const mockedBase64Data = Buffer.from('hello world'); - expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual(expected); - }); +describe('toBase64', () => { + test('should return a properly formatted Base64 image string', () => { + const mockedMimeType = 'image/jpeg'; + const mockedBase64Data = Buffer.from('hello world'); + expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual( + 'data:image/jpeg;base64,aGVsbG8gd29ybGQ=', + ); }); +}); - describe('toPalette', () => { - let correctTestSwatch: Palette = {}; - let testSwatchWithNull: Palette & {Vibrant?: null} = {}; +describe('toPalette', () => { + let correctTestSwatch: Palette = {}; + let testSwatchWithNull: Palette & {Vibrant?: null} = {}; - beforeAll(() => { - const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg'); - const vibrant = new Vibrant(imgPath, {}); + beforeAll(() => { + const imgPath = path.join(__dirname, '__fixtures__/endi.jpg'); + const vibrant = new Vibrant(imgPath, {}); - return vibrant.getPalette().then((palette) => { - correctTestSwatch = {...palette}; - testSwatchWithNull = {...palette, Vibrant: null}; - }); + return vibrant.getPalette().then((palette) => { + correctTestSwatch = {...palette}; + testSwatchWithNull = {...palette, Vibrant: null}; }); + }); - it('should return 6 hex colours sorted by popularity', () => { - expect(toPalette(correctTestSwatch)).toHaveLength(6); - }); + it('should return 6 hex colours sorted by popularity', () => { + expect(toPalette(correctTestSwatch)).toHaveLength(6); + }); - it('should return 5 hex colours with no errors if a palette was incomplete', () => { - expect(toPalette(testSwatchWithNull)).toHaveLength(5); - }); + it('should return 5 hex colours with no errors if a palette was incomplete', () => { + expect(toPalette(testSwatchWithNull)).toHaveLength(5); }); }); diff --git a/website/_dogfooding/_pages tests/link-tests.tsx b/website/_dogfooding/_pages tests/link-tests.tsx index bfd7364fd18e..d0afa2ef4f0a 100644 --- a/website/_dogfooding/_pages tests/link-tests.tsx +++ b/website/_dogfooding/_pages tests/link-tests.tsx @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import React, {useRef} from 'react'; import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; export default function LinkTest(): JSX.Element { - const anchorRef = React.useRef(null); + const anchorRef = useRef(null); return (
diff --git a/website/_dogfooding/_pages tests/markdownPageTests.md b/website/_dogfooding/_pages tests/markdownPageTests.md index 2f7ecdcb8f78..0f1ba8ec8004 100644 --- a/website/_dogfooding/_pages tests/markdownPageTests.md +++ b/website/_dogfooding/_pages tests/markdownPageTests.md @@ -102,7 +102,7 @@ import MyComponentSource from '!!raw-loader!@site/src/pages/examples/\_myCompone ```jsx live function Demo() { - React.useEffect(() => console.log('mount'), []); + useEffect(() => console.log('mount'), []); return null; } ``` diff --git a/website/src/components/APITable/index.tsx b/website/src/components/APITable/index.tsx index aef73f87280c..5608d543b5c8 100644 --- a/website/src/components/APITable/index.tsx +++ b/website/src/components/APITable/index.tsx @@ -6,14 +6,12 @@ */ import React, { - Children, type ComponentProps, type ReactElement, type ReactNode, isValidElement, useRef, useEffect, - forwardRef, } from 'react'; import {useHistory} from '@docusaurus/router'; import styles from './styles.module.css'; @@ -27,41 +25,41 @@ interface Props { function getText(node: ReactElement): string { let curNode: ReactNode = node; while (isValidElement(curNode)) { - [curNode] = Children.toArray(curNode.props.children); + [curNode] = React.Children.toArray(curNode.props.children); } return curNode as string; } -const APITableRow = forwardRef( - ( - { - name, - children, - }: {name: string | undefined; children: ReactElement>}, - ref: React.ForwardedRef, - ) => { - const entryName = getText(children); - const id = name ? `${name}-${entryName}` : entryName; - const anchor = `#${id}`; - const history = useHistory(); - return ( - { +function APITableRow( + { + name, + children, + }: {name: string | undefined; children: ReactElement>}, + ref: React.ForwardedRef, +) { + const entryName = getText(children); + const id = name ? `${name}-${entryName}` : entryName; + const anchor = `#${id}`; + const history = useHistory(); + return ( + { + history.push(anchor); + }} + onKeyDown={(e: React.KeyboardEvent) => { + if (e.key === 'Enter') { history.push(anchor); - }} - onKeyDown={(e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - history.push(anchor); - } - }}> - {children.props.children} - - ); - }, -); + } + }}> + {children.props.children} + + ); +} + +const APITableRowComp = React.forwardRef(APITableRow); /* * Note: this is not a quite robust component since it makes a lot of @@ -69,19 +67,19 @@ const APITableRow = forwardRef( * should be generally correct in the MDX context. */ export default function APITable({children, name}: Props): JSX.Element { - const [thead, tbody] = Children.toArray( + const [thead, tbody] = React.Children.toArray( children.props.children, ) as ReactElement[]; const highlightedRow = useRef(null); useEffect(() => { highlightedRow.current?.focus(); }, [highlightedRow]); - const rows = Children.map( + const rows = React.Children.map( tbody.props.children, (row: ReactElement>) => ( - + {row} - + ), ); diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index 1489ff70db76..183d9c37eeb6 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -6,12 +6,10 @@ */ import {TagList, sortedUsers, type User} from '../users'; -// eslint-disable-next-line import/no-extraneous-dependencies import {Joi} from '@docusaurus/utils-validation'; import fs from 'fs-extra'; import path from 'path'; -// eslint-disable-next-line import/no-extraneous-dependencies import imageSize from 'image-size'; declare global { diff --git a/website/src/pages/showcase/_components/ShowcaseCard/index.tsx b/website/src/pages/showcase/_components/ShowcaseCard/index.tsx index 61ad51a292da..a09b4c5e4909 100644 --- a/website/src/pages/showcase/_components/ShowcaseCard/index.tsx +++ b/website/src/pages/showcase/_components/ShowcaseCard/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {memo} from 'react'; +import React from 'react'; import clsx from 'clsx'; import Image from '@theme/IdealImage'; import Link from '@docusaurus/Link'; @@ -95,4 +95,4 @@ function ShowcaseCard({user}: {user: User}) { ); } -export default memo(ShowcaseCard); +export default React.memo(ShowcaseCard); diff --git a/website/src/pages/showcase/_components/ShowcaseTagSelect/index.tsx b/website/src/pages/showcase/_components/ShowcaseTagSelect/index.tsx index d0d58328a4f2..29ed978841b9 100644 --- a/website/src/pages/showcase/_components/ShowcaseTagSelect/index.tsx +++ b/website/src/pages/showcase/_components/ShowcaseTagSelect/index.tsx @@ -6,12 +6,12 @@ */ import React, { - type ComponentProps, - type ReactNode, - type ReactElement, useCallback, useState, useEffect, + type ComponentProps, + type ReactNode, + type ReactElement, } from 'react'; import {useHistory, useLocation} from '@docusaurus/router'; import {toggleListItem} from '@site/src/utils/jsUtils'; From 1efc6c609185c780c03d6205015b998e3ec24c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 11 Mar 2022 14:55:53 +0100 Subject: [PATCH 002/405] refactor(theme-classic): split theme footer into smaller components + swizzle config (#6894) Co-authored-by: Joshua Chen --- .../src/getSwizzleConfig.ts | 53 ++++- .../src/theme-classic.d.ts | 73 ++++++- .../src/theme/Footer/Copyright/index.tsx | 22 +++ .../src/theme/Footer/Layout/index.tsx | 34 ++++ .../src/theme/Footer/LinkItem/index.tsx | 38 ++++ .../theme/Footer/Links/MultiColumn/index.tsx | 53 +++++ .../src/theme/Footer/Links/Simple/index.tsx | 44 +++++ .../src/theme/Footer/Links/index.tsx | 21 ++ .../src/theme/Footer/Logo/index.tsx | 41 ++++ .../theme/Footer/{ => Logo}/styles.module.css | 0 .../src/theme/Footer/index.tsx | 182 ++---------------- packages/docusaurus-theme-common/src/index.ts | 3 + .../src/utils/footerUtils.ts | 14 ++ .../src/utils/useThemeConfig.ts | 18 +- 14 files changed, 416 insertions(+), 180 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Layout/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Links/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/Footer/Logo/index.tsx rename packages/docusaurus-theme-classic/src/theme/Footer/{ => Logo}/styles.module.css (100%) create mode 100644 packages/docusaurus-theme-common/src/utils/footerUtils.ts diff --git a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts index 9c2385114b69..3bf2cac6f652 100644 --- a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts +++ b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts @@ -37,11 +37,62 @@ export default function getSwizzleConfig(): SwizzleConfig { }, Footer: { actions: { - eject: 'unsafe', // TODO split footer into smaller parts + eject: 'safe', wrap: 'safe', }, description: "The footer component of you site's layout", }, + 'Footer/Copyright': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The footer copyright', + }, + 'Footer/Layout': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The footer main layout component', + }, + 'Footer/LinkItem': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The footer link item component', + }, + 'Footer/Links': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The footer component rendering the footer links', + }, + 'Footer/Links/MultiColumn': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The footer component rendering the footer links with a multi-column layout', + }, + 'Footer/Links/Simple': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The footer component rendering the footer links with a simple layout (single row)', + }, + 'Footer/Logo': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The footer logo', + }, IconArrow: { actions: { eject: 'safe', diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index e6b4359b7a3d..bd926b51379d 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -205,7 +205,7 @@ declare module '@theme/DocSidebar/Desktop/Content' { readonly sidebar: readonly PropSidebarItem[]; } - export default function CollapseButton(props: Props): JSX.Element; + export default function Content(props: Props): JSX.Element; } declare module '@theme/DocSidebar/Desktop/CollapseButton' { @@ -280,6 +280,77 @@ declare module '@theme/Footer' { export default function Footer(): JSX.Element | null; } +declare module '@theme/Footer/Logo' { + import type {FooterLogo} from '@docusaurus/theme-common'; + + export interface Props { + logo: FooterLogo; + } + + export default function FooterLogo(props: Props): JSX.Element; +} + +declare module '@theme/Footer/Copyright' { + export interface Props { + copyright: string; + } + + export default function FooterCopyright(props: Props): JSX.Element; +} + +declare module '@theme/Footer/LinkItem' { + import type {FooterLinkItem} from '@docusaurus/theme-common'; + + export interface Props { + item: FooterLinkItem; + } + + export default function FooterLinkItem(props: Props): JSX.Element; +} + +declare module '@theme/Footer/Layout' { + import type {ReactNode} from 'react'; + + export interface Props { + style: 'light' | 'dark'; + links: ReactNode; + logo: ReactNode; + copyright: ReactNode; + } + + export default function FooterLayout(props: Props): JSX.Element; +} + +declare module '@theme/Footer/Links' { + import type {Footer} from '@docusaurus/theme-common'; + + export interface Props { + links: Footer['links']; + } + + export default function FooterLinks(props: Props): JSX.Element; +} + +declare module '@theme/Footer/Links/MultiColumn' { + import type {MultiColumnFooter} from '@docusaurus/theme-common'; + + export interface Props { + columns: MultiColumnFooter['links']; + } + + export default function FooterLinksMultiColumn(props: Props): JSX.Element; +} + +declare module '@theme/Footer/Links/Simple' { + import type {SimpleFooter} from '@docusaurus/theme-common'; + + export interface Props { + links: SimpleFooter['links']; + } + + export default function FooterLinksSimple(props: Props): JSX.Element; +} + declare module '@theme/Heading' { import type {ComponentProps} from 'react'; diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx new file mode 100644 index 000000000000..eaa98f6ab01f --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import type {Props} from '@theme/Footer/Copyright'; + +export default function FooterCopyright({copyright}: Props): JSX.Element { + return ( +
+ ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Layout/index.tsx new file mode 100644 index 000000000000..bb22f31f5b39 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Layout/index.tsx @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import type {Props} from '@theme/Footer/Layout'; + +export default function FooterLayout({ + style, + links, + logo, + copyright, +}: Props): JSX.Element { + return ( +
+
+ {links} + {(logo || copyright) && ( +
+ {logo &&
{logo}
} + {copyright} +
+ )} +
+
+ ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx new file mode 100644 index 000000000000..7ae87c588540 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; + +import Link from '@docusaurus/Link'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import isInternalUrl from '@docusaurus/isInternalUrl'; +import IconExternalLink from '@theme/IconExternalLink'; +import type {Props} from '@theme/Footer/LinkItem'; + +export default function FooterLinkItem({item}: Props): JSX.Element { + const {to, href, label, prependBaseUrlToHref, ...props} = item; + const toUrl = useBaseUrl(to); + const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); + + return ( + + + {label} + {href && !isInternalUrl(href) && } + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx new file mode 100644 index 000000000000..9616c34912ef --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx @@ -0,0 +1,53 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import type {Props} from '@theme/Footer/Links/MultiColumn'; +import LinkItem from '@theme/Footer/LinkItem'; + +type ColumnType = Props['columns'][number]; +type ColumnItemType = ColumnType['items'][number]; + +function ColumnLinkItem({item}: {item: ColumnItemType}) { + return item.html ? ( +
  • + ) : ( +
  • + +
  • + ); +} + +function Column({column}: {column: ColumnType}) { + return ( +
    +
    {column.title}
    +
      + {column.items.map((item, i) => ( + + ))} +
    +
    + ); +} + +export default function FooterLinksMultiColumn({columns}: Props): JSX.Element { + return ( +
    + {columns.map((column, i) => ( + + ))} +
    + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx new file mode 100644 index 000000000000..fc0b023f02fd --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import type {Props} from '@theme/Footer/Links/Simple'; +import LinkItem from '@theme/Footer/LinkItem'; + +function Separator() { + return ·; +} + +function SimpleLinkItem({item}: {item: Props['links'][number]}) { + return item.html ? ( + + ) : ( + + ); +} + +export default function FooterLinksSimple({links}: Props): JSX.Element { + return ( +
    +
    + {links.map((item, i) => ( + + + {links.length !== i + 1 && } + + ))} +
    +
    + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/index.tsx new file mode 100644 index 000000000000..44e553e5390e --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/index.tsx @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; + +import {isMultiColumnFooterLinks} from '@docusaurus/theme-common'; +import type {Props} from '@theme/Footer/Links'; +import FooterLinksMultiColumn from '@theme/Footer/Links/MultiColumn'; +import FooterLinksSimple from '@theme/Footer/Links/Simple'; + +export default function FooterLinks({links}: Props): JSX.Element { + return isMultiColumnFooterLinks(links) ? ( + + ) : ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Logo/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Logo/index.tsx new file mode 100644 index 000000000000..f566555a1791 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Logo/index.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; + +import Link from '@docusaurus/Link'; +import {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; +import styles from './styles.module.css'; +import ThemedImage from '@theme/ThemedImage'; +import type {Props} from '@theme/Footer/Logo'; + +function LogoImage({logo}: Props) { + const {withBaseUrl} = useBaseUrlUtils(); + const sources = { + light: withBaseUrl(logo.src), + dark: withBaseUrl(logo.srcDark ?? logo.src), + }; + return ( + + ); +} + +export default function FooterLogo({logo}: Props): JSX.Element { + return logo.href ? ( + + + + ) : ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/styles.module.css b/packages/docusaurus-theme-classic/src/theme/Footer/Logo/styles.module.css similarity index 100% rename from packages/docusaurus-theme-classic/src/theme/Footer/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/Footer/Logo/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx index eaeb173a79d4..5106ca241c7f 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/index.tsx @@ -6,185 +6,27 @@ */ import React from 'react'; -import clsx from 'clsx'; -import Link from '@docusaurus/Link'; -import { - type FooterLinkItem, - useThemeConfig, - type MultiColumnFooter, - type SimpleFooter, -} from '@docusaurus/theme-common'; -import useBaseUrl, {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; -import isInternalUrl from '@docusaurus/isInternalUrl'; -import styles from './styles.module.css'; -import ThemedImage from '@theme/ThemedImage'; -import IconExternalLink from '@theme/IconExternalLink'; - -function FooterLink({ - to, - href, - label, - prependBaseUrlToHref, - ...props -}: FooterLinkItem) { - const toUrl = useBaseUrl(to); - const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); - - return ( - - - {label} - {href && !isInternalUrl(href) && } - - - ); -} - -function FooterLogo({logo}: {logo: SimpleFooter['logo']}) { - const {withBaseUrl} = useBaseUrlUtils(); - if (!logo?.src) { - return null; - } - const sources = { - light: withBaseUrl(logo.src), - dark: withBaseUrl(logo.srcDark ?? logo.src), - }; - const image = ( - - ); - return ( -
    - {logo.href ? ( - - {image} - - ) : ( - image - )} -
    - ); -} - -function MultiColumnLinks({links}: {links: MultiColumnFooter['links']}) { - return ( - <> - {links.map((linkItem, i) => ( -
    -
    {linkItem.title}
    -
      - {linkItem.items.map((item, key) => - item.html ? ( -
    • - ) : ( -
    • - -
    • - ), - )} -
    -
    - ))} - - ); -} - -function SimpleLinks({links}: {links: SimpleFooter['links']}) { - return ( -
    - {links.map((item, key) => ( - - {item.html ? ( - - ) : ( - - )} - {links.length !== key + 1 && ( - · - )} - - ))} -
    - ); -} - -function isMultiColumnFooterLinks( - links: MultiColumnFooter['links'] | SimpleFooter['links'], -): links is MultiColumnFooter['links'] { - return 'title' in links[0]!; -} +import {useThemeConfig} from '@docusaurus/theme-common'; +import FooterLinks from '@theme/Footer/Links'; +import FooterLogo from '@theme/Footer/Logo'; +import FooterCopyright from '@theme/Footer/Copyright'; +import FooterLayout from '@theme/Footer/Layout'; function Footer(): JSX.Element | null { const {footer} = useThemeConfig(); if (!footer) { return null; } - const {copyright, links, logo} = footer; + const {copyright, links, logo, style} = footer; return ( -
    -
    - {links && - links.length > 0 && - (isMultiColumnFooterLinks(links) ? ( -
    - -
    - ) : ( -
    - -
    - ))} - {(logo || copyright) && ( -
    - - {copyright && ( -
    - )} -
    - )} -
    -
    + 0 && } + logo={logo && } + copyright={copyright && } + /> ); } diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index c1138eec2514..50de4ea881f6 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -20,6 +20,7 @@ export type { MultiColumnFooter, SimpleFooter, Footer, + FooterLogo, FooterLinkItem, ColorModeConfig, } from './utils/useThemeConfig'; @@ -110,6 +111,8 @@ export { type TOCTreeNode, } from './utils/tocUtils'; +export {isMultiColumnFooterLinks} from './utils/footerUtils'; + export { ScrollControllerProvider, useScrollController, diff --git a/packages/docusaurus-theme-common/src/utils/footerUtils.ts b/packages/docusaurus-theme-common/src/utils/footerUtils.ts new file mode 100644 index 000000000000..2ced0cd6df17 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/footerUtils.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {MultiColumnFooter, SimpleFooter} from './useThemeConfig'; + +export function isMultiColumnFooterLinks( + links: MultiColumnFooter['links'] | SimpleFooter['links'], +): links is MultiColumnFooter['links'] { + return 'title' in links[0]!; +} diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index 3c64ef2380aa..a27451eacce7 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -65,18 +65,20 @@ export type FooterLinkItem = { href?: string; html?: string; prependBaseUrlToHref?: string; +} & Record; + +export type FooterLogo = { + alt?: string; + src: string; + srcDark?: string; + width?: string | number; + height?: string | number; + href?: string; }; export type FooterBase = { style: 'light' | 'dark'; - logo?: { - alt?: string; - src: string; - srcDark?: string; - width?: string | number; - height?: string | number; - href?: string; - }; + logo?: FooterLogo; copyright?: string; }; From aa5a2d4c041dc6fac5c352e53af322718f975dd1 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 12 Mar 2022 08:43:09 +0800 Subject: [PATCH 003/405] test: enable a few jest eslint rules (#6900) * test: enable a few jest eslint rules * more --- .eslintrc.js | 21 +- __tests__/validate-package-json.test.ts | 6 +- .../__tests__/index.test.js | 4 +- .../__snapshots__/index.test.ts.snap | 69 ++ .../src/__tests__/index.test.ts | 94 +-- .../remark/headings/__tests__/index.test.ts | 16 +- .../__snapshots__/index.test.ts.snap | 159 ++++- .../src/remark/toc/__tests__/index.test.ts | 219 ++----- .../transformImage/__tests__/index.test.ts | 14 +- .../transformLinks/__tests__/index.test.ts | 8 +- .../__snapshots__/index.test.ts.snap | 4 +- .../__tests__/index.test.ts | 6 +- .../src/__tests__/frontMatter.test.ts | 4 +- .../src/__tests__/migration.test.ts | 14 +- .../src/__tests__/migrationConfig.test.ts | 2 +- .../collectRedirects.test.ts.snap | 6 +- .../createRedirectPageContent.test.ts.snap | 4 +- .../normalizePluginOptions.test.ts.snap | 6 +- .../writeRedirectFiles.test.ts.snap | 10 +- .../src/__tests__/collectRedirects.test.ts | 26 +- .../createRedirectPageContent.test.ts | 4 +- .../src/__tests__/extensionRedirects.test.ts | 28 +- .../__tests__/normalizePluginOptions.test.ts | 16 +- .../src/__tests__/redirectValidation.test.ts | 4 +- .../src/__tests__/writeRedirectFiles.test.ts | 18 +- ...fy.test.ts.snap => blogUtils.test.ts.snap} | 4 +- .../__tests__/__snapshots__/feed.test.ts.snap | 6 +- .../__snapshots__/index.test.ts.snap | 50 +- .../pluginOptionSchema.test.ts.snap | 4 +- .../__snapshots__/translations.test.ts.snap | 6 +- .../src/__tests__/authors.test.ts | 52 +- .../src/__tests__/blogFrontMatter.test.ts | 14 +- .../src/__tests__/blogUtils.test.ts | 130 +++- .../src/__tests__/feed.test.ts | 144 ++--- .../src/__tests__/index.test.ts | 122 ++-- .../src/__tests__/linkify.test.ts | 101 --- .../src/__tests__/pluginOptionSchema.test.ts | 172 ++--- .../src/__tests__/translations.test.ts | 8 +- .../__snapshots__/index.test.ts.snap | 78 ++- .../__snapshots__/translations.test.ts.snap | 4 +- .../src/__tests__/cli.test.ts | 32 +- .../src/__tests__/docFrontMatter.test.ts | 15 +- .../src/__tests__/docs.test.ts | 46 +- .../src/__tests__/index.test.ts | 146 ++--- .../src/__tests__/lastUpdate.test.ts | 20 +- .../src/__tests__/numberPrefix.test.ts | 14 +- .../src/__tests__/options.test.ts | 34 +- .../src/__tests__/props.test.ts | 2 +- .../src/__tests__/slug.test.ts | 16 +- .../src/__tests__/translations.test.ts | 6 +- .../src/__tests__/versions.test.ts | 52 +- .../client/__tests__/docsClientUtils.test.ts | 10 +- .../__snapshots__/linkify.test.ts.snap | 74 +-- .../src/markdown/__tests__/linkify.test.ts | 168 ++--- .../__snapshots__/postProcessor.test.ts.snap | 78 +++ .../src/sidebars/__tests__/generator.test.ts | 14 +- .../src/sidebars/__tests__/index.test.ts | 25 +- .../sidebars/__tests__/normalization.test.ts | 4 +- .../sidebars/__tests__/postProcessor.test.ts | 81 +-- .../src/sidebars/__tests__/processor.test.ts | 6 +- .../src/sidebars/__tests__/utils.test.ts | 36 +- .../src/sidebars/__tests__/validation.test.ts | 56 +- .../__snapshots__/index.test.ts.snap | 105 +++ .../src/__tests__/index.test.ts | 131 +--- .../src/__tests__/pluginOptionSchema.test.ts | 8 +- .../src/__tests__/createSitemap.test.ts | 12 +- .../src/__tests__/pluginOptionSchema.test.ts | 12 +- .../__snapshots__/index.test.ts.snap | 38 +- .../src/__tests__/index.test.ts | 10 +- .../__snapshots__/translations.test.ts.snap | 6 +- .../src/__tests__/translations.test.ts | 12 +- .../src/__tests__/validateThemeConfig.test.ts | 264 ++++---- .../src/theme/Tabs/__tests__/index.test.tsx | 10 +- .../__snapshots__/codeBlockUtils.test.ts.snap | 123 ++++ .../utils/__tests__/codeBlockUtils.test.ts | 150 +---- .../src/utils/__tests__/docsUtils.test.tsx | 600 +++++++++--------- .../src/utils/__tests__/jsUtils.test.ts | 8 +- .../src/utils/__tests__/pathUtils.test.ts | 14 +- .../src/utils/__tests__/regexpUtils.test.ts | 2 +- .../src/utils/__tests__/routesUtils.test.ts | 12 +- .../src/utils/__tests__/searchUtils.test.ts | 2 +- .../src/utils/__tests__/tagUtils.test.ts | 2 +- .../src/utils/__tests__/tocUtils.test.ts | 4 +- .../src/__tests__/validateThemeConfig.test.ts | 14 +- .../src/__tests__/validateThemeConfig.test.ts | 20 +- .../__tests__/update.test.ts | 38 +- .../src/__tests__/index.test.ts | 20 +- .../src/__tests__/applyTrailingSlash.test.ts | 18 +- .../validationSchemas.test.ts.snap | 66 +- .../src/__tests__/validationSchemas.test.ts | 12 +- .../src/__tests__/validationUtils.test.ts | 10 +- .../__snapshots__/markdownLinks.test.ts.snap | 136 ++++ .../__snapshots__/markdownParser.test.ts.snap | 200 ++++++ .../src/__tests__/dataFileUtils.test.ts | 30 +- .../src/__tests__/emitUtils.test.ts | 138 ++-- .../src/__tests__/globUtils.test.ts | 10 +- .../src/__tests__/hashUtils.test.ts | 4 +- .../src/__tests__/i18nUtils.test.ts | 82 +-- .../src/__tests__/jsUtils.test.ts | 26 +- .../src/__tests__/markdownLinks.test.ts | 149 +---- .../src/__tests__/markdownParser.test.ts | 305 ++------- .../src/__tests__/pathUtils.test.ts | 116 ++-- .../src/__tests__/slugger.test.ts | 4 +- .../src/__tests__/tags.test.ts | 16 +- .../src/__tests__/urlUtils.test.ts | 112 ++-- .../src/__tests__/webpackUtils.test.ts | 2 +- .../src/client/__tests__/flat.test.ts | 10 +- .../__tests__/normalizeLocation.test.ts | 4 +- .../exports/__tests__/BrowserOnly.test.tsx | 6 +- .../exports/__tests__/Interpolate.test.tsx | 18 +- .../exports/__tests__/Translate.test.tsx | 8 +- .../exports/__tests__/isInternalUrl.test.ts | 18 +- .../exports/__tests__/useBaseUrl.test.ts | 8 +- .../src/commands/__tests__/deploy.test.ts | 16 +- .../__tests__/writeHeadingIds.test.ts | 20 +- .../__snapshots__/actions.test.ts.snap | 94 +++ .../__snapshots__/config.test.ts.snap | 21 + .../swizzle/__tests__/actions.test.ts | 111 +--- .../swizzle/__tests__/components.test.ts | 16 +- .../commands/swizzle/__tests__/config.test.ts | 32 +- .../commands/swizzle/__tests__/index.test.ts | 36 +- .../configValidation.test.ts.snap | 82 +-- .../duplicateRoutes.test.ts.snap | 2 +- .../__snapshots__/routes.test.ts.snap | 6 +- .../src/server/__tests__/brokenLinks.test.ts | 8 +- .../src/server/__tests__/config.test.ts | 14 +- .../server/__tests__/configValidation.test.ts | 32 +- .../server/__tests__/duplicateRoutes.test.ts | 16 +- .../src/server/__tests__/i18n.test.ts | 22 +- .../server/__tests__/moduleShorthand.test.ts | 16 +- .../src/server/__tests__/routes.test.ts | 35 +- .../src/server/__tests__/utils.test.ts | 2 +- .../client-modules/__tests__/index.test.ts | 12 +- .../html-tags/__tests__/htmlTags.test.ts | 10 +- .../server/html-tags/__tests__/index.test.ts | 12 +- .../__tests__/__snapshots__/init.test.ts.snap | 4 +- .../__tests__/applyRouteTrailingSlash.test.ts | 20 +- .../src/server/plugins/__tests__/init.test.ts | 8 +- .../plugins/__tests__/pluginIds.test.ts | 12 +- .../__snapshots__/index.test.ts.snap | 164 +++++ .../server/presets/__tests__/index.test.ts | 179 +----- .../src/server/themes/__tests__/alias.test.ts | 14 +- .../src/server/themes/__tests__/index.test.ts | 2 +- .../__tests__/translations.test.ts | 46 +- .../__tests__/translationsExtractor.test.ts | 36 +- .../server/versions/__tests__/index.test.ts | 6 +- .../__tests__/__snapshots__/base.test.ts.snap | 4 +- .../src/webpack/__tests__/base.test.ts | 14 +- .../src/webpack/__tests__/client.test.ts | 7 +- .../src/webpack/__tests__/server.test.ts | 4 +- .../src/webpack/__tests__/utils.test.ts | 14 +- .../lqip-loader/src/__tests__/lqip.test.ts | 22 +- .../lqip-loader/src/__tests__/utils.test.ts | 6 +- .../__tests__/index.test.js | 6 +- website/src/data/__tests__/user.test.ts | 78 ++- 155 files changed, 3572 insertions(+), 3406 deletions(-) create mode 100644 packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap rename packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/{linkify.test.ts.snap => blogUtils.test.ts.snap} (78%) delete mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts create mode 100644 packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap create mode 100644 packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap create mode 100644 packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap create mode 100644 packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap create mode 100644 packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap create mode 100644 packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap create mode 100644 packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap diff --git a/.eslintrc.js b/.eslintrc.js index 0b18a8ab9c8f..236f14d62359 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -205,9 +205,26 @@ module.exports = { 'import/order': OFF, 'import/prefer-default-export': OFF, - 'jest/prefer-expect-resolves': WARNING, + 'jest/consistent-test-it': WARNING, 'jest/expect-expect': OFF, - 'jest/valid-title': OFF, + 'jest/no-large-snapshots': [ + WARNING, + {maxSize: Infinity, inlineMaxSize: 10}, + ], + 'jest/prefer-expect-resolves': WARNING, + 'jest/prefer-lowercase-title': [WARNING, {ignore: ['describe']}], + 'jest/require-top-level-describe': ERROR, + 'jest/valid-title': [ + ERROR, + { + mustNotMatch: { + it: [ + '^should|\\.$', + 'Titles should not begin with "should" or end with a full-stop', + ], + }, + }, + ], 'jsx-a11y/click-events-have-key-events': WARNING, 'jsx-a11y/no-noninteractive-element-interactions': WARNING, diff --git a/__tests__/validate-package-json.test.ts b/__tests__/validate-package-json.test.ts index 9eab91288f5b..23b81e4f2786 100644 --- a/__tests__/validate-package-json.test.ts +++ b/__tests__/validate-package-json.test.ts @@ -26,12 +26,12 @@ async function getPackagesJsonFiles(): Promise { } describe('packages', () => { - test('should be found', async () => { + it('are found', async () => { const packageJsonFiles = await getPackagesJsonFiles(); expect(packageJsonFiles.length).toBeGreaterThan(0); }); - test('should contain repository and directory for every package', async () => { + it('contain repository and directory', async () => { const packageJsonFiles = await getPackagesJsonFiles(); packageJsonFiles @@ -51,7 +51,7 @@ describe('packages', () => { This will make you publish an incomplete list of Docusaurus packages when trying to release with lerna-publish */ - test('should have publishConfig.access: "public" when name starts with @', async () => { + it('have publishConfig.access: "public" when name starts with @', async () => { const packageJsonFiles = await getPackagesJsonFiles(); packageJsonFiles diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js index e847faca8a3a..b54446179796 100644 --- a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js @@ -23,11 +23,11 @@ const processFixture = (name) => { }; describe('remove-overridden-custom-properties', () => { - test('overridden custom properties should be removed', () => { + it('overridden custom properties should be removed', () => { expect(processFixture('normal')).toMatchSnapshot(); }); - test('overridden custom properties with `!important` rule should not be removed', () => { + it('overridden custom properties with `!important` rule should not be removed', () => { expect(processFixture('important_rule')).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..27685bfd371a --- /dev/null +++ b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`error prints objects 1`] = ` +Array [ + Array [ + "[ERROR] {\\"a\\":1}", + ], + Array [ + "[ERROR] undefined", + ], + Array [ + "[ERROR] 1,2,3", + ], + Array [ + "[ERROR] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + ], +] +`; + +exports[`info prints objects 1`] = ` +Array [ + Array [ + "[INFO] {\\"a\\":1}", + ], + Array [ + "[INFO] undefined", + ], + Array [ + "[INFO] 1,2,3", + ], + Array [ + "[INFO] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + ], +] +`; + +exports[`success prints objects 1`] = ` +Array [ + Array [ + "[SUCCESS] {\\"a\\":1}", + ], + Array [ + "[SUCCESS] undefined", + ], + Array [ + "[SUCCESS] 1,2,3", + ], + Array [ + "[SUCCESS] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + ], +] +`; + +exports[`warn prints objects 1`] = ` +Array [ + Array [ + "[WARNING] {\\"a\\":1}", + ], + Array [ + "[WARNING] undefined", + ], + Array [ + "[WARNING] 1,2,3", + ], + Array [ + "[WARNING] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + ], +] +`; diff --git a/packages/docusaurus-logger/src/__tests__/index.test.ts b/packages/docusaurus-logger/src/__tests__/index.test.ts index e78571a0f210..e564fc2bb11b 100644 --- a/packages/docusaurus-logger/src/__tests__/index.test.ts +++ b/packages/docusaurus-logger/src/__tests__/index.test.ts @@ -9,22 +9,22 @@ import {jest} from '@jest/globals'; import logger from '../index'; describe('formatters', () => { - test('path', () => { + it('path', () => { expect(logger.path('hey')).toMatchInlineSnapshot(`"hey"`); }); - test('id', () => { + it('id', () => { expect(logger.name('hey')).toMatchInlineSnapshot(`"hey"`); }); - test('code', () => { + it('code', () => { expect(logger.code('hey')).toMatchInlineSnapshot(`"\`hey\`"`); }); - test('subdue', () => { + it('subdue', () => { expect(logger.subdue('hey')).toMatchInlineSnapshot(`"hey"`); }); }); describe('interpolate', () => { - test('should format text with variables & arrays', () => { + it('formats text with variables & arrays', () => { const name = 'Josh'; const items = [1, 'hi', 'Hmmm']; expect(logger.interpolate`Hello ${name}! Here are your goodies:${items}`) @@ -35,14 +35,14 @@ describe('interpolate', () => { - Hmmm" `); }); - test('should recognize valid flags', () => { + it('recognizes valid flags', () => { expect( logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, ).toMatchInlineSnapshot( `"The package at packages/docusaurus has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, ); }); - test('should interpolate arrays with flags', () => { + it('interpolates arrays with flags', () => { expect( logger.interpolate`The following commands are available:code=${[ 'docusaurus start', @@ -56,14 +56,14 @@ describe('interpolate', () => { - \`docusaurus deploy\`" `); }); - test('should print detached flags as-is', () => { + it('prints detached flags as-is', () => { expect( logger.interpolate`You can use placeholders like code= ${'and it will'} be replaced with the succeeding arguments`, ).toMatchInlineSnapshot( `"You can use placeholders like code= and it will be replaced with the succeeding arguments"`, ); }); - test('should throw with bad flags', () => { + it('throws with bad flags', () => { expect( () => logger.interpolate`I mistyped this: cde=${'this code'} and I will be damned`, @@ -75,104 +75,44 @@ describe('interpolate', () => { describe('info', () => { const consoleMock = jest.spyOn(console, 'info').mockImplementation(() => {}); - test('should print objects', () => { + it('prints objects', () => { logger.info({a: 1}); logger.info(undefined); logger.info([1, 2, 3]); logger.info(new Date(2021, 10, 13)); - expect(consoleMock.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "[INFO] {\\"a\\":1}", - ], - Array [ - "[INFO] undefined", - ], - Array [ - "[INFO] 1,2,3", - ], - Array [ - "[INFO] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", - ], - ] - `); + expect(consoleMock.mock.calls).toMatchSnapshot(); }); }); describe('warn', () => { const consoleMock = jest.spyOn(console, 'warn').mockImplementation(() => {}); - test('should print objects', () => { + it('prints objects', () => { logger.warn({a: 1}); logger.warn(undefined); logger.warn([1, 2, 3]); logger.warn(new Date(2021, 10, 13)); - expect(consoleMock.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "[WARNING] {\\"a\\":1}", - ], - Array [ - "[WARNING] undefined", - ], - Array [ - "[WARNING] 1,2,3", - ], - Array [ - "[WARNING] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", - ], - ] - `); + expect(consoleMock.mock.calls).toMatchSnapshot(); }); }); describe('error', () => { const consoleMock = jest.spyOn(console, 'error').mockImplementation(() => {}); - test('should print objects', () => { + it('prints objects', () => { logger.error({a: 1}); logger.error(undefined); logger.error([1, 2, 3]); logger.error(new Date(2021, 10, 13)); - expect(consoleMock.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "[ERROR] {\\"a\\":1}", - ], - Array [ - "[ERROR] undefined", - ], - Array [ - "[ERROR] 1,2,3", - ], - Array [ - "[ERROR] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", - ], - ] - `); + expect(consoleMock.mock.calls).toMatchSnapshot(); }); }); describe('success', () => { const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); - test('should print objects', () => { + it('prints objects', () => { logger.success({a: 1}); logger.success(undefined); logger.success([1, 2, 3]); logger.success(new Date(2021, 10, 13)); - expect(consoleMock.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "[SUCCESS] {\\"a\\":1}", - ], - Array [ - "[SUCCESS] undefined", - ], - Array [ - "[SUCCESS] 1,2,3", - ], - Array [ - "[SUCCESS] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", - ], - ] - `); + expect(consoleMock.mock.calls).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts index ee10568ba883..371080d2737e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts @@ -27,8 +27,8 @@ function heading(label, id) { ); } -describe('headings plugin', () => { - test('should patch `id`s and `data.hProperties.id', () => { +describe('headings remark plugin', () => { + it('patches `id`s and `data.hProperties.id', () => { const result = process('# Normal\n\n## Table of Contents\n\n# Baz\n'); const expected = u('root', [ u( @@ -55,7 +55,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should not overwrite `data` on headings', () => { + it('does not overwrite `data` on headings', () => { const result = process('# Normal\n', [ () => { function transform(tree) { @@ -78,7 +78,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should not overwrite `data.hProperties` on headings', () => { + it('does not overwrite `data.hProperties` on headings', () => { const result = process('# Normal\n', [ () => { function transform(tree) { @@ -101,7 +101,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should generate `id`s and `hProperties.id`s, based on `hProperties.id` if they exist', () => { + it('generates `id`s and `hProperties.id`s, based on `hProperties.id` if they exist', () => { const result = process( [ '## Something', @@ -157,7 +157,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should create GitHub-style headings ids', () => { + it('creates GitHub-style headings ids', () => { const result = process( [ '## I ♥ unicode', @@ -225,7 +225,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should generate id from only text contents of headings if they contains HTML tags', () => { + it('generates id from only text contents of headings if they contains HTML tags', () => { const result = process('# Normal\n'); const expected = u('root', [ u( @@ -245,7 +245,7 @@ describe('headings plugin', () => { expect(result).toEqual(expected); }); - test('should create custom headings ids', () => { + it('creates custom headings ids', () => { const result = process(` # Heading One {#custom_h1} diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap index f82cda96d317..bb2f9b07233a 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`inline code should be escaped 1`] = ` +exports[`toc remark plugin escapes inline code 1`] = ` "export const toc = [ { value: '<Head />', @@ -48,7 +48,120 @@ exports[`inline code should be escaped 1`] = ` " `; -exports[`non text phrasing content 1`] = ` +exports[`toc remark plugin exports even with existing name 1`] = ` +"export const toc = [ + { + value: 'Thanos', + id: 'thanos', + level: 2 + }, + { + value: 'Tony Stark', + id: 'tony-stark', + level: 2 + }, + { + value: 'Avengers', + id: 'avengers', + level: 3 + } +]; + +## Thanos + +## Tony Stark + +### Avengers +" +`; + +exports[`toc remark plugin exports with custom name 1`] = ` +"export const customName = [ + { + value: 'Endi', + id: 'endi', + level: 3 + }, + { + value: 'Endi', + id: 'endi-1', + level: 2 + }, + { + value: 'Yangshun', + id: 'yangshun', + level: 3 + }, + { + value: 'I ♥ unicode.', + id: 'i--unicode', + level: 2 + } +]; + +### Endi + +\`\`\`md +## This is ignored +\`\`\` + +## Endi + +Lorem ipsum + +### Yangshun + +Some content here + +## I ♥ unicode. +" +`; + +exports[`toc remark plugin handles empty headings 1`] = ` +"export const toc = []; + +# Ignore this + +## + +## ![](an-image.svg) +" +`; + +exports[`toc remark plugin inserts below imports 1`] = ` +"import something from 'something'; + +import somethingElse from 'something-else'; + +export const toc = [ + { + value: 'Title', + id: 'title', + level: 2 + }, + { + value: 'Test', + id: 'test', + level: 2 + }, + { + value: 'Again', + id: 'again', + level: 3 + } +]; + +## Title + +## Test + +### Again + +Content. +" +`; + +exports[`toc remark plugin works on non text phrasing content 1`] = ` "export const toc = [ { value: 'Emphasis', @@ -88,3 +201,45 @@ exports[`non text phrasing content 1`] = ` ## \`inline.code()\` " `; + +exports[`toc remark plugin works on text content 1`] = ` +"export const toc = [ + { + value: 'Endi', + id: 'endi', + level: 3 + }, + { + value: 'Endi', + id: 'endi-1', + level: 2 + }, + { + value: 'Yangshun', + id: 'yangshun', + level: 3 + }, + { + value: 'I ♥ unicode.', + id: 'i--unicode', + level: 2 + } +]; + +### Endi + +\`\`\`md +## This is ignored +\`\`\` + +## Endi + +Lorem ipsum + +### Yangshun + +Some content here + +## I ♥ unicode. +" +`; diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts index daf2488705a6..b3fd7babac76 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.ts @@ -24,185 +24,42 @@ const processFixture = async (name, options?) => { return result.toString(); }; -test('non text phrasing content', async () => { - const result = await processFixture('non-text-content'); - expect(result).toMatchSnapshot(); -}); - -test('inline code should be escaped', async () => { - const result = await processFixture('inline-code'); - expect(result).toMatchSnapshot(); -}); - -test('text content', async () => { - const result = await processFixture('just-content'); - expect(result).toMatchInlineSnapshot(` - "export const toc = [ - { - value: 'Endi', - id: 'endi', - level: 3 - }, - { - value: 'Endi', - id: 'endi-1', - level: 2 - }, - { - value: 'Yangshun', - id: 'yangshun', - level: 3 - }, - { - value: 'I ♥ unicode.', - id: 'i--unicode', - level: 2 - } - ]; - - ### Endi - - \`\`\`md - ## This is ignored - \`\`\` - - ## Endi - - Lorem ipsum - - ### Yangshun - - Some content here - - ## I ♥ unicode. - " - `); -}); - -test('should export even with existing name', async () => { - const result = await processFixture('name-exist'); - expect(result).toMatchInlineSnapshot(` - "export const toc = [ - { - value: 'Thanos', - id: 'thanos', - level: 2 - }, - { - value: 'Tony Stark', - id: 'tony-stark', - level: 2 - }, - { - value: 'Avengers', - id: 'avengers', - level: 3 - } - ]; - - ## Thanos - - ## Tony Stark - - ### Avengers - " - `); -}); - -test('should export with custom name', async () => { - const options = { - name: 'customName', - }; - const result = await processFixture('just-content', options); - expect(result).toMatchInlineSnapshot(` - "export const customName = [ - { - value: 'Endi', - id: 'endi', - level: 3 - }, - { - value: 'Endi', - id: 'endi-1', - level: 2 - }, - { - value: 'Yangshun', - id: 'yangshun', - level: 3 - }, - { - value: 'I ♥ unicode.', - id: 'i--unicode', - level: 2 - } - ]; - - ### Endi - - \`\`\`md - ## This is ignored - \`\`\` - - ## Endi - - Lorem ipsum - - ### Yangshun - - Some content here - - ## I ♥ unicode. - " - `); -}); - -test('should insert below imports', async () => { - const result = await processFixture('insert-below-imports'); - expect(result).toMatchInlineSnapshot(` - "import something from 'something'; - - import somethingElse from 'something-else'; - - export const toc = [ - { - value: 'Title', - id: 'title', - level: 2 - }, - { - value: 'Test', - id: 'test', - level: 2 - }, - { - value: 'Again', - id: 'again', - level: 3 - } - ]; - - ## Title - - ## Test - - ### Again - - Content. - " - `); -}); - -test('empty headings', async () => { - const result = await processFixture('empty-headings'); - expect(result).toMatchInlineSnapshot(` - "export const toc = []; - - # Ignore this - - ## - - ## ![](an-image.svg) - " - `); +describe('toc remark plugin', () => { + it('works on non text phrasing content', async () => { + const result = await processFixture('non-text-content'); + expect(result).toMatchSnapshot(); + }); + + it('escapes inline code', async () => { + const result = await processFixture('inline-code'); + expect(result).toMatchSnapshot(); + }); + + it('works on text content', async () => { + const result = await processFixture('just-content'); + expect(result).toMatchSnapshot(); + }); + + it('exports even with existing name', async () => { + const result = await processFixture('name-exist'); + expect(result).toMatchSnapshot(); + }); + + it('exports with custom name', async () => { + const options = { + name: 'customName', + }; + const result = await processFixture('just-content', options); + expect(result).toMatchSnapshot(); + }); + + it('inserts below imports', async () => { + const result = await processFixture('insert-below-imports'); + expect(result).toMatchSnapshot(); + }); + + it('handles empty headings', async () => { + const result = await processFixture('empty-headings'); + expect(result).toMatchSnapshot(); + }); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts index 9ab5161441ec..15fac36b29cb 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/index.test.ts @@ -33,34 +33,34 @@ const staticDirs = [ const siteDir = path.join(__dirname, '__fixtures__'); describe('transformImage plugin', () => { - test('fail if image does not exist', async () => { + it('fail if image does not exist', async () => { await expect( processFixture('fail', {staticDirs}), ).rejects.toThrowErrorMatchingSnapshot(); }); - test('fail if image relative path does not exist', async () => { + it('fail if image relative path does not exist', async () => { await expect( processFixture('fail2', {staticDirs}), ).rejects.toThrowErrorMatchingSnapshot(); }); - test('fail if image url is absent', async () => { + it('fail if image url is absent', async () => { await expect( processFixture('noUrl', {staticDirs}), ).rejects.toThrowErrorMatchingSnapshot(); }); - test('transform md images to ', async () => { + it('transform md images to ', async () => { const result = await processFixture('img', {staticDirs, siteDir}); expect(result).toMatchSnapshot(); }); - test('pathname protocol', async () => { + it('pathname protocol', async () => { const result = await processFixture('pathname', {staticDirs}); expect(result).toMatchSnapshot(); }); - test('does not choke on invalid image', async () => { - const errorMock = jest.spyOn(console, 'warn').mockImplementation(); + it('does not choke on invalid image', async () => { + const errorMock = jest.spyOn(console, 'warn').mockImplementation(() => {}); const result = await processFixture('invalid-img', {staticDirs}); expect(result).toMatchSnapshot(); expect(errorMock).toBeCalledTimes(1); diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts index 2b2ac7979dc3..65aac94fb322 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/index.test.ts @@ -34,24 +34,24 @@ const processFixture = async (name: string, options?) => { }; describe('transformAsset plugin', () => { - test('fail if asset url is absent', async () => { + it('fail if asset url is absent', async () => { await expect( processFixture('noUrl'), ).rejects.toThrowErrorMatchingSnapshot(); }); - test('fail if asset with site alias does not exist', async () => { + it('fail if asset with site alias does not exist', async () => { await expect( processFixture('nonexistentSiteAlias'), ).rejects.toThrowErrorMatchingSnapshot(); }); - test('transform md links to ', async () => { + it('transform md links to ', async () => { const result = await processFixture('asset'); expect(result).toMatchSnapshot(); }); - test('pathname protocol', async () => { + it('pathname protocol', async () => { const result = await processFixture('pathname'); expect(result).toMatchSnapshot(); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap index c234d26fe0d1..d7b84a935097 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`unwrapMdxCodeBlocks should unwrap the mdx code blocks 1`] = ` +exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks 1`] = ` "# MDX code blocks test document ## Some basic markdown @@ -95,7 +95,7 @@ cmd /C 'set \\"GIT_USER=\\" && yarn deploy' " `; -exports[`unwrapMdxCodeBlocks should unwrap the mdx code blocks AST 1`] = ` +exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = ` Object { "children": Array [ Object { diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts index d18b4634e0f8..13fe031f5b84 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/index.test.ts @@ -22,14 +22,14 @@ const processFixtureAST = async (name: string) => { return remark().use(mdx).use(plugin).parse(file); }; -describe('unwrapMdxCodeBlocks', () => { - test('should unwrap the mdx code blocks', async () => { +describe('unwrapMdxCodeBlocks remark plugin', () => { + it('unwraps the mdx code blocks', async () => { const result = await processFixture('has-mdx-code-blocks.mdx'); expect(result).toMatchSnapshot(); }); // The AST output should be parsed correctly or the MDX loader won't work! - test('should unwrap the mdx code blocks AST', async () => { + it('unwraps the mdx code blocks AST', async () => { const result = await processFixtureAST('has-mdx-code-blocks.mdx'); expect(result).toMatchSnapshot(); }); diff --git a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts index 1359b2b574ab..3f480415b43e 100644 --- a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts @@ -7,8 +7,8 @@ import {shouldQuotifyFrontMatter} from '../frontMatter'; -describe('frontMatter', () => { - test('shouldQuotifyFrontMatter', () => { +describe('shouldQuotifyFrontMatter', () => { + it('works', () => { expect(shouldQuotifyFrontMatter(['id', 'value'])).toEqual(false); expect( shouldQuotifyFrontMatter([ diff --git a/packages/docusaurus-migrate/src/__tests__/migration.test.ts b/packages/docusaurus-migrate/src/__tests__/migration.test.ts index 8129bab62030..be9c4ae9ae31 100644 --- a/packages/docusaurus-migrate/src/__tests__/migration.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migration.test.ts @@ -12,10 +12,10 @@ import fs from 'fs-extra'; import {posixPath} from '@docusaurus/utils'; async function testMigration(siteDir: string, newDir: string) { - const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(); - const mkdirpMock = jest.spyOn(fs, 'mkdirp').mockImplementation(); - const mkdirsMock = jest.spyOn(fs, 'mkdirs').mockImplementation(); - const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); + const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {}); + const mkdirpMock = jest.spyOn(fs, 'mkdirp').mockImplementation(() => {}); + const mkdirsMock = jest.spyOn(fs, 'mkdirs').mockImplementation(() => {}); + const copyMock = jest.spyOn(fs, 'copy').mockImplementation(() => {}); await migrateDocusaurusProject(siteDir, newDir, true, true); expect( writeMock.mock.calls.sort((a, b) => @@ -45,18 +45,18 @@ async function testMigration(siteDir: string, newDir: string) { describe('migration test', () => { const fixtureDir = path.join(__dirname, '__fixtures__'); - test('simple website', async () => { + it('simple website', async () => { const siteDir = path.join(fixtureDir, 'simple_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_simple_site'); await testMigration(siteDir, newDir); }); - test('complex website', async () => { + it('complex website', async () => { const siteDir = path.join(fixtureDir, 'complex_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_complex_site'); await testMigration(siteDir, newDir); }); - test('missing versions', async () => { + it('missing versions', async () => { const siteDir = path.join(fixtureDir, 'missing_version_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_missing_version_site'); await testMigration(siteDir, newDir); diff --git a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts index 2f57bb7cb207..6e77e277e042 100644 --- a/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migrationConfig.test.ts @@ -10,7 +10,7 @@ import {createConfigFile} from '../index'; import type {VersionOneConfig} from '../types'; describe('create config', () => { - test('simple test', () => { + it('simple test', () => { const v1Config: VersionOneConfig = importFresh( `${__dirname}/__fixtures__/sourceSiteConfig.js`, ); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap index 785f7e3478dc..7c9cd4ee9de9 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`collectRedirects should throw if plugin option redirects contain invalid to paths 1`] = ` +exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = ` "You are trying to create client-side redirections to paths that do not exist: - /this/path/does/not/exist2 - /this/path/does/not/exist2 @@ -12,13 +12,13 @@ Valid paths you can redirect to: " `; -exports[`collectRedirects should throw if redirect creator creates array of array redirect 1`] = ` +exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = ` "Some created redirects are invalid: - {\\"from\\":[\\"/fromPath\\"],\\"to\\":\\"/\\"} => Validation error: \\"from\\" must be a string " `; -exports[`collectRedirects should throw if redirect creator creates invalid redirects 1`] = ` +exports[`collectRedirects throws if redirect creator creates invalid redirects 1`] = ` "Some created redirects are invalid: - {\\"from\\":\\"https://google.com/\\",\\"to\\":\\"/\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. - {\\"from\\":\\"//abc\\",\\"to\\":\\"/\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap index 7fa3afa57de0..7882ae877ad0 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`createRedirectPageContent should encode uri special chars 1`] = ` +exports[`createRedirectPageContent encodes uri special chars 1`] = ` " @@ -14,7 +14,7 @@ exports[`createRedirectPageContent should encode uri special chars 1`] = ` " `; -exports[`createRedirectPageContent should match snapshot 1`] = ` +exports[`createRedirectPageContent works 1`] = ` " diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap index 0bfd440bfedc..e16490337bb1 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`normalizePluginOptions should reject bad createRedirects user inputs 1`] = ` +exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = ` "Invalid @docusaurus/plugin-client-redirects options: \\"createRedirects\\" must be of type function { \\"createRedirects\\": [ @@ -10,7 +10,7 @@ exports[`normalizePluginOptions should reject bad createRedirects user inputs 1` }" `; -exports[`normalizePluginOptions should reject bad fromExtensions user inputs 1`] = ` +exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = ` "Invalid @docusaurus/plugin-client-redirects options: \\"fromExtensions[0]\\" contains an invalid value { \\"fromExtensions\\": [ @@ -22,7 +22,7 @@ exports[`normalizePluginOptions should reject bad fromExtensions user inputs 1`] }" `; -exports[`normalizePluginOptions should reject bad toExtensions user inputs 1`] = ` +exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = ` "Invalid @docusaurus/plugin-client-redirects options: \\"toExtensions[0]\\" contains an invalid value { \\"toExtensions\\": [ diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap index a57e33c0c21f..acdc68104ebd 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`toRedirectFilesMetadata should create appropriate metadata for empty baseUrl: fileContent baseUrl=empty 1`] = ` +exports[`toRedirectFilesMetadata creates appropriate metadata for empty baseUrl: fileContent baseUrl=empty 1`] = ` Array [ " @@ -16,7 +16,7 @@ Array [ ] `; -exports[`toRedirectFilesMetadata should create appropriate metadata for root baseUrl: fileContent baseUrl=/ 1`] = ` +exports[`toRedirectFilesMetadata creates appropriate metadata for root baseUrl: fileContent baseUrl=/ 1`] = ` Array [ " @@ -32,7 +32,7 @@ Array [ ] `; -exports[`toRedirectFilesMetadata should create appropriate metadata trailingSlash=false: fileContent 1`] = ` +exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=false: fileContent 1`] = ` Array [ " @@ -70,7 +70,7 @@ Array [ ] `; -exports[`toRedirectFilesMetadata should create appropriate metadata trailingSlash=true: fileContent 1`] = ` +exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=true: fileContent 1`] = ` Array [ " @@ -108,7 +108,7 @@ Array [ ] `; -exports[`toRedirectFilesMetadata should create appropriate metadata trailingSlash=undefined: fileContent 1`] = ` +exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=undefined: fileContent 1`] = ` Array [ " diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts index 5219bc25bd32..e1f24e5949bc 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts @@ -24,7 +24,7 @@ function createTestPluginContext( } describe('collectRedirects', () => { - test('should collect no redirect for undefined config', () => { + it('collects no redirect for undefined config', () => { expect( collectRedirects( createTestPluginContext(undefined, ['/', '/path']), @@ -33,13 +33,13 @@ describe('collectRedirects', () => { ).toEqual([]); }); - test('should collect no redirect for empty config', () => { + it('collects no redirect for empty config', () => { expect(collectRedirects(createTestPluginContext({}), undefined)).toEqual( [], ); }); - test('should collect redirects from html/exe extension', () => { + it('collects redirects from html/exe extension', () => { expect( collectRedirects( createTestPluginContext( @@ -62,7 +62,7 @@ describe('collectRedirects', () => { ]); }); - test('should collect redirects to html/exe extension', () => { + it('collects redirects to html/exe extension', () => { expect( collectRedirects( createTestPluginContext( @@ -81,7 +81,7 @@ describe('collectRedirects', () => { ]); }); - test('should collect redirects from plugin option redirects', () => { + it('collects redirects from plugin option redirects', () => { expect( collectRedirects( createTestPluginContext( @@ -117,7 +117,7 @@ describe('collectRedirects', () => { ]); }); - test('should collect redirects from plugin option redirects with trailingSlash=true', () => { + it('collects redirects from plugin option redirects with trailingSlash=true', () => { expect( collectRedirects( createTestPluginContext( @@ -153,7 +153,7 @@ describe('collectRedirects', () => { ]); }); - test('should collect redirects from plugin option redirects with trailingSlash=false', () => { + it('collects redirects from plugin option redirects with trailingSlash=false', () => { expect( collectRedirects( createTestPluginContext( @@ -189,7 +189,7 @@ describe('collectRedirects', () => { ]); }); - test('should throw if plugin option redirects contain invalid to paths', () => { + it('throw if plugin option redirects contain invalid to paths', () => { expect(() => collectRedirects( createTestPluginContext( @@ -216,7 +216,7 @@ describe('collectRedirects', () => { ).toThrowErrorMatchingSnapshot(); }); - test('should collect redirects with custom redirect creator', () => { + it('collects redirects with custom redirect creator', () => { expect( collectRedirects( createTestPluginContext( @@ -260,7 +260,7 @@ describe('collectRedirects', () => { ]); }); - test('should allow returning string / undefined', () => { + it('allows returning string / undefined', () => { expect( collectRedirects( createTestPluginContext( @@ -279,7 +279,7 @@ describe('collectRedirects', () => { ).toEqual([{from: '/foo', to: '/'}]); }); - test('should throw if redirect creator creates invalid redirects', () => { + it('throws if redirect creator creates invalid redirects', () => { expect(() => collectRedirects( createTestPluginContext( @@ -302,7 +302,7 @@ describe('collectRedirects', () => { ).toThrowErrorMatchingSnapshot(); }); - test('should throw if redirect creator creates array of array redirect', () => { + it('throws if redirect creator creates array of array redirect', () => { expect(() => collectRedirects( createTestPluginContext( @@ -321,7 +321,7 @@ describe('collectRedirects', () => { ).toThrowErrorMatchingSnapshot(); }); - test('should filter unwanted redirects', () => { + it('filters unwanted redirects', () => { expect( collectRedirects( createTestPluginContext( diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/createRedirectPageContent.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/createRedirectPageContent.test.ts index e30bd762d441..a65449b0c5de 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/createRedirectPageContent.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/createRedirectPageContent.test.ts @@ -8,13 +8,13 @@ import createRedirectPageContent from '../createRedirectPageContent'; describe('createRedirectPageContent', () => { - test('should match snapshot', () => { + it('works', () => { expect( createRedirectPageContent({toUrl: 'https://docusaurus.io/'}), ).toMatchSnapshot(); }); - test('should encode uri special chars', () => { + it('encodes uri special chars', () => { const result = createRedirectPageContent({ toUrl: 'https://docusaurus.io/gr/σελιδας/', }); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts index dcaa6bca3442..59f60c679e89 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts @@ -11,7 +11,7 @@ import { } from '../extensionRedirects'; describe('createToExtensionsRedirects', () => { - test('should reject empty extensions', () => { + it('rejects empty extensions', () => { expect(() => { createToExtensionsRedirects(['/'], ['']); }).toThrowErrorMatchingInlineSnapshot(` @@ -20,7 +20,7 @@ describe('createToExtensionsRedirects', () => { `); }); - test('should reject extensions with .', () => { + it('rejects extensions with "."', () => { expect(() => { createToExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` @@ -29,7 +29,7 @@ describe('createToExtensionsRedirects', () => { `); }); - test('should reject extensions with /', () => { + it('rejects extensions with /', () => { expect(() => { createToExtensionsRedirects(['/'], ['ht/ml']); }).toThrowErrorMatchingInlineSnapshot(` @@ -38,7 +38,7 @@ describe('createToExtensionsRedirects', () => { `); }); - test('should reject extensions with illegal url char', () => { + it('rejects extensions with illegal url char', () => { expect(() => { createToExtensionsRedirects(['/'], [',']); }).toThrowErrorMatchingInlineSnapshot(` @@ -47,7 +47,7 @@ describe('createToExtensionsRedirects', () => { `); }); - test('should create redirects from html/htm extensions', () => { + it('creates redirects from html/htm extensions', () => { const ext = ['html', 'htm']; expect(createToExtensionsRedirects([''], ext)).toEqual([]); expect(createToExtensionsRedirects(['/'], ext)).toEqual([]); @@ -60,13 +60,13 @@ describe('createToExtensionsRedirects', () => { expect(createToExtensionsRedirects(['/abc.xyz'], ext)).toEqual([]); }); - test('should create "to" redirects when relativeRoutesPath contains a prefix', () => { + it('creates "to" redirects when relativeRoutesPath contains a prefix', () => { expect( createToExtensionsRedirects(['/prefix/file.html'], ['html']), ).toEqual([{from: '/prefix/file', to: '/prefix/file.html'}]); }); - test('should not create redirection for an empty extension array', () => { + it('does not create redirection for an empty extension array', () => { const ext: string[] = []; expect(createToExtensionsRedirects([''], ext)).toEqual([]); expect(createToExtensionsRedirects(['/'], ext)).toEqual([]); @@ -75,7 +75,7 @@ describe('createToExtensionsRedirects', () => { }); describe('createFromExtensionsRedirects', () => { - test('should reject empty extensions', () => { + it('rejects empty extensions', () => { expect(() => { createFromExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` @@ -84,7 +84,7 @@ describe('createFromExtensionsRedirects', () => { `); }); - test('should reject extensions with .', () => { + it('rejects extensions with "."', () => { expect(() => { createFromExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` @@ -93,7 +93,7 @@ describe('createFromExtensionsRedirects', () => { `); }); - test('should reject extensions with /', () => { + it('rejects extensions with /', () => { expect(() => { createFromExtensionsRedirects(['/'], ['ht/ml']); }).toThrowErrorMatchingInlineSnapshot(` @@ -102,7 +102,7 @@ describe('createFromExtensionsRedirects', () => { `); }); - test('should reject extensions with illegal url char', () => { + it('rejects extensions with illegal url char', () => { expect(() => { createFromExtensionsRedirects(['/'], [',']); }).toThrowErrorMatchingInlineSnapshot(` @@ -111,7 +111,7 @@ describe('createFromExtensionsRedirects', () => { `); }); - test('should create redirects from html/htm extensions', () => { + it('creates redirects from html/htm extensions', () => { const ext = ['html', 'htm']; expect(createFromExtensionsRedirects([''], ext)).toEqual([]); expect(createFromExtensionsRedirects(['/'], ext)).toEqual([]); @@ -126,13 +126,13 @@ describe('createFromExtensionsRedirects', () => { ]); }); - test('should create "from" redirects when relativeRoutesPath contains a prefix', () => { + it('creates "from" redirects when relativeRoutesPath contains a prefix', () => { expect(createFromExtensionsRedirects(['/prefix/file'], ['html'])).toEqual([ {from: '/prefix/file.html', to: '/prefix/file'}, ]); }); - test('should not create redirection for an empty extension array', () => { + it('does not create redirection for an empty extension array', () => { const ext: string[] = []; expect(createFromExtensionsRedirects([''], ext)).toEqual([]); expect(createFromExtensionsRedirects(['/'], ext)).toEqual([]); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts index 68f29cbf485b..da727e4ad258 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts @@ -8,18 +8,18 @@ import normalizePluginOptions, { DefaultPluginOptions, } from '../normalizePluginOptions'; -import type {CreateRedirectsFnOption} from '../types'; +import type {CreateRedirectsFnOption} from '@docusaurus/plugin-client-redirects'; describe('normalizePluginOptions', () => { - test('should return default options for undefined user options', () => { + it('returns default options for undefined user options', () => { expect(normalizePluginOptions()).toEqual(DefaultPluginOptions); }); - test('should return default options for empty user options', () => { + it('returns default options for empty user options', () => { expect(normalizePluginOptions()).toEqual(DefaultPluginOptions); }); - test('should override one default options with valid user options', () => { + it('overrides one default options with valid user options', () => { expect( normalizePluginOptions({ toExtensions: ['html'], @@ -27,7 +27,7 @@ describe('normalizePluginOptions', () => { ).toEqual({...DefaultPluginOptions, toExtensions: ['html']}); }); - test('should override all default options with valid user options', () => { + it('overrides all default options with valid user options', () => { const createRedirects: CreateRedirectsFnOption = (_routePath: string) => []; expect( normalizePluginOptions({ @@ -45,7 +45,7 @@ describe('normalizePluginOptions', () => { }); }); - test('should reject bad fromExtensions user inputs', () => { + it('rejects bad fromExtensions user inputs', () => { expect(() => normalizePluginOptions({ fromExtensions: [null, undefined, 123, true] as unknown as string[], @@ -53,7 +53,7 @@ describe('normalizePluginOptions', () => { ).toThrowErrorMatchingSnapshot(); }); - test('should reject bad toExtensions user inputs', () => { + it('rejects bad toExtensions user inputs', () => { expect(() => normalizePluginOptions({ toExtensions: [null, undefined, 123, true] as unknown as string[], @@ -61,7 +61,7 @@ describe('normalizePluginOptions', () => { ).toThrowErrorMatchingSnapshot(); }); - test('should reject bad createRedirects user inputs', () => { + it('rejects bad createRedirects user inputs', () => { expect(() => normalizePluginOptions({ createRedirects: ['bad', 'value'] as unknown as CreateRedirectsFnOption, diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts index 2b0b9b59af39..727fd1184258 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts @@ -8,7 +8,7 @@ import {validateRedirect} from '../redirectValidation'; describe('validateRedirect', () => { - test('validate good redirects without throwing', () => { + it('validate good redirects without throwing', () => { expect(() => { validateRedirect({ from: '/fromSomePath', @@ -29,7 +29,7 @@ describe('validateRedirect', () => { }).not.toThrow(); }); - test('throw for bad redirects', () => { + it('throw for bad redirects', () => { expect(() => validateRedirect({ from: 'https://fb.com/fromSomePath', diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts index 1b29c49e1b6f..8cb651fab8a4 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts @@ -17,7 +17,7 @@ import writeRedirectFiles, { // - https://github.com/facebook/docusaurus/issues/3886 // - https://github.com/facebook/docusaurus/issues/3925 describe('createToUrl', () => { - test('should create appropriate redirect urls', async () => { + it('creates appropriate redirect urls', async () => { expect(createToUrl('/', '/docs/something/else')).toEqual( '/docs/something/else', ); @@ -29,7 +29,7 @@ describe('createToUrl', () => { ); }); - test('should create appropriate redirect urls with baseUrl', async () => { + it('creates appropriate redirect urls with baseUrl', async () => { expect(createToUrl('/baseUrl/', '/docs/something/else')).toEqual( '/baseUrl/docs/something/else', ); @@ -43,7 +43,7 @@ describe('createToUrl', () => { }); describe('toRedirectFilesMetadata', () => { - test('should create appropriate metadata trailingSlash=undefined', async () => { + it('creates appropriate metadata trailingSlash=undefined', async () => { const pluginContext = { outDir: '/tmp/someFixedOutDir', baseUrl: 'https://docusaurus.io', @@ -70,7 +70,7 @@ describe('toRedirectFilesMetadata', () => { ); }); - test('should create appropriate metadata trailingSlash=true', async () => { + it('creates appropriate metadata trailingSlash=true', async () => { const pluginContext = { outDir: '/tmp/someFixedOutDir', baseUrl: 'https://docusaurus.io', @@ -97,7 +97,7 @@ describe('toRedirectFilesMetadata', () => { ); }); - test('should create appropriate metadata trailingSlash=false', async () => { + it('creates appropriate metadata trailingSlash=false', async () => { const pluginContext = { outDir: '/tmp/someFixedOutDir', baseUrl: 'https://docusaurus.io', @@ -127,7 +127,7 @@ describe('toRedirectFilesMetadata', () => { ); }); - test('should create appropriate metadata for root baseUrl', async () => { + it('creates appropriate metadata for root baseUrl', async () => { const pluginContext = { outDir: '/tmp/someFixedOutDir', baseUrl: '/', @@ -142,7 +142,7 @@ describe('toRedirectFilesMetadata', () => { ); }); - test('should create appropriate metadata for empty baseUrl', async () => { + it('creates appropriate metadata for empty baseUrl', async () => { const pluginContext = { outDir: '/tmp/someFixedOutDir', baseUrl: '', @@ -159,7 +159,7 @@ describe('toRedirectFilesMetadata', () => { }); describe('writeRedirectFiles', () => { - test('write the files', async () => { + it('write the files', async () => { const outDir = `/tmp/docusaurus_tests_${Math.random()}`; const filesMetadata = [ @@ -184,7 +184,7 @@ describe('writeRedirectFiles', () => { ).resolves.toEqual('content 2'); }); - test('avoid overwriting existing files', async () => { + it('avoid overwriting existing files', async () => { const outDir = `/tmp/docusaurus_tests_${Math.random()}`; const filesMetadata = [ diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/linkify.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap similarity index 78% rename from packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/linkify.test.ts.snap rename to packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap index f1c28fabbb0f..3820f35780e5 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/linkify.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`report broken markdown links 1`] = ` +exports[`linkify reports broken markdown links 1`] = ` "--- title: This post links to another one! --- @@ -15,7 +15,7 @@ title: This post links to another one! " `; -exports[`transform to correct link 1`] = ` +exports[`linkify transforms to correct link 1`] = ` "--- title: This post links to another one! --- diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index 67b84bc407ef..f44f9a71052d 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`blogFeed atom shows feed item for each post 1`] = ` +exports[`atom has feed item for each post 1`] = ` Array [ " @@ -84,7 +84,7 @@ Array [ ] `; -exports[`blogFeed json shows feed item for each post 1`] = ` +exports[`json has feed item for each post 1`] = ` Array [ "{ \\"version\\": \\"https://jsonfeed.org/version/1\\", @@ -171,7 +171,7 @@ Array [ ] `; -exports[`blogFeed rss shows feed item for each post 1`] = ` +exports[`rss has feed item for each post 1`] = ` Array [ " diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap index 1d788e5744a0..37ba6bf0d0f6 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`loadBlog test blog tags 1`] = ` +exports[`blog plugin works on blog tags without pagination 1`] = ` Object { "/blog/tags/tag-1": Object { "items": Array [ @@ -14,33 +14,18 @@ Object { "items": Array [ "/simple/slug/another", "/another/tags", + "/another/tags2", ], "metadata": Object { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": "/blog/tags/tag-1/page/2", + "nextPage": null, "page": 1, "permalink": "/blog/tags/tag-1", - "postsPerPage": 2, + "postsPerPage": 3, "previousPage": null, "totalCount": 3, - "totalPages": 2, - }, - }, - Object { - "items": Array [ - "/another/tags2", - ], - "metadata": Object { - "blogDescription": "Blog", - "blogTitle": "Blog", - "nextPage": null, - "page": 2, - "permalink": "/blog/tags/tag-1/page/2", - "postsPerPage": 2, - "previousPage": "/blog/tags/tag-1", - "totalCount": 3, - "totalPages": 2, + "totalPages": 1, }, }, ], @@ -76,7 +61,7 @@ Object { } `; -exports[`loadBlog test blog tags: no pagination 1`] = ` +exports[`blog plugin works with blog tags 1`] = ` Object { "/blog/tags/tag-1": Object { "items": Array [ @@ -90,18 +75,33 @@ Object { "items": Array [ "/simple/slug/another", "/another/tags", - "/another/tags2", ], "metadata": Object { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": null, + "nextPage": "/blog/tags/tag-1/page/2", "page": 1, "permalink": "/blog/tags/tag-1", - "postsPerPage": 3, + "postsPerPage": 2, "previousPage": null, "totalCount": 3, - "totalPages": 1, + "totalPages": 2, + }, + }, + Object { + "items": Array [ + "/another/tags2", + ], + "metadata": Object { + "blogDescription": "Blog", + "blogTitle": "Blog", + "nextPage": null, + "page": 2, + "permalink": "/blog/tags/tag-1/page/2", + "postsPerPage": 2, + "previousPage": "/blog/tags/tag-1", + "totalCount": 3, + "totalPages": 2, }, }, ], diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap index 0a95617bd7bf..dd55a4cd1dce 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should throw Error in case of invalid feedtype 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`; +exports[`blog plugin options schema throws Error in case of invalid feedtype 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`; -exports[`should throw Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be greater than or equal to 1]`; +exports[`blog plugin options schema throws Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be greater than or equal to 1]`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap index d2cb32ded063..9e97fbbe8347 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getContentTranslationFiles should return translation files matching snapshot 1`] = ` +exports[`getContentTranslationFiles returns translation files matching snapshot 1`] = ` Array [ Object { "content": Object { @@ -22,7 +22,7 @@ Array [ ] `; -exports[`translateContent should fallback when translation is incomplete 1`] = ` +exports[`translateContent falls back when translation is incomplete 1`] = ` Object { "blogListPaginated": Array [ Object { @@ -63,7 +63,7 @@ Object { } `; -exports[`translateContent should return translated loaded content matching snapshot 1`] = ` +exports[`translateContent returns translated loaded 1`] = ` Object { "blogListPaginated": Array [ Object { diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts index 78152420283e..5c159b7bbd73 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts @@ -14,7 +14,7 @@ import { import path from 'path'; describe('getBlogPostAuthors', () => { - test('can read no authors', () => { + it('can read no authors', () => { expect( getBlogPostAuthors({ frontMatter: {}, @@ -31,7 +31,7 @@ describe('getBlogPostAuthors', () => { ).toEqual([]); }); - test('can read author from legacy front matter', () => { + it('can read author from legacy front matter', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -79,7 +79,7 @@ describe('getBlogPostAuthors', () => { ]); }); - test('can read authors string', () => { + it('can read authors string', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -90,7 +90,7 @@ describe('getBlogPostAuthors', () => { ).toEqual([{key: 'slorber', name: 'Sébastien Lorber'}]); }); - test('can read authors string[]', () => { + it('can read authors string[]', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -107,7 +107,7 @@ describe('getBlogPostAuthors', () => { ]); }); - test('can read authors Author', () => { + it('can read authors Author', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -118,7 +118,7 @@ describe('getBlogPostAuthors', () => { ).toEqual([{name: 'Sébastien Lorber', title: 'maintainer'}]); }); - test('can read authors Author[]', () => { + it('can read authors Author[]', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -135,7 +135,7 @@ describe('getBlogPostAuthors', () => { ]); }); - test('can read authors complex (string | Author)[] setup with keys and local overrides', () => { + it('can read authors complex (string | Author)[] setup with keys and local overrides', () => { expect( getBlogPostAuthors({ frontMatter: { @@ -166,7 +166,7 @@ describe('getBlogPostAuthors', () => { ]); }); - test('throw when using author key with no authorsMap', () => { + it('throw when using author key with no authorsMap', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -180,7 +180,7 @@ describe('getBlogPostAuthors', () => { `); }); - test('throw when using author key with empty authorsMap', () => { + it('throw when using author key with empty authorsMap', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -194,7 +194,7 @@ describe('getBlogPostAuthors', () => { `); }); - test('throw when using bad author key in string', () => { + it('throw when using bad author key in string', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -213,7 +213,7 @@ describe('getBlogPostAuthors', () => { `); }); - test('throw when using bad author key in string[]', () => { + it('throw when using bad author key in string[]', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -232,7 +232,7 @@ describe('getBlogPostAuthors', () => { `); }); - test('throw when using bad author key in Author[].key', () => { + it('throw when using bad author key in Author[].key', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -251,7 +251,7 @@ describe('getBlogPostAuthors', () => { `); }); - test('throw when mixing legacy/new authors front matter', () => { + it('throw when mixing legacy/new authors front matter', () => { expect(() => getBlogPostAuthors({ frontMatter: { @@ -287,7 +287,7 @@ describe('getAuthorsMap', () => { contentPath: fixturesDir, }; - test('getAuthorsMap can read yml file', async () => { + it('getAuthorsMap can read yml file', async () => { await expect( getAuthorsMap({ contentPaths, @@ -296,7 +296,7 @@ describe('getAuthorsMap', () => { ).resolves.toBeDefined(); }); - test('getAuthorsMap can read json file', async () => { + it('getAuthorsMap can read json file', async () => { await expect( getAuthorsMap({ contentPaths, @@ -305,7 +305,7 @@ describe('getAuthorsMap', () => { ).resolves.toBeDefined(); }); - test('getAuthorsMap can return undefined if yaml file not found', async () => { + it('getAuthorsMap can return undefined if yaml file not found', async () => { await expect( getAuthorsMap({ contentPaths, @@ -316,7 +316,7 @@ describe('getAuthorsMap', () => { }); describe('validateAuthorsMap', () => { - test('accept valid authors map', () => { + it('accept valid authors map', () => { const authorsMap: AuthorsMap = { slorber: { name: 'Sébastien Lorber', @@ -338,7 +338,7 @@ describe('validateAuthorsMap', () => { expect(validateAuthorsMap(authorsMap)).toEqual(authorsMap); }); - test('rename snake case image_url to camelCase imageURL', () => { + it('rename snake case image_url to camelCase imageURL', () => { const authorsMap: AuthorsMap = { slorber: { name: 'Sébastien Lorber', @@ -353,7 +353,7 @@ describe('validateAuthorsMap', () => { }); }); - test('accept author with only image', () => { + it('accept author with only image', () => { const authorsMap: AuthorsMap = { slorber: { imageURL: 'https://github.com/slorber.png', @@ -363,7 +363,7 @@ describe('validateAuthorsMap', () => { expect(validateAuthorsMap(authorsMap)).toEqual(authorsMap); }); - test('reject author without name or image', () => { + it('reject author without name or image', () => { const authorsMap: AuthorsMap = { slorber: { title: 'foo', @@ -376,7 +376,7 @@ describe('validateAuthorsMap', () => { ); }); - test('reject undefined author', () => { + it('reject undefined author', () => { expect(() => validateAuthorsMap({ slorber: undefined, @@ -384,7 +384,7 @@ describe('validateAuthorsMap', () => { ).toThrowErrorMatchingInlineSnapshot(`"\\"slorber\\" is required"`); }); - test('reject null author', () => { + it('reject null author', () => { expect(() => validateAuthorsMap({ slorber: null, @@ -394,7 +394,7 @@ describe('validateAuthorsMap', () => { ); }); - test('reject array author', () => { + it('reject array author', () => { expect(() => validateAuthorsMap({slorber: []}), ).toThrowErrorMatchingInlineSnapshot( @@ -402,14 +402,14 @@ describe('validateAuthorsMap', () => { ); }); - test('reject array content', () => { + it('reject array content', () => { expect(() => validateAuthorsMap([])).toThrowErrorMatchingInlineSnapshot( // TODO improve this error message `"\\"value\\" must be of type object"`, ); }); - test('reject flat author', () => { + it('reject flat author', () => { expect(() => validateAuthorsMap({name: 'Sébastien'}), ).toThrowErrorMatchingInlineSnapshot( @@ -418,7 +418,7 @@ describe('validateAuthorsMap', () => { ); }); - test('reject non-map author', () => { + it('reject non-map author', () => { const authorsMap: AuthorsMap = { // @ts-expect-error: for tests slorber: [], diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts index 67ee71969f05..7622034b0954 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts @@ -24,13 +24,13 @@ function testField(params: { ][]; }) { describe(`"${params.fieldName}" field`, () => { - test('accept valid values', () => { + it('accept valid values', () => { params.validFrontMatters.forEach((frontMatter) => { expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter); }); }); - test('convert valid values', () => { + it('convert valid values', () => { params.convertibleFrontMatter?.forEach( ([convertibleFrontMatter, convertedFrontMatter]) => { expect(validateBlogPostFrontMatter(convertibleFrontMatter)).toEqual( @@ -40,7 +40,7 @@ function testField(params: { ); }); - test('throw error for values', () => { + it('throw error for values', () => { params.invalidFrontMatters?.forEach(([frontMatter, message]) => { try { validateBlogPostFrontMatter(frontMatter); @@ -64,12 +64,12 @@ function testField(params: { } describe('validateBlogPostFrontMatter', () => { - test('accept empty object', () => { + it('accept empty object', () => { const frontMatter = {}; expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter); }); - test('accept unknown field', () => { + it('accept unknown field', () => { const frontMatter = {abc: '1'}; expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter); }); @@ -106,7 +106,7 @@ describe('validateBlogPostFrontMatter id', () => { }); describe('validateBlogPostFrontMatter handles legacy/new author front matter', () => { - test('allow legacy author front matter', () => { + it('allow legacy author front matter', () => { const frontMatter: BlogPostFrontMatter = { author: 'Sebastien', author_url: 'https://sebastienlorber.com', @@ -116,7 +116,7 @@ describe('validateBlogPostFrontMatter handles legacy/new author front matter', ( expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter); }); - test('allow new authors front matter', () => { + it('allow new authors front matter', () => { const frontMatter: BlogPostFrontMatter = { authors: [ 'slorber', diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts index 4a8874dfb8ce..db3ad1852a53 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts @@ -5,10 +5,74 @@ * LICENSE file in the root directory of this source tree. */ -import {truncate, parseBlogFileName} from '../blogUtils'; +import {jest} from '@jest/globals'; +import { + truncate, + parseBlogFileName, + linkify, + getSourceToPermalink, + type LinkifyParams, +} from '../blogUtils'; +import fs from 'fs-extra'; +import path from 'path'; +import type { + BlogBrokenMarkdownLink, + BlogContentPaths, + BlogPost, +} from '../types'; + +const siteDir = path.join(__dirname, '__fixtures__', 'website'); +const contentPaths: BlogContentPaths = { + contentPath: path.join(siteDir, 'blog-with-ref'), + contentPathLocalized: path.join(siteDir, 'blog-with-ref-localized'), +}; +const pluginDir = 'blog-with-ref'; +const blogPosts: BlogPost[] = [ + { + id: 'Happy 1st Birthday Slash!', + metadata: { + permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', + source: path.posix.join( + '@site', + pluginDir, + '2018-12-14-Happy-First-Birthday-Slash.md', + ), + title: 'Happy 1st Birthday Slash!', + description: `pattern name`, + date: new Date('2018-12-14'), + tags: [], + prevItem: { + permalink: '/blog/2019/01/01/date-matter', + title: 'date-matter', + }, + truncated: false, + }, + }, +]; + +const transform = async ( + filePath: string, + options?: Partial, +) => { + const fileContent = await fs.readFile(filePath, 'utf-8'); + const transformedContent = linkify({ + filePath, + fileString: fileContent, + siteDir, + contentPaths, + sourceToPermalink: getSourceToPermalink(blogPosts), + onBrokenMarkdownLink: (brokenMarkdownLink) => { + throw new Error( + `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, + ); + }, + ...options, + }); + return [fileContent, transformedContent]; +}; describe('truncate', () => { - test('truncates texts', () => { + it('truncates texts', () => { expect( truncate('aaa\n\nbbb\nccc', //), ).toEqual('aaa\n'); @@ -16,7 +80,8 @@ describe('truncate', () => { truncate('\n\nbbb\nccc', //), ).toEqual('\n'); }); - test('leaves texts without markers', () => { + + it('leaves texts without markers', () => { expect(truncate('aaa\nbbb\nccc', //)).toEqual( 'aaa\nbbb\nccc', ); @@ -25,7 +90,7 @@ describe('truncate', () => { }); describe('parseBlogFileName', () => { - test('parse file', () => { + it('parses file', () => { expect(parseBlogFileName('some-post.md')).toEqual({ date: undefined, text: 'some-post', @@ -33,7 +98,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse folder', () => { + it('parses folder', () => { expect(parseBlogFileName('some-post/index.md')).toEqual({ date: undefined, text: 'some-post', @@ -41,7 +106,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse nested file', () => { + it('parses nested file', () => { expect(parseBlogFileName('some-post/some-file.md')).toEqual({ date: undefined, text: 'some-post/some-file', @@ -49,7 +114,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse nested folder', () => { + it('parses nested folder', () => { expect(parseBlogFileName('some-post/some-subfolder/index.md')).toEqual({ date: undefined, text: 'some-post/some-subfolder', @@ -57,7 +122,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse file respecting date convention', () => { + it('parses file respecting date convention', () => { expect( parseBlogFileName('2021-05-12-announcing-docusaurus-two-beta.md'), ).toEqual({ @@ -67,7 +132,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse folder name respecting date convention', () => { + it('parses folder name respecting date convention', () => { expect( parseBlogFileName('2021-05-12-announcing-docusaurus-two-beta/index.md'), ).toEqual({ @@ -77,7 +142,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse folder tree respecting date convention', () => { + it('parses folder tree respecting date convention', () => { expect( parseBlogFileName('2021/05/12/announcing-docusaurus-two-beta/index.md'), ).toEqual({ @@ -87,7 +152,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse folder name/tree (mixed) respecting date convention', () => { + it('parses folder name/tree (mixed) respecting date convention', () => { expect( parseBlogFileName('2021/05-12-announcing-docusaurus-two-beta/index.md'), ).toEqual({ @@ -97,7 +162,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse nested folder tree respecting date convention', () => { + it('parses nested folder tree respecting date convention', () => { expect( parseBlogFileName( '2021/05/12/announcing-docusaurus-two-beta/subfolder/subfile.md', @@ -109,7 +174,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse date in the middle of path', () => { + it('parses date in the middle of path', () => { expect( parseBlogFileName('team-a/2021/05/12/announcing-docusaurus-two-beta.md'), ).toEqual({ @@ -119,7 +184,7 @@ describe('parseBlogFileName', () => { }); }); - test('parse date in the middle of a folder name', () => { + it('parses date in the middle of a folder name', () => { expect( parseBlogFileName( 'team-a-2021-05-12-hey/announcing-docusaurus-two-beta.md', @@ -131,3 +196,40 @@ describe('parseBlogFileName', () => { }); }); }); + +describe('linkify', () => { + it('transforms to correct link', async () => { + const post = path.join(contentPaths.contentPath, 'post.md'); + const [content, transformedContent] = await transform(post); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain( + '](/blog/2018/12/14/Happy-First-Birthday-Slash', + ); + expect(transformedContent).not.toContain( + '](2018-12-14-Happy-First-Birthday-Slash.md)', + ); + expect(content).not.toEqual(transformedContent); + }); + + it('reports broken markdown links', async () => { + const filePath = 'post-with-broken-links.md'; + const folderPath = contentPaths.contentPath; + const postWithBrokenLinks = path.join(folderPath, filePath); + const onBrokenMarkdownLink = jest.fn(); + const [, transformedContent] = await transform(postWithBrokenLinks, { + onBrokenMarkdownLink, + }); + expect(transformedContent).toMatchSnapshot(); + expect(onBrokenMarkdownLink).toHaveBeenCalledTimes(2); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { + filePath: path.resolve(folderPath, filePath), + contentPaths, + link: 'postNotExist1.md', + } as BlogBrokenMarkdownLink); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { + filePath: path.resolve(folderPath, filePath), + contentPaths, + link: './postNotExist2.mdx', + } as BlogBrokenMarkdownLink); + }); +}); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index 6ac05193ce32..99ac95ca49ed 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -52,85 +52,81 @@ async function testGenerateFeeds( }); } -describe('blogFeed', () => { - (['atom', 'rss', 'json'] as const).forEach((feedType) => { - describe(`${feedType}`, () => { - const fsMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {}); +describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { + const fsMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {}); - test('should not show feed without posts', async () => { - const siteDir = __dirname; - const siteConfig = { - title: 'Hello', - baseUrl: '/', - url: 'https://docusaurus.io', - favicon: 'image/favicon.ico', - }; - const outDir = path.join(siteDir, 'build-snap'); + it('does not get generated without posts', async () => { + const siteDir = __dirname; + const siteConfig = { + title: 'Hello', + baseUrl: '/', + url: 'https://docusaurus.io', + favicon: 'image/favicon.ico', + }; + const outDir = path.join(siteDir, 'build-snap'); - await testGenerateFeeds( - { - siteDir, - siteConfig, - i18n: DefaultI18N, - outDir, - } as LoadContext, - { - path: 'invalid-blog-path', - routeBasePath: 'blog', - tagsBasePath: 'tags', - authorsMapPath: 'authors.yml', - include: ['*.md', '*.mdx'], - feedOptions: { - type: [feedType], - copyright: 'Copyright', - }, - readingTime: ({content, defaultReadingTime}) => - defaultReadingTime({content}), - } as PluginOptions, - ); + await testGenerateFeeds( + { + siteDir, + siteConfig, + i18n: DefaultI18N, + outDir, + } as LoadContext, + { + path: 'invalid-blog-path', + routeBasePath: 'blog', + tagsBasePath: 'tags', + authorsMapPath: 'authors.yml', + include: ['*.md', '*.mdx'], + feedOptions: { + type: [feedType], + copyright: 'Copyright', + }, + readingTime: ({content, defaultReadingTime}) => + defaultReadingTime({content}), + } as PluginOptions, + ); - expect(fsMock).toBeCalledTimes(0); - fsMock.mockClear(); - }); + expect(fsMock).toBeCalledTimes(0); + fsMock.mockClear(); + }); - test('shows feed item for each post', async () => { - const siteDir = path.join(__dirname, '__fixtures__', 'website'); - const outDir = path.join(siteDir, 'build-snap'); - const siteConfig = { - title: 'Hello', - baseUrl: '/myBaseUrl/', - url: 'https://docusaurus.io', - favicon: 'image/favicon.ico', - }; + it('has feed item for each post', async () => { + const siteDir = path.join(__dirname, '__fixtures__', 'website'); + const outDir = path.join(siteDir, 'build-snap'); + const siteConfig = { + title: 'Hello', + baseUrl: '/myBaseUrl/', + url: 'https://docusaurus.io', + favicon: 'image/favicon.ico', + }; - // Build is quite difficult to mock, so we built the blog beforehand and - // copied the output to the fixture... - await testGenerateFeeds( - { - siteDir, - siteConfig, - i18n: DefaultI18N, - outDir, - } as LoadContext, - { - path: 'blog', - routeBasePath: 'blog', - tagsBasePath: 'tags', - authorsMapPath: 'authors.yml', - include: DEFAULT_OPTIONS.include, - exclude: DEFAULT_OPTIONS.exclude, - feedOptions: { - type: [feedType], - copyright: 'Copyright', - }, - readingTime: ({content, defaultReadingTime}) => - defaultReadingTime({content}), - } as PluginOptions, - ); + // Build is quite difficult to mock, so we built the blog beforehand and + // copied the output to the fixture... + await testGenerateFeeds( + { + siteDir, + siteConfig, + i18n: DefaultI18N, + outDir, + } as LoadContext, + { + path: 'blog', + routeBasePath: 'blog', + tagsBasePath: 'tags', + authorsMapPath: 'authors.yml', + include: DEFAULT_OPTIONS.include, + exclude: DEFAULT_OPTIONS.exclude, + feedOptions: { + type: [feedType], + copyright: 'Copyright', + }, + readingTime: ({content, defaultReadingTime}) => + defaultReadingTime({content}), + } as PluginOptions, + ); - expect(fsMock.mock.calls.map((call) => call[1])).toMatchSnapshot(); - fsMock.mockClear(); - }); - }); + expect(fsMock.mock.calls.map((call) => call[1])).toMatchSnapshot(); + fsMock.mockClear(); }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 2f7668091330..345847a56cd7 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -59,58 +59,58 @@ function validateAndNormalize( } } -describe('loadBlog', () => { - const PluginPath = 'blog'; - - const BaseEditUrl = 'https://baseEditUrl.com/edit'; - - const getPlugin = async ( - siteDir: string, - pluginOptions: Partial = {}, - i18n: I18n = DefaultI18N, - ) => { - const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus'); - const siteConfig = { - title: 'Hello', - baseUrl: '/', - url: 'https://docusaurus.io', - } as DocusaurusConfig; - return pluginContentBlog( - { - siteDir, - siteConfig, - generatedFilesDir, - i18n, - } as LoadContext, - validateAndNormalize(PluginOptionSchema, { - path: PluginPath, - editUrl: BaseEditUrl, - ...pluginOptions, - }), - ); - }; - - const getBlogPosts = async ( - siteDir: string, - pluginOptions: Partial = {}, - i18n: I18n = DefaultI18N, - ) => { - const plugin = await getPlugin(siteDir, pluginOptions, i18n); - const {blogPosts} = (await plugin.loadContent!())!; - return blogPosts; - }; - - const getBlogTags = async ( - siteDir: string, - pluginOptions: Partial = {}, - i18n: I18n = DefaultI18N, - ) => { - const plugin = await getPlugin(siteDir, pluginOptions, i18n); - const {blogTags} = (await plugin.loadContent!())!; - return blogTags; - }; - - test('getPathsToWatch', async () => { +const PluginPath = 'blog'; + +const BaseEditUrl = 'https://baseEditUrl.com/edit'; + +const getPlugin = async ( + siteDir: string, + pluginOptions: Partial = {}, + i18n: I18n = DefaultI18N, +) => { + const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus'); + const siteConfig = { + title: 'Hello', + baseUrl: '/', + url: 'https://docusaurus.io', + } as DocusaurusConfig; + return pluginContentBlog( + { + siteDir, + siteConfig, + generatedFilesDir, + i18n, + } as LoadContext, + validateAndNormalize(PluginOptionSchema, { + path: PluginPath, + editUrl: BaseEditUrl, + ...pluginOptions, + }), + ); +}; + +const getBlogPosts = async ( + siteDir: string, + pluginOptions: Partial = {}, + i18n: I18n = DefaultI18N, +) => { + const plugin = await getPlugin(siteDir, pluginOptions, i18n); + const {blogPosts} = (await plugin.loadContent!())!; + return blogPosts; +}; + +const getBlogTags = async ( + siteDir: string, + pluginOptions: Partial = {}, + i18n: I18n = DefaultI18N, +) => { + const plugin = await getPlugin(siteDir, pluginOptions, i18n); + const {blogTags} = (await plugin.loadContent!())!; + return blogTags; +}; + +describe('blog plugin', () => { + it('getPathsToWatch returns right files', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const plugin = await getPlugin(siteDir); const pathsToWatch = plugin.getPathsToWatch!(); @@ -124,7 +124,7 @@ describe('loadBlog', () => { ]); }); - test('simple website', async () => { + it('builds a simple website', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPosts = await getBlogPosts(siteDir); @@ -303,7 +303,7 @@ describe('loadBlog', () => { }); }); - test('simple website blog dates localized', async () => { + it('builds simple website blog with localized dates', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPostsFrench = await getBlogPosts(siteDir, {}, getI18n('fr')); expect(blogPostsFrench).toHaveLength(8); @@ -333,7 +333,7 @@ describe('loadBlog', () => { ); }); - test('edit url with editLocalizedBlogs true', async () => { + it('handles edit URL with editLocalizedBlogs: true', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPosts = await getBlogPosts(siteDir, {editLocalizedFiles: true}); @@ -346,7 +346,7 @@ describe('loadBlog', () => { ); }); - test('edit url with editUrl function', async () => { + it('handles edit URL with editUrl function', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const hardcodedEditUrl = 'hardcoded-edit-url'; @@ -410,7 +410,7 @@ describe('loadBlog', () => { }); }); - test('draft blog post not exists in production build', async () => { + it('excludes draft blog post from production build', async () => { process.env.NODE_ENV = 'production'; const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPosts = await getBlogPosts(siteDir); @@ -418,7 +418,7 @@ describe('loadBlog', () => { expect(blogPosts.find((v) => v.metadata.title === 'draft')).toBeUndefined(); }); - test('create blog post without date', async () => { + it('creates blog post without date', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -457,7 +457,7 @@ describe('loadBlog', () => { }); }); - test('test ascending sort direction of blog post', async () => { + it('can sort blog posts in ascending order', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const normalOrder = await getBlogPosts(siteDir); const reversedOrder = await getBlogPosts(siteDir, { @@ -468,7 +468,7 @@ describe('loadBlog', () => { ); }); - test('test blog tags', async () => { + it('works with blog tags', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -482,7 +482,7 @@ describe('loadBlog', () => { expect(blogTags).toMatchSnapshot(); }); - test('test blog tags: no pagination', async () => { + it('works on blog tags without pagination', async () => { const siteDir = path.join( __dirname, '__fixtures__', diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts deleted file mode 100644 index bdfffa7ffbe8..000000000000 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/linkify.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {jest} from '@jest/globals'; -import fs from 'fs-extra'; -import path from 'path'; -import {linkify, type LinkifyParams, getSourceToPermalink} from '../blogUtils'; -import type { - BlogBrokenMarkdownLink, - BlogContentPaths, - BlogPost, -} from '../types'; - -const siteDir = path.join(__dirname, '__fixtures__', 'website'); -const contentPaths: BlogContentPaths = { - contentPath: path.join(siteDir, 'blog-with-ref'), - contentPathLocalized: path.join(siteDir, 'blog-with-ref-localized'), -}; -const pluginDir = 'blog-with-ref'; -const blogPosts: BlogPost[] = [ - { - id: 'Happy 1st Birthday Slash!', - metadata: { - permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', - source: path.posix.join( - '@site', - pluginDir, - '2018-12-14-Happy-First-Birthday-Slash.md', - ), - title: 'Happy 1st Birthday Slash!', - description: `pattern name`, - date: new Date('2018-12-14'), - tags: [], - prevItem: { - permalink: '/blog/2019/01/01/date-matter', - title: 'date-matter', - }, - truncated: false, - }, - }, -]; - -const transform = async ( - filePath: string, - options?: Partial, -) => { - const fileContent = await fs.readFile(filePath, 'utf-8'); - const transformedContent = linkify({ - filePath, - fileString: fileContent, - siteDir, - contentPaths, - sourceToPermalink: getSourceToPermalink(blogPosts), - onBrokenMarkdownLink: (brokenMarkdownLink) => { - throw new Error( - `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, - ); - }, - ...options, - }); - return [fileContent, transformedContent]; -}; - -test('transform to correct link', async () => { - const post = path.join(contentPaths.contentPath, 'post.md'); - const [content, transformedContent] = await transform(post); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain( - '](/blog/2018/12/14/Happy-First-Birthday-Slash', - ); - expect(transformedContent).not.toContain( - '](2018-12-14-Happy-First-Birthday-Slash.md)', - ); - expect(content).not.toEqual(transformedContent); -}); - -test('report broken markdown links', async () => { - const filePath = 'post-with-broken-links.md'; - const folderPath = contentPaths.contentPath; - const postWithBrokenLinks = path.join(folderPath, filePath); - const onBrokenMarkdownLink = jest.fn(); - const [, transformedContent] = await transform(postWithBrokenLinks, { - onBrokenMarkdownLink, - }); - expect(transformedContent).toMatchSnapshot(); - expect(onBrokenMarkdownLink).toHaveBeenCalledTimes(2); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { - filePath: path.resolve(folderPath, filePath), - contentPaths, - link: 'postNotExist1.md', - } as BlogBrokenMarkdownLink); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { - filePath: path.resolve(folderPath, filePath), - contentPaths, - link: './postNotExist2.mdx', - } as BlogBrokenMarkdownLink); -}); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts index 4c0fdef73f16..28bbe06b8142 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts @@ -11,121 +11,123 @@ import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; const markdownPluginsFunctionStub = () => {}; const markdownPluginsObjectStub = {}; -test('should normalize options', () => { - const {value, error} = PluginOptionSchema.validate({}); - expect(value).toEqual(DEFAULT_OPTIONS); - expect(error).toBe(undefined); -}); - -test('should accept correctly defined user options', () => { - const userOptions = { - ...DEFAULT_OPTIONS, - feedOptions: {type: 'rss', title: 'myTitle'}, - path: 'not_blog', - routeBasePath: 'myBlog', - postsPerPage: 5, - include: ['api/*', 'docs/*'], - }; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual({ - ...userOptions, - feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, +describe('blog plugin options schema', () => { + it('normalizes options', () => { + const {value, error} = PluginOptionSchema.validate({}); + expect(value).toEqual(DEFAULT_OPTIONS); + expect(error).toBe(undefined); }); - expect(error).toBe(undefined); -}); -test('should accept valid user options', async () => { - const userOptions = { - ...DEFAULT_OPTIONS, - routeBasePath: 'myBlog', - beforeDefaultRemarkPlugins: [], - beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], - remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], - rehypePlugins: [ - markdownPluginsObjectStub, - [markdownPluginsFunctionStub, {option1: '42'}], - ], - }; - const {value, error} = await PluginOptionSchema.validate(userOptions); - expect(value).toEqual(userOptions); - expect(error).toBe(undefined); -}); + it('accepts correctly defined user options', () => { + const userOptions = { + ...DEFAULT_OPTIONS, + feedOptions: {type: 'rss', title: 'myTitle'}, + path: 'not_blog', + routeBasePath: 'myBlog', + postsPerPage: 5, + include: ['api/*', 'docs/*'], + }; + const {value, error} = PluginOptionSchema.validate(userOptions); + expect(value).toEqual({ + ...userOptions, + feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, + }); + expect(error).toBe(undefined); + }); -test('should throw Error in case of invalid options', () => { - const {error} = PluginOptionSchema.validate({ - path: 'not_blog', - postsPerPage: -1, - include: ['api/*', 'docs/*'], - routeBasePath: 'not_blog', + it('accepts valid user options', async () => { + const userOptions = { + ...DEFAULT_OPTIONS, + routeBasePath: 'myBlog', + beforeDefaultRemarkPlugins: [], + beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], + remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], + rehypePlugins: [ + markdownPluginsObjectStub, + [markdownPluginsFunctionStub, {option1: '42'}], + ], + }; + const {value, error} = PluginOptionSchema.validate(userOptions); + expect(value).toEqual(userOptions); + expect(error).toBe(undefined); }); - expect(error).toMatchSnapshot(); -}); + it('throws Error in case of invalid options', () => { + const {error} = PluginOptionSchema.validate({ + path: 'not_blog', + postsPerPage: -1, + include: ['api/*', 'docs/*'], + routeBasePath: 'not_blog', + }); -test('should throw Error in case of invalid feedtype', () => { - const {error} = PluginOptionSchema.validate({ - feedOptions: { - type: 'none', - }, + expect(error).toMatchSnapshot(); }); - expect(error).toMatchSnapshot(); -}); + it('throws Error in case of invalid feedtype', () => { + const {error} = PluginOptionSchema.validate({ + feedOptions: { + type: 'none', + }, + }); -test('should convert all feed type to array with other feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {type: 'all'}, - }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''}, + expect(error).toMatchSnapshot(); }); -}); -test('should accept null type and return same', () => { - const {value, error} = PluginOptionSchema.validate({ - feedOptions: {type: null}, - }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: null}, + it('converts all feed type to array with other feed type', () => { + const {value} = PluginOptionSchema.validate({ + feedOptions: {type: 'all'}, + }); + expect(value).toEqual({ + ...DEFAULT_OPTIONS, + feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''}, + }); }); - expect(error).toBe(undefined); -}); -test('should contain array with rss + atom for missing feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {}, + it('accepts null type and return same', () => { + const {value, error} = PluginOptionSchema.validate({ + feedOptions: {type: null}, + }); + expect(value).toEqual({ + ...DEFAULT_OPTIONS, + feedOptions: {type: null}, + }); + expect(error).toBe(undefined); }); - expect(value).toEqual(DEFAULT_OPTIONS); -}); -test('should have array with rss + atom, title for missing feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {title: 'title'}, + it('contains array with rss + atom for missing feed type', () => { + const {value} = PluginOptionSchema.validate({ + feedOptions: {}, + }); + expect(value).toEqual(DEFAULT_OPTIONS); }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''}, + + it('has array with rss + atom, title for missing feed type', () => { + const {value} = PluginOptionSchema.validate({ + feedOptions: {title: 'title'}, + }); + expect(value).toEqual({ + ...DEFAULT_OPTIONS, + feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''}, + }); }); }); describe('blog sidebar', () => { - test('should accept 0 sidebar count', () => { + it('accepts 0 sidebar count', () => { const userOptions = {blogSidebarCount: 0}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); expect(error).toBe(undefined); }); - test('should accept "ALL" sidebar count', () => { + it('accepts "ALL" sidebar count', () => { const userOptions = {blogSidebarCount: 'ALL'}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); expect(error).toBe(undefined); }); - test('should reject "abcdef" sidebar count', () => { + it('rejects "abcdef" sidebar count', () => { const userOptions = {blogSidebarCount: 'abcdef'}; const {error} = PluginOptionSchema.validate(userOptions); expect(error).toMatchInlineSnapshot( @@ -133,14 +135,14 @@ describe('blog sidebar', () => { ); }); - test('should accept "all posts" sidebar title', () => { + it('accepts "all posts" sidebar title', () => { const userOptions = {blogSidebarTitle: 'all posts'}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); expect(error).toBe(undefined); }); - test('should reject 42 sidebar title', () => { + it('rejects 42 sidebar title', () => { const userOptions = {blogSidebarTitle: 42}; const {error} = PluginOptionSchema.validate(userOptions); expect(error).toMatchInlineSnapshot( diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts index 71cdd42af28a..c6cfd5b5ae04 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts @@ -71,26 +71,26 @@ function getSampleTranslationFilesTranslated() { } describe('getContentTranslationFiles', () => { - test('should return translation files matching snapshot', async () => { + it('returns translation files matching snapshot', async () => { expect(getSampleTranslationFiles()).toMatchSnapshot(); }); }); describe('translateContent', () => { - test('should fallback when translation is incomplete', () => { + it('falls back when translation is incomplete', () => { expect( translateContent(sampleBlogContent, [{path: 'foo', content: {}}]), ).toMatchSnapshot(); }); - test('should not translate anything if translation files are untranslated', () => { + it('does not translate anything if translation files are untranslated', () => { const translationFiles = getSampleTranslationFiles(); expect(translateContent(sampleBlogContent, translationFiles)).toEqual( sampleBlogContent, ); }); - test('should return translated loaded content matching snapshot', () => { + it('returns translated loaded', () => { const translationFiles = getSampleTranslationFilesTranslated(); expect( translateContent(sampleBlogContent, translationFiles), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 3fb1a48e0a71..750029643375 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,26 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`sidebar site with wrong sidebar content 1`] = ` -"Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". -These sidebar document ids do not exist: -- goku - -Available document ids are: -- doc with space -- foo/bar -- foo/baz -- headingAsTitle -- hello -- ipsum -- lorem -- rootAbsoluteSlug -- rootRelativeSlug -- rootResolvedSlug -- rootTryToEscapeSlug -- slugs/absoluteSlug -- slugs/relativeSlug -- slugs/resolvedSlug -- slugs/tryToEscapeSlug" +exports[`sidebar site with undefined sidebar 1`] = ` +Object { + "defaultSidebar": Array [ + Object { + "id": "hello-1", + "type": "doc", + }, + Object { + "id": "hello-2", + "label": "Hello 2 From Doc", + "type": "doc", + }, + ], +} `; exports[`simple website content 1`] = ` @@ -1247,6 +1240,15 @@ Array [ ] `; +exports[`simple website getPathToWatch 1`] = ` +Array [ + "sidebars.json", + "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", + "docs/**/*.{md,mdx}", + "docs/**/_category_.{json,yml,yaml}", +] +`; + exports[`site with custom sidebar items generator sidebar is autogenerated according to a custom sidebarItemsGenerator 1`] = ` Object { "defaultSidebar": Array [ @@ -2511,6 +2513,19 @@ Array [ ] `; +exports[`versioned website (community) getPathToWatch 1`] = ` +Array [ + "community_sidebars.json", + "i18n/en/docusaurus-plugin-content-docs-community/current/**/*.{md,mdx}", + "community/**/*.{md,mdx}", + "community/**/_category_.{json,yml,yaml}", + "community_versioned_sidebars/version-1.0.0-sidebars.json", + "i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0/**/*.{md,mdx}", + "community_versioned_docs/version-1.0.0/**/*.{md,mdx}", + "community_versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}", +] +`; + exports[`versioned website content 1`] = ` Object { "description": "This is next version of bar.", @@ -3885,3 +3900,24 @@ Object { ], } `; + +exports[`versioned website getPathToWatch 1`] = ` +Array [ + "sidebars.json", + "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", + "docs/**/*.{md,mdx}", + "docs/**/_category_.{json,yml,yaml}", + "versioned_sidebars/version-1.0.1-sidebars.json", + "i18n/en/docusaurus-plugin-content-docs/version-1.0.1/**/*.{md,mdx}", + "versioned_docs/version-1.0.1/**/*.{md,mdx}", + "versioned_docs/version-1.0.1/**/_category_.{json,yml,yaml}", + "versioned_sidebars/version-1.0.0-sidebars.json", + "i18n/en/docusaurus-plugin-content-docs/version-1.0.0/**/*.{md,mdx}", + "versioned_docs/version-1.0.0/**/*.{md,mdx}", + "versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}", + "versioned_sidebars/version-withSlugs-sidebars.json", + "i18n/en/docusaurus-plugin-content-docs/version-withSlugs/**/*.{md,mdx}", + "versioned_docs/version-withSlugs/**/*.{md,mdx}", + "versioned_docs/version-withSlugs/**/_category_.{json,yml,yaml}", +] +`; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap index 408b3ed66574..62fceab793f3 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getLoadedContentTranslationFiles should return translation files matching snapshot 1`] = ` +exports[`getLoadedContentTranslationFiles returns translation files 1`] = ` Array [ Object { "content": Object { @@ -80,7 +80,7 @@ Array [ ] `; -exports[`translateLoadedContent should return translated loaded content matching snapshot 1`] = ` +exports[`translateLoadedContent returns translated loaded content 1`] = ` Object { "loadedVersions": Array [ Object { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index c9235e35cfac..21d6faa7c0fe 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -33,7 +33,7 @@ describe('docsVersion', () => { sidebarCollapsible: true, }; - test('no version tag provided', async () => { + it('no version tag provided', async () => { await expect(() => cliDocsVersionCommand( null, @@ -66,7 +66,7 @@ describe('docsVersion', () => { ); }); - test('version tag should not have slash', async () => { + it('version tag should not have slash', async () => { await expect(() => cliDocsVersionCommand( 'foo/bar', @@ -89,7 +89,7 @@ describe('docsVersion', () => { ); }); - test('version tag should not be too long', async () => { + it('version tag should not be too long', async () => { await expect(() => cliDocsVersionCommand( 'a'.repeat(255), @@ -102,7 +102,7 @@ describe('docsVersion', () => { ); }); - test('version tag should not be a dot or two dots', async () => { + it('version tag should not be a dot or two dots', async () => { await expect(() => cliDocsVersionCommand( '..', @@ -125,7 +125,7 @@ describe('docsVersion', () => { ); }); - test('version tag should be a valid pathname', async () => { + it('version tag should be a valid pathname', async () => { await expect(() => cliDocsVersionCommand( '', @@ -158,7 +158,7 @@ describe('docsVersion', () => { ); }); - test('version tag already exist', async () => { + it('version tag already exist', async () => { await expect(() => cliDocsVersionCommand( '1.0.0', @@ -171,7 +171,7 @@ describe('docsVersion', () => { ); }); - test('no docs file to version', async () => { + it('no docs file to version', async () => { const emptySiteDir = path.join(fixtureDir, 'empty-site'); await expect(() => cliDocsVersionCommand( @@ -185,8 +185,8 @@ describe('docsVersion', () => { ); }); - test('first time versioning', async () => { - const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); + it('first time versioning', async () => { + const copyMock = jest.spyOn(fs, 'copy').mockImplementation(() => {}); const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; @@ -200,7 +200,7 @@ describe('docsVersion', () => { versionsPath = filepath; versions = JSON.parse(content as string); }); - const consoleMock = jest.spyOn(console, 'log').mockImplementation(); + const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); const options = { ...DEFAULT_OPTIONS, sidebarPath: path.join(simpleSiteDir, 'sidebars.json'), @@ -240,8 +240,8 @@ describe('docsVersion', () => { consoleMock.mockRestore(); }); - test('not the first time versioning', async () => { - const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); + it('not the first time versioning', async () => { + const copyMock = jest.spyOn(fs, 'copy').mockImplementation(() => {}); const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; @@ -255,7 +255,7 @@ describe('docsVersion', () => { versionsPath = filepath; versions = JSON.parse(content as string); }); - const consoleMock = jest.spyOn(console, 'log').mockImplementation(); + const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); const options = { ...DEFAULT_OPTIONS, sidebarPath: path.join(versionedSiteDir, 'sidebars.json'), @@ -295,10 +295,10 @@ describe('docsVersion', () => { consoleMock.mockRestore(); }); - test('second docs instance versioning', async () => { + it('second docs instance versioning', async () => { const pluginId = 'community'; - const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); + const copyMock = jest.spyOn(fs, 'copy').mockImplementation(() => {}); const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; @@ -312,7 +312,7 @@ describe('docsVersion', () => { versionsPath = filepath; versions = JSON.parse(content as string); }); - const consoleMock = jest.spyOn(console, 'log').mockImplementation(); + const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); const options = { ...DEFAULT_OPTIONS, path: 'community', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts index 1a648a0eb628..727861d7d690 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts @@ -21,12 +21,14 @@ function testField(params: { ErrorMessage: string, ][]; }) { + // eslint-disable-next-line jest/require-top-level-describe test(`[${params.prefix}] accept valid values`, () => { params.validFrontMatters.forEach((frontMatter) => { expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter); }); }); + // eslint-disable-next-line jest/require-top-level-describe test(`[${params.prefix}] convert valid values`, () => { params.convertibleFrontMatter?.forEach( ([convertibleFrontMatter, convertedFrontMatter]) => { @@ -37,6 +39,7 @@ function testField(params: { ); }); + // eslint-disable-next-line jest/require-top-level-describe test(`[${params.prefix}] throw error for values`, () => { params.invalidFrontMatters?.forEach(([frontMatter, message]) => { try { @@ -59,13 +62,13 @@ function testField(params: { }); } -describe('validateDocFrontMatter', () => { - test('accept empty object', () => { +describe('doc front matter schema', () => { + it('accepts empty object', () => { const frontMatter: DocFrontMatter = {}; expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter); }); - test('accept unknown field', () => { + it('accepts unknown field', () => { const frontMatter = {abc: '1'}; expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter); }); @@ -277,7 +280,7 @@ describe('validateDocFrontMatter tags', () => { }); }); -describe('validateDocFrontMatter toc_min_heading_level', () => { +describe('toc_min_heading_level', () => { testField({ prefix: 'toc_min_heading_level', validFrontMatters: [ @@ -313,7 +316,7 @@ describe('validateDocFrontMatter toc_min_heading_level', () => { }); }); -describe('validateDocFrontMatter toc_max_heading_level', () => { +describe('toc_max_heading_level', () => { testField({ prefix: 'toc_max_heading_level', validFrontMatters: [ @@ -349,7 +352,7 @@ describe('validateDocFrontMatter toc_max_heading_level', () => { }); }); -describe('validateDocFrontMatter toc min/max consistency', () => { +describe('toc min/max consistency', () => { testField({ prefix: 'toc min/max', validFrontMatters: [ diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 5348c845c6b1..5e4b292fcc54 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -195,7 +195,7 @@ describe('simple site', () => { }; } - test('readVersionDocs', async () => { + it('readVersionDocs', async () => { const {options, currentVersion} = await loadSite(); const docs = await readVersionDocs(currentVersion, options); expect(docs.map((doc) => doc.source).sort()).toEqual( @@ -219,7 +219,7 @@ describe('simple site', () => { ); }); - test('normal docs', async () => { + it('normal docs', async () => { const {defaultTestUtils} = await loadSite(); await defaultTestUtils.testMeta(path.join('foo', 'bar.md'), { version: 'current', @@ -268,7 +268,7 @@ describe('simple site', () => { }); }); - test('docs with editUrl', async () => { + it('docs with editUrl', async () => { const {siteDir, context, options, currentVersion} = await loadSite({ options: { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', @@ -317,7 +317,7 @@ describe('simple site', () => { }); }); - test('docs with custom editUrl & unrelated frontMatter', async () => { + it('docs with custom editUrl & unrelated frontMatter', async () => { const {defaultTestUtils} = await loadSite(); await defaultTestUtils.testMeta('lorem.md', { @@ -338,7 +338,7 @@ describe('simple site', () => { }); }); - test('docs with function editUrl', async () => { + it('docs with function editUrl', async () => { const hardcodedEditUrl = 'hardcoded-edit-url'; const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl); @@ -399,7 +399,7 @@ describe('simple site', () => { }); }); - test('docs with last update time and author', async () => { + it('docs with last update time and author', async () => { const {siteDir, context, options, currentVersion} = await loadSite({ options: { showLastUpdateAuthor: true, @@ -435,7 +435,7 @@ describe('simple site', () => { }); }); - test('docs with slugs', async () => { + it('docs with slugs', async () => { const {defaultTestUtils} = await loadSite(); await defaultTestUtils.testSlug( @@ -473,7 +473,7 @@ describe('simple site', () => { ); }); - test('docs with invalid id', async () => { + it('docs with invalid id', async () => { const {defaultTestUtils} = await loadSite(); await expect(async () => defaultTestUtils.processDocFile( @@ -489,7 +489,7 @@ describe('simple site', () => { ); }); - test('custom pagination', async () => { + it('custom pagination', async () => { const {defaultTestUtils, options, versionsMetadata} = await loadSite(); const docs = await readVersionDocs(versionsMetadata[0], options); await expect( @@ -497,7 +497,7 @@ describe('simple site', () => { ).resolves.toMatchSnapshot(); }); - test('bad pagination', async () => { + it('bad pagination', async () => { const {defaultTestUtils, options, versionsMetadata} = await loadSite(); const docs = await readVersionDocs(versionsMetadata[0], options); docs.push( @@ -577,7 +577,7 @@ describe('versioned site', () => { }; } - test('next docs', async () => { + it('next docs', async () => { const {currentVersionTestUtils} = await loadSite(); await currentVersionTestUtils.testMeta(path.join('foo', 'bar.md'), { @@ -631,7 +631,7 @@ describe('versioned site', () => { }); }); - test('versioned docs', async () => { + it('versioned docs', async () => { const {version101TestUtils, version100TestUtils} = await loadSite(); await version100TestUtils.testMeta(path.join('foo', 'bar.md'), { @@ -690,7 +690,7 @@ describe('versioned site', () => { }); }); - test('next doc slugs', async () => { + it('next doc slugs', async () => { const {currentVersionTestUtils} = await loadSite(); await currentVersionTestUtils.testSlug( @@ -711,7 +711,7 @@ describe('versioned site', () => { ); }); - test('versioned doc slugs', async () => { + it('versioned doc slugs', async () => { const {versionWithSlugsTestUtils} = await loadSite(); await versionWithSlugsTestUtils.testSlug( @@ -749,7 +749,7 @@ describe('versioned site', () => { ); }); - test('doc with editUrl function', async () => { + it('doc with editUrl function', async () => { const hardcodedEditUrl = 'hardcoded-edit-url'; const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl); @@ -795,7 +795,7 @@ describe('versioned site', () => { }); }); - test('translated doc with editUrl', async () => { + it('translated doc with editUrl', async () => { const {siteDir, context, options, version100} = await loadSite({ options: { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', @@ -830,7 +830,7 @@ describe('versioned site', () => { }); }); - test('translated en doc with editUrl and editCurrentVersion=true', async () => { + it('translated en doc with editUrl and editCurrentVersion=true', async () => { const {siteDir, context, options, version100} = await loadSite({ options: { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', @@ -865,7 +865,7 @@ describe('versioned site', () => { }); }); - test('translated fr doc with editUrl and editLocalizedFiles=true', async () => { + it('translated fr doc with editUrl and editLocalizedFiles=true', async () => { const {siteDir, context, options, version100} = await loadSite({ options: { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', @@ -901,7 +901,7 @@ describe('versioned site', () => { }); }); - test('translated fr doc with editUrl and editLocalizedFiles=true + editCurrentVersion=true', async () => { + it('translated fr doc with editUrl and editLocalizedFiles=true + editCurrentVersion=true', async () => { const {siteDir, context, options, version100} = await loadSite({ options: { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', @@ -940,7 +940,7 @@ describe('versioned site', () => { }); describe('isConventionalDocIndex', () => { - test('supports readme', () => { + it('supports readme', () => { expect( isCategoryIndex({ fileName: 'readme', @@ -971,7 +971,7 @@ describe('isConventionalDocIndex', () => { ).toEqual(true); }); - test('supports index', () => { + it('supports index', () => { expect( isCategoryIndex({ fileName: 'index', @@ -1002,7 +1002,7 @@ describe('isConventionalDocIndex', () => { ).toEqual(true); }); - test('supports /.md', () => { + it('supports /.md', () => { expect( isCategoryIndex({ fileName: 'someCategory', @@ -1040,7 +1040,7 @@ describe('isConventionalDocIndex', () => { ).toEqual(true); }); - test('reject other cases', () => { + it('reject other cases', () => { expect( isCategoryIndex({ fileName: 'some_Category', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 885916099cd7..f6751119230f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -113,7 +113,7 @@ Entries created: }; describe('sidebar', () => { - test('site with wrong sidebar content', async () => { + it('site with wrong sidebar content', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); const context = await loadContext(siteDir); const sidebarPath = path.join(siteDir, 'wrong-sidebars.json'); @@ -123,10 +123,32 @@ describe('sidebar', () => { sidebarPath, }), ); - await expect(plugin.loadContent!()).rejects.toThrowErrorMatchingSnapshot(); + await expect(plugin.loadContent!()).rejects + .toThrowErrorMatchingInlineSnapshot(` + "Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". + These sidebar document ids do not exist: + - goku + + Available document ids are: + - doc with space + - foo/bar + - foo/baz + - headingAsTitle + - hello + - ipsum + - lorem + - rootAbsoluteSlug + - rootRelativeSlug + - rootResolvedSlug + - rootTryToEscapeSlug + - slugs/absoluteSlug + - slugs/relativeSlug + - slugs/resolvedSlug + - slugs/tryToEscapeSlug" + `); }); - test('site with wrong sidebar file path', async () => { + it('site with wrong sidebar file path', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); const context = await loadContext(siteDir); @@ -147,7 +169,7 @@ describe('sidebar', () => { `); }); - test('site with undefined sidebar', async () => { + it('site with undefined sidebar', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); const context = await loadContext(siteDir); const plugin = await pluginContentDocs( @@ -159,24 +181,10 @@ describe('sidebar', () => { const result = await plugin.loadContent!(); expect(result.loadedVersions).toHaveLength(1); - expect(result.loadedVersions[0].sidebars).toMatchInlineSnapshot(` - Object { - "defaultSidebar": Array [ - Object { - "id": "hello-1", - "type": "doc", - }, - Object { - "id": "hello-2", - "label": "Hello 2 From Doc", - "type": "doc", - }, - ], - } - `); + expect(result.loadedVersions[0].sidebars).toMatchSnapshot(); }); - test('site with disabled sidebar', async () => { + it('site with disabled sidebar', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); const context = await loadContext(siteDir); const plugin = await pluginContentDocs( @@ -195,7 +203,7 @@ describe('sidebar', () => { describe('empty/no docs website', () => { const siteDir = path.join(__dirname, '__fixtures__', 'empty-site'); - test('no files in docs folder', async () => { + it('no files in docs folder', async () => { const context = await loadContext(siteDir); await fs.ensureDir(path.join(siteDir, 'docs')); const plugin = await pluginContentDocs( @@ -209,7 +217,7 @@ describe('empty/no docs website', () => { ); }); - test('docs folder does not exist', async () => { + it('docs folder does not exist', async () => { const context = await loadContext(siteDir); await expect( pluginContentDocs( @@ -245,11 +253,11 @@ describe('simple website', () => { return {siteDir, context, sidebarPath, plugin, pluginContentDir}; } - test('extendCli - docsVersion', async () => { + it('extendCli - docsVersion', async () => { const {siteDir, sidebarPath, plugin} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') - .mockImplementation(); + .mockImplementation(async () => {}); const cli = new commander.Command(); // @ts-expect-error: in actual usage, we pass the static commander instead // of the new command @@ -265,22 +273,14 @@ describe('simple website', () => { mock.mockRestore(); }); - test('getPathToWatch', async () => { + it('getPathToWatch', async () => { const {siteDir, plugin} = await loadSite(); const pathToWatch = plugin.getPathsToWatch!(); const matchPattern = pathToWatch.map((filepath) => posixPath(path.relative(siteDir, filepath)), ); - expect(matchPattern).not.toEqual([]); - expect(matchPattern).toMatchInlineSnapshot(` - Array [ - "sidebars.json", - "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", - "docs/**/*.{md,mdx}", - "docs/**/_category_.{json,yml,yaml}", - ] - `); + expect(matchPattern).toMatchSnapshot(); expect(isMatch('docs/hello.md', matchPattern)).toEqual(true); expect(isMatch('docs/hello.mdx', matchPattern)).toEqual(true); expect(isMatch('docs/foo/bar.md', matchPattern)).toEqual(true); @@ -294,7 +294,7 @@ describe('simple website', () => { expect(isMatch('super/docs/hello.md', matchPattern)).toEqual(false); }); - test('configureWebpack', async () => { + it('configureWebpack', async () => { const {plugin} = await loadSite(); const content = await plugin.loadContent?.(); @@ -316,7 +316,7 @@ describe('simple website', () => { expect(errors).toBeUndefined(); }); - test('content', async () => { + it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); expect(content.loadedVersions.length).toEqual(1); @@ -370,11 +370,11 @@ describe('versioned website', () => { }; } - test('extendCli - docsVersion', async () => { + it('extendCli - docsVersion', async () => { const {siteDir, routeBasePath, sidebarPath, plugin} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') - .mockImplementation(); + .mockImplementation(async () => {}); const cli = new commander.Command(); // @ts-expect-error: in actual usage, we pass the static commander instead // of the new command @@ -390,33 +390,14 @@ describe('versioned website', () => { mock.mockRestore(); }); - test('getPathToWatch', async () => { + it('getPathToWatch', async () => { const {siteDir, plugin} = await loadSite(); const pathToWatch = plugin.getPathsToWatch!(); const matchPattern = pathToWatch.map((filepath) => posixPath(path.relative(siteDir, filepath)), ); expect(matchPattern).not.toEqual([]); - expect(matchPattern).toMatchInlineSnapshot(` - Array [ - "sidebars.json", - "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", - "docs/**/*.{md,mdx}", - "docs/**/_category_.{json,yml,yaml}", - "versioned_sidebars/version-1.0.1-sidebars.json", - "i18n/en/docusaurus-plugin-content-docs/version-1.0.1/**/*.{md,mdx}", - "versioned_docs/version-1.0.1/**/*.{md,mdx}", - "versioned_docs/version-1.0.1/**/_category_.{json,yml,yaml}", - "versioned_sidebars/version-1.0.0-sidebars.json", - "i18n/en/docusaurus-plugin-content-docs/version-1.0.0/**/*.{md,mdx}", - "versioned_docs/version-1.0.0/**/*.{md,mdx}", - "versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}", - "versioned_sidebars/version-withSlugs-sidebars.json", - "i18n/en/docusaurus-plugin-content-docs/version-withSlugs/**/*.{md,mdx}", - "versioned_docs/version-withSlugs/**/*.{md,mdx}", - "versioned_docs/version-withSlugs/**/_category_.{json,yml,yaml}", - ] - `); + expect(matchPattern).toMatchSnapshot(); expect(isMatch('docs/hello.md', matchPattern)).toEqual(true); expect(isMatch('docs/hello.mdx', matchPattern)).toEqual(true); expect(isMatch('docs/foo/bar.md', matchPattern)).toEqual(true); @@ -449,7 +430,7 @@ describe('versioned website', () => { expect(isMatch('super/docs/hello.md', matchPattern)).toEqual(false); }); - test('content', async () => { + it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); expect(content.loadedVersions.length).toEqual(4); @@ -519,12 +500,12 @@ describe('versioned website (community)', () => { }; } - test('extendCli - docsVersion', async () => { + it('extendCli - docsVersion', async () => { const {siteDir, routeBasePath, sidebarPath, pluginId, plugin} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') - .mockImplementation(); + .mockImplementation(async () => {}); const cli = new commander.Command(); // @ts-expect-error: in actual usage, we pass the static commander instead // of the new command @@ -540,25 +521,14 @@ describe('versioned website (community)', () => { mock.mockRestore(); }); - test('getPathToWatch', async () => { + it('getPathToWatch', async () => { const {siteDir, plugin} = await loadSite(); const pathToWatch = plugin.getPathsToWatch!(); const matchPattern = pathToWatch.map((filepath) => posixPath(path.relative(siteDir, filepath)), ); expect(matchPattern).not.toEqual([]); - expect(matchPattern).toMatchInlineSnapshot(` - Array [ - "community_sidebars.json", - "i18n/en/docusaurus-plugin-content-docs-community/current/**/*.{md,mdx}", - "community/**/*.{md,mdx}", - "community/**/_category_.{json,yml,yaml}", - "community_versioned_sidebars/version-1.0.0-sidebars.json", - "i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0/**/*.{md,mdx}", - "community_versioned_docs/version-1.0.0/**/*.{md,mdx}", - "community_versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}", - ] - `); + expect(matchPattern).toMatchSnapshot(); expect(isMatch('community/team.md', matchPattern)).toEqual(true); expect( isMatch('community_versioned_docs/version-1.0.0/team.md', matchPattern), @@ -581,7 +551,7 @@ describe('versioned website (community)', () => { ).toEqual(false); }); - test('content', async () => { + it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); expect(content.loadedVersions.length).toEqual(2); @@ -625,20 +595,20 @@ describe('site with doc label', () => { return {content}; } - test('label in sidebar.json is used', async () => { + it('label in sidebar.json is used', async () => { const {content} = await loadSite(); const loadedVersion = content.loadedVersions[0]; const sidebarProps = toSidebarsProp(loadedVersion); - expect(sidebarProps.docs[0].label).toBe('Hello One'); + expect(sidebarProps.docs[0].label).toEqual('Hello One'); }); - test('sidebar_label in doc has higher precedence over label in sidebar.json', async () => { + it('sidebar_label in doc has higher precedence over label in sidebar.json', async () => { const {content} = await loadSite(); const loadedVersion = content.loadedVersions[0]; const sidebarProps = toSidebarsProp(loadedVersion); - expect(sidebarProps.docs[1].label).toBe('Hello 2 From Doc'); + expect(sidebarProps.docs[1].label).toEqual('Hello 2 From Doc'); }); }); @@ -662,14 +632,14 @@ describe('site with full autogenerated sidebar', () => { return {content, siteDir}; } - test('sidebar is fully autogenerated', async () => { + it('sidebar is fully autogenerated', async () => { const {content} = await loadSite(); const version = content.loadedVersions[0]; expect(version.sidebars).toMatchSnapshot(); }); - test('docs in fully generated sidebar have correct metadata', async () => { + it('docs in fully generated sidebar have correct metadata', async () => { const {content} = await loadSite(); const version = content.loadedVersions[0]; @@ -720,14 +690,14 @@ describe('site with partial autogenerated sidebars', () => { return {content, siteDir}; } - test('sidebar is partially autogenerated', async () => { + it('sidebar is partially autogenerated', async () => { const {content} = await loadSite(); const version = content.loadedVersions[0]; expect(version.sidebars).toMatchSnapshot(); }); - test('docs in partially generated sidebar have correct metadata', async () => { + it('docs in partially generated sidebar have correct metadata', async () => { const {content} = await loadSite(); const version = content.loadedVersions[0]; @@ -773,7 +743,7 @@ describe('site with partial autogenerated sidebars 2 (fix #4638)', () => { return {content, siteDir}; } - test('sidebar is partially autogenerated', async () => { + it('sidebar is partially autogenerated', async () => { const {content} = await loadSite(); const version = content.loadedVersions[0]; @@ -800,7 +770,7 @@ describe('site with custom sidebar items generator', () => { return {content, siteDir}; } - test('sidebarItemsGenerator is called with appropriate data', async () => { + it('sidebarItemsGenerator is called with appropriate data', async () => { const customSidebarItemsGeneratorMock = jest.fn( async (_arg: SidebarItemsGeneratorOptionArgs) => [], ); @@ -830,7 +800,7 @@ describe('site with custom sidebar items generator', () => { ); }); - test('sidebar is autogenerated according to a custom sidebarItemsGenerator', async () => { + it('sidebar is autogenerated according to a custom sidebarItemsGenerator', async () => { const customSidebarItemsGenerator: SidebarItemsGeneratorOption = async () => [ {type: 'doc', id: 'API/api-overview'}, @@ -843,7 +813,7 @@ describe('site with custom sidebar items generator', () => { expect(version.sidebars).toMatchSnapshot(); }); - test('sidebarItemsGenerator can wrap/enhance/sort/reverse the default sidebar generator', async () => { + it('sidebarItemsGenerator can wrap/enhance/sort/reverse the default sidebar generator', async () => { function reverseSidebarItems(items: SidebarItem[]): SidebarItem[] { const result: SidebarItem[] = items.map((item) => { if (item.type === 'category') { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts index 2ec2a16e4caf..61e27d9014bd 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts @@ -12,12 +12,12 @@ import shell from 'shelljs'; import {getFileLastUpdate} from '../lastUpdate'; -describe('lastUpdate', () => { +describe('getFileLastUpdate', () => { const existingFilePath = path.join( __dirname, '__fixtures__/simple-site/docs/hello.md', ); - test('existing test file in repository with Git timestamp', async () => { + it('existing test file in repository with Git timestamp', async () => { const lastUpdateData = await getFileLastUpdate(existingFilePath); expect(lastUpdateData).not.toBeNull(); @@ -29,7 +29,7 @@ describe('lastUpdate', () => { expect(typeof timestamp).toBe('number'); }); - test('existing test file with spaces in path', async () => { + it('existing test file with spaces in path', async () => { const filePathWithSpace = path.join( __dirname, '__fixtures__/simple-site/docs/doc with space.md', @@ -45,8 +45,10 @@ describe('lastUpdate', () => { expect(typeof timestamp).toBe('number'); }); - test('non-existing file', async () => { - const consoleMock = jest.spyOn(console, 'error').mockImplementation(); + it('non-existing file', async () => { + const consoleMock = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); const nonExistingFileName = '.nonExisting'; const nonExistingFilePath = path.join( __dirname, @@ -63,16 +65,18 @@ describe('lastUpdate', () => { consoleMock.mockRestore(); }); - test('temporary created file that has no git timestamp', async () => { + it('temporary created file that has no git timestamp', async () => { const tempFilePath = path.join(__dirname, '__fixtures__', '.temp'); await fs.writeFile(tempFilePath, 'Lorem ipsum :)'); await expect(getFileLastUpdate(tempFilePath)).resolves.toBeNull(); await fs.unlink(tempFilePath); }); - test('Git does not exist', async () => { + it('git does not exist', async () => { const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null); - const consoleMock = jest.spyOn(console, 'warn').mockImplementation(); + const consoleMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); const lastUpdateData = await getFileLastUpdate(existingFilePath); expect(lastUpdateData).toBeNull(); expect(consoleMock).toHaveBeenLastCalledWith( diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts index 6ca7081a345b..933d2d7297ca 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts @@ -69,7 +69,7 @@ describe('stripNumberPrefix', () => { return stripNumberPrefix(str, DefaultNumberPrefixParser); } - test('should strip number prefix if present', () => { + it('strips number prefix if present', () => { expect(stripNumberPrefixDefault('1-My Doc')).toEqual('My Doc'); expect(stripNumberPrefixDefault('01-My Doc')).toEqual('My Doc'); expect(stripNumberPrefixDefault('001-My Doc')).toEqual('My Doc'); @@ -111,7 +111,7 @@ describe('stripNumberPrefix', () => { ); }); - test('should not strip number prefix if pattern does not match', () => { + it('does not strip number prefix if pattern does not match', () => { IgnoredNumberPrefixPatterns.forEach((badPattern) => { expect(stripNumberPrefixDefault(badPattern)).toEqual(badPattern); }); @@ -119,7 +119,7 @@ describe('stripNumberPrefix', () => { }); describe('stripPathNumberPrefix', () => { - test('should strip number prefixes in paths', () => { + it('strips number prefixes in paths', () => { expect( stripPathNumberPrefixes( '0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3', @@ -128,7 +128,7 @@ describe('stripPathNumberPrefix', () => { ).toEqual('MyRootFolder0/MySubFolder1/MyDeepFolder2/MyDoc3'); }); - test('should strip number prefixes in paths with custom parser', () => { + it('strips number prefixes in paths with custom parser', () => { function stripPathNumberPrefixCustom(str: string) { return { filename: str.substring(1, str.length), @@ -141,7 +141,7 @@ describe('stripPathNumberPrefix', () => { ).toEqual('aaa/bbb/ccc'); }); - test('should strip number prefixes in paths with disabled parser', () => { + it('does not strip number prefixes in paths with disabled parser', () => { expect( stripPathNumberPrefixes( '0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3', @@ -152,7 +152,7 @@ describe('stripPathNumberPrefix', () => { }); describe('DefaultNumberPrefixParser', () => { - test('should extract number prefix if present', () => { + it('extracts number prefix if present', () => { expect(DefaultNumberPrefixParser('0-My Doc')).toEqual({ filename: 'My Doc', numberPrefix: 0, @@ -188,7 +188,7 @@ describe('DefaultNumberPrefixParser', () => { }); }); - test('should not extract number prefix if pattern does not match', () => { + it('does not extract number prefix if pattern does not match', () => { IgnoredNumberPrefixPatterns.forEach((badPattern) => { expect(DefaultNumberPrefixParser(badPattern)).toEqual({ filename: badPattern, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 95fb65e38c9f..3c39f1b6de23 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -30,13 +30,13 @@ function testValidateOptions(options: Partial) { } describe('normalizeDocsPluginOptions', () => { - test('should return default options for undefined user options', async () => { + it('returns default options for undefined user options', async () => { const {value, error} = await OptionsSchema.validate({}); expect(value).toEqual(DEFAULT_OPTIONS); expect(error).toBe(undefined); }); - test('should accept correctly defined user options', async () => { + it('accepts correctly defined user options', async () => { const userOptions = { path: 'my-docs', // Path to data on filesystem, relative to site dir. routeBasePath: 'my-docs', // URL Route. @@ -82,7 +82,7 @@ describe('normalizeDocsPluginOptions', () => { expect(error).toBe(undefined); }); - test('should accept correctly defined remark and rehype plugin options', async () => { + it('accepts correctly defined remark and rehype plugin options', async () => { const userOptions = { ...DEFAULT_OPTIONS, beforeDefaultRemarkPlugins: [], @@ -98,7 +98,7 @@ describe('normalizeDocsPluginOptions', () => { expect(error).toBe(undefined); }); - test('should accept admonitions false', async () => { + it('accepts admonitions false', async () => { const admonitionsFalse = { ...DEFAULT_OPTIONS, admonitions: false, @@ -108,7 +108,7 @@ describe('normalizeDocsPluginOptions', () => { expect(error).toBe(undefined); }); - test('should accept numberPrefixParser function', () => { + it('accepts numberPrefixParser function', () => { function customNumberPrefixParser() {} expect( normalizePluginOptions(OptionsSchema, { @@ -122,7 +122,7 @@ describe('normalizeDocsPluginOptions', () => { }); }); - test('should accept numberPrefixParser false', () => { + it('accepts numberPrefixParser false', () => { expect( normalizePluginOptions(OptionsSchema, { ...DEFAULT_OPTIONS, @@ -135,7 +135,7 @@ describe('normalizeDocsPluginOptions', () => { }); }); - test('should accept numberPrefixParser true', () => { + it('accepts numberPrefixParser true', () => { expect( normalizePluginOptions(OptionsSchema, { ...DEFAULT_OPTIONS, @@ -148,7 +148,7 @@ describe('normalizeDocsPluginOptions', () => { }); }); - test('should reject admonitions true', async () => { + it('rejects admonitions true', async () => { const admonitionsTrue = { ...DEFAULT_OPTIONS, admonitions: true, @@ -159,7 +159,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject invalid remark plugin options', () => { + it('rejects invalid remark plugin options', () => { expect(() => { normalizePluginOptions(OptionsSchema, { remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]], @@ -169,7 +169,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject invalid rehype plugin options', () => { + it('rejects invalid rehype plugin options', () => { expect(() => { normalizePluginOptions(OptionsSchema, { rehypePlugins: [ @@ -185,7 +185,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject bad path inputs', () => { + it('rejects bad path inputs', () => { expect(() => { normalizePluginOptions(OptionsSchema, { path: 2, @@ -193,7 +193,7 @@ describe('normalizeDocsPluginOptions', () => { }).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`); }); - test('should reject bad include inputs', () => { + it('rejects bad include inputs', () => { expect(() => { normalizePluginOptions(OptionsSchema, { include: '**/*.{md,mdx}', @@ -201,7 +201,7 @@ describe('normalizeDocsPluginOptions', () => { }).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`); }); - test('should reject bad showLastUpdateTime inputs', () => { + it('rejects bad showLastUpdateTime inputs', () => { expect(() => { normalizePluginOptions(OptionsSchema, { showLastUpdateTime: 'true', @@ -211,7 +211,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject bad remarkPlugins input', () => { + it('rejects bad remarkPlugins input', () => { expect(() => { normalizePluginOptions(OptionsSchema, { remarkPlugins: 'remark-math', @@ -221,7 +221,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject bad lastVersion', () => { + it('rejects bad lastVersion', () => { expect(() => { normalizePluginOptions(OptionsSchema, { lastVersion: false, @@ -231,7 +231,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should reject bad versions', () => { + it('rejects bad versions', () => { expect(() => { normalizePluginOptions(OptionsSchema, { versions: { @@ -249,7 +249,7 @@ describe('normalizeDocsPluginOptions', () => { ); }); - test('should handle sidebarCollapsed option inconsistencies', () => { + it('handles sidebarCollapsed option inconsistencies', () => { expect( testValidateOptions({ ...DEFAULT_OPTIONS, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts index 8a32f9d2463d..508913d6dd13 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts @@ -14,7 +14,7 @@ describe('toTagDocListProp', () => { const allTagsPath = '/all/tags'; - test('should work', () => { + it('works', () => { const tag: Tag = { name: 'tag1', permalink: '/tag1', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts index 04f2a93f3cd8..e015d7260c8a 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts @@ -8,7 +8,7 @@ import getSlug from '../slug'; describe('getSlug', () => { - test('should default to dirname/id', () => { + it('defaults to dirname/id', () => { expect( getSlug({ baseID: 'doc', @@ -25,7 +25,7 @@ describe('getSlug', () => { ).toEqual('/dir/subdir/doc'); }); - test('should handle conventional doc indexes', () => { + it('handles conventional doc indexes', () => { expect( getSlug({ baseID: 'doc', @@ -70,7 +70,7 @@ describe('getSlug', () => { ).toEqual('/dir/subdir/'); }); - test('should ignore conventional doc index when explicit slug front matter is provided', () => { + it('ignores conventional doc index when explicit slug front matter is provided', () => { expect( getSlug({ baseID: 'doc', @@ -81,7 +81,7 @@ describe('getSlug', () => { ).toEqual('/my/frontMatterSlug'); }); - test('can strip dir number prefixes', () => { + it('can strip dir number prefixes', () => { expect( getSlug({ baseID: 'doc', @@ -101,7 +101,7 @@ describe('getSlug', () => { }); // See https://github.com/facebook/docusaurus/issues/3223 - test('should handle special chars in doc path', () => { + it('handles special chars in doc path', () => { expect( getSlug({ baseID: 'my dôc', @@ -111,7 +111,7 @@ describe('getSlug', () => { ).toEqual('/dir with spâce/hey $hello/my dôc'); }); - test('should handle current dir', () => { + it('handles current dir', () => { expect( getSlug({baseID: 'doc', source: '@site/docs/doc.md', sourceDirName: '.'}), ).toEqual('/doc'); @@ -120,7 +120,7 @@ describe('getSlug', () => { ).toEqual('/doc'); }); - test('should resolve absolute slug front matter', () => { + it('resolves absolute slug front matter', () => { expect( getSlug({ baseID: 'any', @@ -147,7 +147,7 @@ describe('getSlug', () => { ).toEqual('/abc/def'); }); - test('should resolve relative slug front matter', () => { + it('resolves relative slug front matter', () => { expect( getSlug({ baseID: 'any', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index 0c70c715c55f..b4ca8cf72b75 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -142,20 +142,20 @@ function getSampleTranslationFilesTranslated() { } describe('getLoadedContentTranslationFiles', () => { - test('should return translation files matching snapshot', async () => { + it('returns translation files', async () => { expect(getSampleTranslationFiles()).toMatchSnapshot(); }); }); describe('translateLoadedContent', () => { - test('should not translate anything if translation files are untranslated', () => { + it('does not translate anything if translation files are untranslated', () => { const translationFiles = getSampleTranslationFiles(); expect( translateLoadedContent(SampleLoadedContent, translationFiles), ).toEqual(SampleLoadedContent); }); - test('should return translated loaded content matching snapshot', () => { + it('returns translated loaded content', () => { const translationFiles = getSampleTranslationFilesTranslated(); expect( translateLoadedContent(SampleLoadedContent, translationFiles), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index aed0e9ec2591..1da8d275149b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -27,7 +27,7 @@ const DefaultI18N: I18n = { }; describe('version paths', () => { - test('getVersionsFilePath', () => { + it('getVersionsFilePath', () => { expect(getVersionsFilePath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versions.json`, ); @@ -36,7 +36,7 @@ describe('version paths', () => { ); }); - test('getVersionedDocsDirPath', () => { + it('getVersionedDocsDirPath', () => { expect(getVersionedDocsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versioned_docs`, ); @@ -45,7 +45,7 @@ describe('version paths', () => { ); }); - test('getVersionedSidebarsDirPath', () => { + it('getVersionedSidebarsDirPath', () => { expect(getVersionedSidebarsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versioned_sidebars`, ); @@ -90,7 +90,7 @@ describe('simple site', () => { return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; } - test('readVersionsMetadata simple site', async () => { + it('readVersionsMetadata simple site', async () => { const {defaultOptions, defaultContext, vCurrent} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -101,7 +101,7 @@ describe('simple site', () => { expect(versionsMetadata).toEqual([vCurrent]); }); - test('readVersionsMetadata simple site with base url', async () => { + it('readVersionsMetadata simple site with base url', async () => { const {defaultOptions, defaultContext, vCurrent} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -121,7 +121,7 @@ describe('simple site', () => { ]); }); - test('readVersionsMetadata simple site with current version config', async () => { + it('readVersionsMetadata simple site with current version config', async () => { const {defaultOptions, defaultContext, vCurrent} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -154,7 +154,7 @@ describe('simple site', () => { ]); }); - test('readVersionsMetadata simple site with unknown lastVersion should throw', async () => { + it('readVersionsMetadata simple site with unknown lastVersion should throw', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -167,7 +167,7 @@ describe('simple site', () => { ); }); - test('readVersionsMetadata simple site with unknown version configurations should throw', async () => { + it('readVersionsMetadata simple site with unknown version configurations should throw', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -187,7 +187,7 @@ describe('simple site', () => { ); }); - test('readVersionsMetadata simple site with disableVersioning while single version should throw', async () => { + it('readVersionsMetadata simple site with disableVersioning while single version should throw', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -200,7 +200,7 @@ describe('simple site', () => { ); }); - test('readVersionsMetadata simple site without including current version should throw', async () => { + it('readVersionsMetadata simple site without including current version should throw', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -325,7 +325,7 @@ describe('versioned site, pluginId=default', () => { }; } - test('readVersionsMetadata versioned site', async () => { + it('readVersionsMetadata versioned site', async () => { const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = await loadSite(); @@ -337,7 +337,7 @@ describe('versioned site, pluginId=default', () => { expect(versionsMetadata).toEqual([vCurrent, v101, v100, vwithSlugs]); }); - test('readVersionsMetadata versioned site with includeCurrentVersion=false', async () => { + it('readVersionsMetadata versioned site with includeCurrentVersion=false', async () => { const {defaultOptions, defaultContext, v101, v100, vwithSlugs} = await loadSite(); @@ -354,7 +354,7 @@ describe('versioned site, pluginId=default', () => { ]); }); - test('readVersionsMetadata versioned site with version options', async () => { + it('readVersionsMetadata versioned site with version options', async () => { const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = await loadSite(); @@ -408,7 +408,7 @@ describe('versioned site, pluginId=default', () => { ]); }); - test('readVersionsMetadata versioned site with editUrl', async () => { + it('readVersionsMetadata versioned site with editUrl', async () => { const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = await loadSite(); @@ -452,7 +452,7 @@ describe('versioned site, pluginId=default', () => { ]); }); - test('readVersionsMetadata versioned site with editUrl and editCurrentVersion=true', async () => { + it('readVersionsMetadata versioned site with editUrl and editCurrentVersion=true', async () => { const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = await loadSite(); @@ -497,7 +497,7 @@ describe('versioned site, pluginId=default', () => { ]); }); - test('readVersionsMetadata versioned site with onlyIncludeVersions option', async () => { + it('readVersionsMetadata versioned site with onlyIncludeVersions option', async () => { const {defaultOptions, defaultContext, v101, vwithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -512,7 +512,7 @@ describe('versioned site, pluginId=default', () => { expect(versionsMetadata).toEqual([v101, vwithSlugs]); }); - test('readVersionsMetadata versioned site with disableVersioning', async () => { + it('readVersionsMetadata versioned site with disableVersioning', async () => { const {defaultOptions, defaultContext, vCurrent} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -533,7 +533,7 @@ describe('versioned site, pluginId=default', () => { ]); }); - test('readVersionsMetadata versioned site with all versions disabled', async () => { + it('readVersionsMetadata versioned site with all versions disabled', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -550,7 +550,7 @@ describe('versioned site, pluginId=default', () => { ); }); - test('readVersionsMetadata versioned site with empty onlyIncludeVersions', async () => { + it('readVersionsMetadata versioned site with empty onlyIncludeVersions', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -566,7 +566,7 @@ describe('versioned site, pluginId=default', () => { ); }); - test('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', async () => { + it('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -582,7 +582,7 @@ describe('versioned site, pluginId=default', () => { ); }); - test('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', async () => { + it('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( @@ -599,7 +599,7 @@ describe('versioned site, pluginId=default', () => { ); }); - test('readVersionsMetadata versioned site with invalid versions.json file', async () => { + it('readVersionsMetadata versioned site with invalid versions.json file', async () => { const {defaultOptions, defaultContext} = await loadSite(); const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => ({ @@ -681,7 +681,7 @@ describe('versioned site, pluginId=community', () => { return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100}; } - test('readVersionsMetadata versioned site (community)', async () => { + it('readVersionsMetadata versioned site (community)', async () => { const {defaultOptions, defaultContext, vCurrent, v100} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -692,7 +692,7 @@ describe('versioned site, pluginId=community', () => { expect(versionsMetadata).toEqual([vCurrent, v100]); }); - test('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', async () => { + it('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', async () => { const {defaultOptions, defaultContext, v100} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -706,7 +706,7 @@ describe('versioned site, pluginId=community', () => { ]); }); - test('readVersionsMetadata versioned site (community) with disableVersioning', async () => { + it('readVersionsMetadata versioned site (community) with disableVersioning', async () => { const {defaultOptions, defaultContext, vCurrent} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -727,7 +727,7 @@ describe('versioned site, pluginId=community', () => { ]); }); - test('readVersionsMetadata versioned site (community) with all versions disabled', async () => { + it('readVersionsMetadata versioned site (community) with all versions disabled', async () => { const {defaultOptions, defaultContext} = await loadSite(); await expect( diff --git a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts index d80710307819..45323322fbd4 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts @@ -20,7 +20,7 @@ import type { import _ from 'lodash'; describe('docsClientUtils', () => { - test('getActivePlugin', () => { + it('getActivePlugin', () => { const data: Record = { pluginIosId: { path: '/ios', @@ -91,7 +91,7 @@ describe('docsClientUtils', () => { ).toEqual('pluginAndroidId'); }); - test('getLatestVersion', () => { + it('getLatestVersion', () => { const versions: GlobalVersion[] = [ { name: 'version1', @@ -127,7 +127,7 @@ describe('docsClientUtils', () => { ).toEqual(versions[1]); }); - test('getActiveVersion', () => { + it('getActiveVersion', () => { const data: GlobalPluginData = { path: 'docs', versions: [ @@ -175,7 +175,7 @@ describe('docsClientUtils', () => { ); }); - test('getActiveDocContext', () => { + it('getActiveDocContext', () => { const versionNext: GlobalVersion = { name: 'next', label: 'next', @@ -304,7 +304,7 @@ describe('docsClientUtils', () => { }); }); - test('getDocVersionSuggestions', () => { + it('getDocVersionSuggestions', () => { const versionNext: GlobalVersion = { name: 'next', label: 'next', diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__snapshots__/linkify.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__snapshots__/linkify.test.ts.snap index 95982ca782e5..39d7880d48a1 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__snapshots__/linkify.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__snapshots__/linkify.test.ts.snap @@ -1,6 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`transform nothing 1`] = ` +exports[`linkify transforms absolute links in versioned docs 1`] = ` +"### Existing Docs + +- [doc1](/docs/1.0.0/subdir/doc1) + +### With hash + +- [doc2](/docs/1.0.0/doc2#existing-docs) +" +`; + +exports[`linkify transforms nothing with no links 1`] = ` "# Don't transform any link here ![image1](assets/image1.png) @@ -17,41 +28,7 @@ exports[`transform nothing 1`] = ` " `; -exports[`transform relative links 1`] = ` -"### Relative linking - -- [doc1](/docs/doc2) -" -`; - -exports[`transform to correct links 1`] = ` -"### Existing Docs - -- [doc1](/docs/doc1) -- [doc2](/docs/doc2) -- [doc3](/docs/subdir/doc3) - -## Repeating Docs - -- [doc1](/docs/doc1) -- [doc2](/docs/doc2) - -- [doc-localized](/fr/doc-localized) -" -`; - -exports[`transforms absolute links in versioned docs 1`] = ` -"### Existing Docs - -- [doc1](/docs/1.0.0/subdir/doc1) - -### With hash - -- [doc2](/docs/1.0.0/doc2#existing-docs) -" -`; - -exports[`transforms reference links 1`] = ` +exports[`linkify transforms reference links 1`] = ` "### Existing Docs - [doc1][doc1] @@ -74,9 +51,32 @@ exports[`transforms reference links 1`] = ` " `; -exports[`transforms relative links in versioned docs 1`] = ` +exports[`linkify transforms relative links 1`] = ` +"### Relative linking + +- [doc1](/docs/doc2) +" +`; + +exports[`linkify transforms relative links in versioned docs 1`] = ` "### Relative linking - [doc1](/docs/1.0.0/doc2) " `; + +exports[`linkify transforms to correct links 1`] = ` +"### Existing Docs + +- [doc1](/docs/doc1) +- [doc2](/docs/doc2) +- [doc3](/docs/subdir/doc3) + +## Repeating Docs + +- [doc1](/docs/doc1) +- [doc2](/docs/doc2) + +- [doc-localized](/fr/doc-localized) +" +`; diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index 56ed2072fad0..4ee10a4acd56 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -100,95 +100,97 @@ const transform = async ( return [content, transformedContent]; }; -test('transform nothing', async () => { - const doc1 = path.join(versionCurrent.contentPath, 'doc1.md'); - const [content, transformedContent] = await transform(doc1); - expect(transformedContent).toMatchSnapshot(); - expect(content).toEqual(transformedContent); -}); +describe('linkify', () => { + it('transforms nothing with no links', async () => { + const doc1 = path.join(versionCurrent.contentPath, 'doc1.md'); + const [content, transformedContent] = await transform(doc1); + expect(transformedContent).toMatchSnapshot(); + expect(content).toEqual(transformedContent); + }); -test('transform to correct links', async () => { - const doc2 = path.join(versionCurrent.contentPath, 'doc2.md'); - const [content, transformedContent] = await transform(doc2); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain('](/docs/doc1'); - expect(transformedContent).toContain('](/docs/doc2'); - expect(transformedContent).toContain('](/docs/subdir/doc3'); - expect(transformedContent).toContain('](/fr/doc-localized'); - expect(transformedContent).not.toContain('](doc1.md)'); - expect(transformedContent).not.toContain('](./doc2.md)'); - expect(transformedContent).not.toContain('](subdir/doc3.md)'); - expect(transformedContent).not.toContain('](/doc-localized'); - expect(content).not.toEqual(transformedContent); -}); + it('transforms to correct links', async () => { + const doc2 = path.join(versionCurrent.contentPath, 'doc2.md'); + const [content, transformedContent] = await transform(doc2); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain('](/docs/doc1'); + expect(transformedContent).toContain('](/docs/doc2'); + expect(transformedContent).toContain('](/docs/subdir/doc3'); + expect(transformedContent).toContain('](/fr/doc-localized'); + expect(transformedContent).not.toContain('](doc1.md)'); + expect(transformedContent).not.toContain('](./doc2.md)'); + expect(transformedContent).not.toContain('](subdir/doc3.md)'); + expect(transformedContent).not.toContain('](/doc-localized'); + expect(content).not.toEqual(transformedContent); + }); -test('transform relative links', async () => { - const doc3 = path.join(versionCurrent.contentPath, 'subdir', 'doc3.md'); + it('transforms relative links', async () => { + const doc3 = path.join(versionCurrent.contentPath, 'subdir', 'doc3.md'); - const [content, transformedContent] = await transform(doc3); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain('](/docs/doc2'); - expect(transformedContent).not.toContain('](../doc2.md)'); - expect(content).not.toEqual(transformedContent); -}); + const [content, transformedContent] = await transform(doc3); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain('](/docs/doc2'); + expect(transformedContent).not.toContain('](../doc2.md)'); + expect(content).not.toEqual(transformedContent); + }); -test('transforms reference links', async () => { - const doc4 = path.join(versionCurrent.contentPath, 'doc4.md'); - const [content, transformedContent] = await transform(doc4); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain('[doc1]: /docs/doc1'); - expect(transformedContent).toContain('[doc2]: /docs/doc2'); - expect(transformedContent).not.toContain('[doc1]: doc1.md'); - expect(transformedContent).not.toContain('[doc2]: ./doc2.md'); - expect(content).not.toEqual(transformedContent); -}); + it('transforms reference links', async () => { + const doc4 = path.join(versionCurrent.contentPath, 'doc4.md'); + const [content, transformedContent] = await transform(doc4); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain('[doc1]: /docs/doc1'); + expect(transformedContent).toContain('[doc2]: /docs/doc2'); + expect(transformedContent).not.toContain('[doc1]: doc1.md'); + expect(transformedContent).not.toContain('[doc2]: ./doc2.md'); + expect(content).not.toEqual(transformedContent); + }); -test('report broken markdown links', async () => { - const doc5 = path.join(versionCurrent.contentPath, 'doc5.md'); - const onBrokenMarkdownLink = jest.fn(); - const [content, transformedContent] = await transform(doc5, { - onBrokenMarkdownLink, + it('reports broken markdown links', async () => { + const doc5 = path.join(versionCurrent.contentPath, 'doc5.md'); + const onBrokenMarkdownLink = jest.fn(); + const [content, transformedContent] = await transform(doc5, { + onBrokenMarkdownLink, + }); + expect(transformedContent).toEqual(content); + expect(onBrokenMarkdownLink).toHaveBeenCalledTimes(4); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { + filePath: doc5, + link: 'docNotExist1.md', + contentPaths: versionCurrent, + } as BrokenMarkdownLink); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { + filePath: doc5, + link: './docNotExist2.mdx', + contentPaths: versionCurrent, + } as BrokenMarkdownLink); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(3, { + filePath: doc5, + link: '../docNotExist3.mdx', + contentPaths: versionCurrent, + } as BrokenMarkdownLink); + expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(4, { + filePath: doc5, + link: './subdir/docNotExist4.md', + contentPaths: versionCurrent, + } as BrokenMarkdownLink); }); - expect(transformedContent).toEqual(content); - expect(onBrokenMarkdownLink).toHaveBeenCalledTimes(4); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(1, { - filePath: doc5, - link: 'docNotExist1.md', - contentPaths: versionCurrent, - } as BrokenMarkdownLink); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { - filePath: doc5, - link: './docNotExist2.mdx', - contentPaths: versionCurrent, - } as BrokenMarkdownLink); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(3, { - filePath: doc5, - link: '../docNotExist3.mdx', - contentPaths: versionCurrent, - } as BrokenMarkdownLink); - expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(4, { - filePath: doc5, - link: './subdir/docNotExist4.md', - contentPaths: versionCurrent, - } as BrokenMarkdownLink); -}); -test('transforms absolute links in versioned docs', async () => { - const doc2 = path.join(version100.contentPath, 'doc2.md'); - const [content, transformedContent] = await transform(doc2); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain('](/docs/1.0.0/subdir/doc1'); - expect(transformedContent).toContain('](/docs/1.0.0/doc2#existing-docs'); - expect(transformedContent).not.toContain('](subdir/doc1.md)'); - expect(transformedContent).not.toContain('](doc2.md#existing-docs)'); - expect(content).not.toEqual(transformedContent); -}); + it('transforms absolute links in versioned docs', async () => { + const doc2 = path.join(version100.contentPath, 'doc2.md'); + const [content, transformedContent] = await transform(doc2); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain('](/docs/1.0.0/subdir/doc1'); + expect(transformedContent).toContain('](/docs/1.0.0/doc2#existing-docs'); + expect(transformedContent).not.toContain('](subdir/doc1.md)'); + expect(transformedContent).not.toContain('](doc2.md#existing-docs)'); + expect(content).not.toEqual(transformedContent); + }); -test('transforms relative links in versioned docs', async () => { - const doc1 = path.join(version100.contentPath, 'subdir', 'doc1.md'); - const [content, transformedContent] = await transform(doc1); - expect(transformedContent).toMatchSnapshot(); - expect(transformedContent).toContain('](/docs/1.0.0/doc2'); - expect(transformedContent).not.toContain('](../doc2.md)'); - expect(content).not.toEqual(transformedContent); + it('transforms relative links in versioned docs', async () => { + const doc1 = path.join(version100.contentPath, 'subdir', 'doc1.md'); + const [content, transformedContent] = await transform(doc1); + expect(transformedContent).toMatchSnapshot(); + expect(transformedContent).toContain('](/docs/1.0.0/doc2'); + expect(transformedContent).not.toContain('](../doc2.md)'); + expect(content).not.toEqual(transformedContent); + }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap new file mode 100644 index 000000000000..6e204eccd703 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`postProcess corrects collapsed state inconsistencies 1`] = ` +Object { + "sidebar": Array [ + Object { + "collapsed": false, + "collapsible": false, + "items": Array [ + Object { + "id": "foo", + "type": "doc", + }, + ], + "label": "Category", + "link": undefined, + "type": "category", + }, + ], +} +`; + +exports[`postProcess corrects collapsed state inconsistencies 2`] = ` +Object { + "sidebar": Array [ + Object { + "collapsed": false, + "collapsible": false, + "items": Array [ + Object { + "id": "foo", + "type": "doc", + }, + ], + "label": "Category", + "link": undefined, + "type": "category", + }, + ], +} +`; + +exports[`postProcess corrects collapsed state inconsistencies 3`] = ` +Object { + "sidebar": Array [ + Object { + "collapsed": false, + "collapsible": false, + "items": Array [ + Object { + "id": "foo", + "type": "doc", + }, + ], + "label": "Category", + "link": undefined, + "type": "category", + }, + ], +} +`; + +exports[`postProcess transforms category without subitems 1`] = ` +Object { + "sidebar": Array [ + Object { + "href": "version/generated/permalink", + "label": "Category", + "type": "link", + }, + Object { + "id": "doc ID", + "label": "Category 2", + "type": "doc", + }, + ], +} +`; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts index 5491b18e67de..3b383756f2fb 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts @@ -36,7 +36,7 @@ describe('DefaultSidebarItemsGenerator', () => { }); } - test('generates empty sidebar slice when no docs and emit a warning', async () => { + it('generates empty sidebar slice when no docs and emit a warning', async () => { const consoleWarn = jest.spyOn(console, 'warn'); const sidebarSlice = await testDefaultSidebarItemsGenerator({ docs: [], @@ -49,7 +49,7 @@ describe('DefaultSidebarItemsGenerator', () => { ); }); - test('generates simple flat sidebar', async () => { + it('generates simple flat sidebar', async () => { const sidebarSlice = await DefaultSidebarItemsGenerator({ numberPrefixParser: DefaultNumberPrefixParser, item: { @@ -108,7 +108,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toMatchSnapshot(); }); - test('generates complex nested sidebar', async () => { + it('generates complex nested sidebar', async () => { const sidebarSlice = await DefaultSidebarItemsGenerator({ numberPrefixParser: DefaultNumberPrefixParser, isCategoryIndex, @@ -212,7 +212,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toMatchSnapshot(); }); - test('generates subfolder sidebar', async () => { + it('generates subfolder sidebar', async () => { // Ensure that category metadata file is correctly read // fix edge case found in https://github.com/facebook/docusaurus/issues/4638 const sidebarSlice = await DefaultSidebarItemsGenerator({ @@ -308,7 +308,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toMatchSnapshot(); }); - test('uses explicit link over the index/readme.{md,mdx} naming convention', async () => { + it('uses explicit link over the index/readme.{md,mdx} naming convention', async () => { const sidebarSlice = await DefaultSidebarItemsGenerator({ numberPrefixParser: DefaultNumberPrefixParser, item: { @@ -379,7 +379,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toMatchSnapshot(); }); - test('respects custom isCategoryIndex', async () => { + it('respects custom isCategoryIndex', async () => { const sidebarSlice = await DefaultSidebarItemsGenerator({ numberPrefixParser: DefaultNumberPrefixParser, isCategoryIndex({fileName, directories}) { @@ -462,7 +462,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toMatchSnapshot(); }); - test('throws for unknown index link', async () => { + it('throws for unknown index link', async () => { const generateSidebar = () => DefaultSidebarItemsGenerator({ numberPrefixParser: DefaultNumberPrefixParser, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts index ad30c2177cec..89fc1696cb3c 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import path from 'path'; import {loadSidebars, DisabledSidebars} from '../index'; import type {SidebarProcessorParams} from '../types'; @@ -30,19 +31,19 @@ describe('loadSidebars', () => { categoryLabelSlugger: null, sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, }; - test('sidebars with known sidebar item type', async () => { + it('sidebars with known sidebar item type', async () => { const sidebarPath = path.join(fixtureDir, 'sidebars.json'); const result = await loadSidebars(sidebarPath, params); expect(result).toMatchSnapshot(); }); - test('sidebars with deep level of category', async () => { + it('sidebars with deep level of category', async () => { const sidebarPath = path.join(fixtureDir, 'sidebars-category.js'); const result = await loadSidebars(sidebarPath, params); expect(result).toMatchSnapshot(); }); - test('sidebars shorthand and longform lead to exact same sidebar', async () => { + it('sidebars shorthand and longform lead to exact same sidebar', async () => { const sidebarPath1 = path.join(fixtureDir, 'sidebars-category.js'); const sidebarPath2 = path.join( fixtureDir, @@ -53,7 +54,7 @@ describe('loadSidebars', () => { expect(sidebar1).toEqual(sidebar2); }); - test('sidebars with category but category.items is not an array', async () => { + it('sidebars with category but category.items is not an array', async () => { const sidebarPath = path.join( fixtureDir, 'sidebars-category-wrong-items.json', @@ -65,7 +66,7 @@ describe('loadSidebars', () => { ); }); - test('sidebars with first level not a category', async () => { + it('sidebars with first level not a category', async () => { const sidebarPath = path.join( fixtureDir, 'sidebars-first-level-not-category.js', @@ -74,35 +75,35 @@ describe('loadSidebars', () => { expect(result).toMatchSnapshot(); }); - test('sidebars link', async () => { + it('sidebars link', async () => { const sidebarPath = path.join(fixtureDir, 'sidebars-link.json'); const result = await loadSidebars(sidebarPath, params); expect(result).toMatchSnapshot(); }); - test('unexisting path', async () => { + it('unexisting path', async () => { await expect(loadSidebars('badpath', params)).resolves.toEqual( DisabledSidebars, ); }); - test('undefined path', async () => { + it('undefined path', async () => { await expect(loadSidebars(undefined, params)).resolves.toMatchSnapshot(); }); - test('literal false path', async () => { + it('literal false path', async () => { await expect(loadSidebars(false, params)).resolves.toEqual( DisabledSidebars, ); }); - test('sidebars with category.collapsed property', async () => { + it('sidebars with category.collapsed property', async () => { const sidebarPath = path.join(fixtureDir, 'sidebars-collapsed.json'); const result = await loadSidebars(sidebarPath, params); expect(result).toMatchSnapshot(); }); - test('sidebars with category.collapsed property at first level', async () => { + it('sidebars with category.collapsed property at first level', async () => { const sidebarPath = path.join( fixtureDir, 'sidebars-collapsed-first-level.json', @@ -111,7 +112,7 @@ describe('loadSidebars', () => { expect(result).toMatchSnapshot(); }); - test('duplicate category metadata files', async () => { + it('duplicate category metadata files', async () => { const sidebarPath = path.join( fixtureDir, 'sidebars-collapsed-first-level.json', diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts index fbb00ec825ae..3dcf930be0e3 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts @@ -8,7 +8,7 @@ import {normalizeSidebars} from '../normalization'; describe('normalization', () => { - test('normalizes shorthands', () => { + it('normalizes shorthands', () => { expect( normalizeSidebars({ sidebar: { @@ -37,7 +37,7 @@ describe('normalization', () => { }), ).toMatchSnapshot(); }); - test('rejects some invalid cases', () => { + it('rejects some invalid cases', () => { expect(() => normalizeSidebars({ sidebar: { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts index 699c69ae6a75..19cd6495831f 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts @@ -8,7 +8,7 @@ import {postProcessSidebars} from '../postProcessor'; describe('postProcess', () => { - test('transforms category without subitems', () => { + it('transforms category without subitems', () => { const processedSidebar = postProcessSidebars( { sidebar: [ @@ -38,22 +38,7 @@ describe('postProcess', () => { }, ); - expect(processedSidebar).toMatchInlineSnapshot(` - Object { - "sidebar": Array [ - Object { - "href": "version/generated/permalink", - "label": "Category", - "type": "link", - }, - Object { - "id": "doc ID", - "label": "Category 2", - "type": "doc", - }, - ], - } - `); + expect(processedSidebar).toMatchSnapshot(); expect(() => { postProcessSidebars( @@ -76,7 +61,7 @@ describe('postProcess', () => { ); }); - test('corrects collapsed state inconsistencies', () => { + it('corrects collapsed state inconsistencies', () => { expect( postProcessSidebars( { @@ -96,25 +81,7 @@ describe('postProcess', () => { version: {versionPath: 'version'}, }, ), - ).toMatchInlineSnapshot(` - Object { - "sidebar": Array [ - Object { - "collapsed": false, - "collapsible": false, - "items": Array [ - Object { - "id": "foo", - "type": "doc", - }, - ], - "label": "Category", - "link": undefined, - "type": "category", - }, - ], - } - `); + ).toMatchSnapshot(); expect( postProcessSidebars( @@ -134,25 +101,7 @@ describe('postProcess', () => { version: {versionPath: 'version'}, }, ), - ).toMatchInlineSnapshot(` - Object { - "sidebar": Array [ - Object { - "collapsed": false, - "collapsible": false, - "items": Array [ - Object { - "id": "foo", - "type": "doc", - }, - ], - "label": "Category", - "link": undefined, - "type": "category", - }, - ], - } - `); + ).toMatchSnapshot(); expect( postProcessSidebars( @@ -171,24 +120,6 @@ describe('postProcess', () => { version: {versionPath: 'version'}, }, ), - ).toMatchInlineSnapshot(` - Object { - "sidebar": Array [ - Object { - "collapsed": false, - "collapsible": false, - "items": Array [ - Object { - "id": "foo", - "type": "doc", - }, - ], - "label": "Category", - "link": undefined, - "type": "category", - }, - ], - } - `); + ).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts index f5021fd8d941..15390eb4b89a 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts @@ -66,7 +66,7 @@ describe('processSidebars', () => { }); } - test('let sidebars without autogenerated items untouched', async () => { + it('leaves sidebars without autogenerated items untouched', async () => { const unprocessedSidebars: NormalizedSidebars = { someSidebar: [ {type: 'doc', id: 'doc1'}, @@ -96,7 +96,7 @@ describe('processSidebars', () => { expect(processedSidebar).toEqual(unprocessedSidebars); }); - test('replace autogenerated items by generated sidebars slices', async () => { + it('replaces autogenerated items by generated sidebars slices', async () => { const unprocessedSidebars: NormalizedSidebars = { someSidebar: [ {type: 'doc', id: 'doc1'}, @@ -199,7 +199,7 @@ describe('processSidebars', () => { } as ProcessedSidebars); }); - test('ensure generated items are normalized', async () => { + it('ensures generated items are normalized', async () => { const sidebarSliceContainingCategoryGeneratedIndex: NormalizedSidebar = [ { type: 'category', diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index 83f28e6c4621..c268103b25b7 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -131,11 +131,11 @@ describe('createSidebarsUtils', () => { getFirstLink, } = createSidebarsUtils(sidebars); - test('getFirstDocIdOfFirstSidebar', async () => { + it('getFirstDocIdOfFirstSidebar', async () => { expect(getFirstDocIdOfFirstSidebar()).toEqual('doc1'); }); - test('getSidebarNameByDocId', async () => { + it('getSidebarNameByDocId', async () => { expect(getSidebarNameByDocId('doc1')).toEqual('sidebar1'); expect(getSidebarNameByDocId('doc2')).toEqual('sidebar1'); expect(getSidebarNameByDocId('doc3')).toEqual('sidebar2'); @@ -146,7 +146,7 @@ describe('createSidebarsUtils', () => { expect(getSidebarNameByDocId('unknown_id')).toEqual(undefined); }); - test('getDocNavigation', async () => { + it('getDocNavigation', async () => { expect(getDocNavigation('doc1', 'doc1', undefined)).toEqual({ sidebarName: 'sidebar1', previous: undefined, @@ -226,7 +226,7 @@ describe('createSidebarsUtils', () => { }); }); - test('getCategoryGeneratedIndexNavigation', async () => { + it('getCategoryGeneratedIndexNavigation', async () => { expect( getCategoryGeneratedIndexNavigation('/s3-subcategory-index-permalink'), ).toMatchObject({ @@ -256,7 +256,7 @@ describe('createSidebarsUtils', () => { }); }); - test('getCategoryGeneratedIndexList', async () => { + it('getCategoryGeneratedIndexList', async () => { expect(getCategoryGeneratedIndexList()).toMatchObject([ { type: 'category', @@ -273,7 +273,7 @@ describe('createSidebarsUtils', () => { ]); }); - test('getFirstLink', () => { + it('getFirstLink', () => { expect(getFirstLink('sidebar1')).toEqual({ id: 'doc1', type: 'doc', @@ -298,7 +298,7 @@ describe('createSidebarsUtils', () => { }); describe('collectSidebarDocItems', () => { - test('can collect docs', async () => { + it('can collect docs', async () => { const sidebar: Sidebar = [ { type: 'category', @@ -354,7 +354,7 @@ describe('collectSidebarDocItems', () => { }); describe('collectSidebarCategories', () => { - test('can collect categories', async () => { + it('can collect categories', async () => { const sidebar: Sidebar = [ { type: 'category', @@ -412,7 +412,7 @@ describe('collectSidebarCategories', () => { }); describe('collectSidebarLinks', () => { - test('can collect links', async () => { + it('can collect links', async () => { const sidebar: Sidebar = [ { type: 'category', @@ -450,7 +450,7 @@ describe('collectSidebarLinks', () => { }); describe('collectSidebarsDocIds', () => { - test('can collect sidebars doc items', async () => { + it('can collect sidebars doc items', async () => { const sidebar1: Sidebar = [ { type: 'category', @@ -496,7 +496,7 @@ describe('collectSidebarsDocIds', () => { }); describe('transformSidebarItems', () => { - test('can transform sidebar items', async () => { + it('can transform sidebar items', async () => { const sidebar: Sidebar = [ { type: 'category', @@ -606,7 +606,7 @@ describe('toDocNavigationLink', () => { return data as DocMetadataBase; } - test('with no front matter', () => { + it('with no front matter', () => { expect( toDocNavigationLink( testDoc({ @@ -621,7 +621,7 @@ describe('toDocNavigationLink', () => { } as DocNavLink); }); - test('with pagination_label front matter', () => { + it('with pagination_label front matter', () => { expect( toDocNavigationLink( testDoc({ @@ -638,7 +638,7 @@ describe('toDocNavigationLink', () => { } as DocNavLink); }); - test('with sidebar_label front matter', () => { + it('with sidebar_label front matter', () => { expect( toDocNavigationLink( testDoc({ @@ -655,7 +655,7 @@ describe('toDocNavigationLink', () => { } as DocNavLink); }); - test('with pagination_label + sidebar_label front matter', () => { + it('with pagination_label + sidebar_label front matter', () => { expect( toDocNavigationLink( testDoc({ @@ -691,7 +691,7 @@ describe('toNavigationLink', () => { }), }; - test('with doc items', () => { + it('with doc items', () => { expect(toNavigationLink({type: 'doc', id: 'doc1'}, docsById)).toEqual( toDocNavigationLink(docsById.doc1), ); @@ -705,7 +705,7 @@ describe('toNavigationLink', () => { ); }); - test('with category item and doc link', () => { + it('with category item and doc link', () => { expect( toNavigationLink( { @@ -742,7 +742,7 @@ describe('toNavigationLink', () => { ); }); - test('with category item and generated-index link', () => { + it('with category item and generated-index link', () => { expect( toNavigationLink( { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts index 2088302876f5..96887b889c5b 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts @@ -9,7 +9,7 @@ import {validateSidebars, validateCategoryMetadataFile} from '../validation'; import type {SidebarsConfig, CategoryMetadataFile} from '../types'; describe('validateSidebars', () => { - test('throw for bad value', async () => { + it('throw for bad value', async () => { expect(() => validateSidebars({sidebar: [{type: 42}]})) .toThrowErrorMatchingInlineSnapshot(` "{ @@ -21,12 +21,12 @@ describe('validateSidebars', () => { `); }); - test('accept empty object', async () => { + it('accept empty object', async () => { const sidebars: SidebarsConfig = {}; validateSidebars(sidebars); }); - test('accept valid values', async () => { + it('accept valid values', async () => { const sidebars: SidebarsConfig = { sidebar1: [ {type: 'doc', id: 'doc1'}, @@ -41,17 +41,19 @@ describe('validateSidebars', () => { validateSidebars(sidebars); }); - test('sidebar category wrong label', () => { - expect(() => - validateSidebars({ - docs: [ - { - type: 'category', - label: true, - items: [{type: 'doc', id: 'doc1'}], - }, - ], - }), + it('sidebar category wrong label', () => { + expect( + () => + validateSidebars({ + docs: [ + { + type: 'category', + label: true, + items: [{type: 'doc', id: 'doc1'}], + }, + ], + }), + // eslint-disable-next-line jest/no-large-snapshots ).toThrowErrorMatchingInlineSnapshot(` "{ \\"type\\": \\"category\\", @@ -68,7 +70,7 @@ describe('validateSidebars', () => { `); }); - test('sidebars link wrong label', () => { + it('sidebars link wrong label', () => { expect(() => validateSidebars({ docs: [ @@ -90,7 +92,7 @@ describe('validateSidebars', () => { `); }); - test('sidebars link wrong href', () => { + it('sidebars link wrong href', () => { expect(() => validateSidebars({ docs: [ @@ -114,7 +116,7 @@ describe('validateSidebars', () => { `); }); - test('sidebars with unknown sidebar item type', () => { + it('sidebars with unknown sidebar item type', () => { expect(() => validateSidebars({ docs: [ @@ -133,7 +135,7 @@ describe('validateSidebars', () => { `); }); - test('sidebars category missing items', () => { + it('sidebars category missing items', () => { expect(() => validateSidebars({ docs: [ @@ -159,7 +161,7 @@ describe('validateSidebars', () => { `); }); - test('sidebars category wrong field', () => { + it('sidebars category wrong field', () => { expect(() => validateSidebars({ docs: [ @@ -188,7 +190,7 @@ describe('validateSidebars', () => { `); }); - test('sidebar category wrong items', () => { + it('sidebar category wrong items', () => { expect(() => validateSidebars({ docs: { @@ -204,7 +206,7 @@ describe('validateSidebars', () => { ).toThrowErrorMatchingInlineSnapshot(`"sidebar.forEach is not a function"`); }); - test('sidebars item doc but id is not a string', async () => { + it('sidebars item doc but id is not a string', async () => { expect(() => validateSidebars({ docs: [ @@ -226,7 +228,7 @@ describe('validateSidebars', () => { `); }); - test('HTML type requires a value', () => { + it('hTML type requires a value', () => { const sidebars: SidebarsConfig = { sidebar1: [ { @@ -246,7 +248,7 @@ describe('validateSidebars', () => { `); }); - test('HTML type accepts valid values', () => { + it('hTML type accepts valid values', () => { const sidebars: SidebarsConfig = { sidebar1: [ { @@ -264,7 +266,7 @@ describe('validateSidebars', () => { describe('validateCategoryMetadataFile', () => { // TODO add more tests - test('throw for bad value', async () => { + it('throw for bad value', async () => { expect(() => validateCategoryMetadataFile(42), ).toThrowErrorMatchingInlineSnapshot( @@ -272,12 +274,12 @@ describe('validateCategoryMetadataFile', () => { ); }); - test('accept empty object', async () => { + it('accept empty object', async () => { const content: CategoryMetadataFile = {}; expect(validateCategoryMetadataFile(content)).toEqual(content); }); - test('accept valid values', async () => { + it('accept valid values', async () => { const content: CategoryMetadataFile = { className: 'className', label: 'Category Label', @@ -294,7 +296,7 @@ describe('validateCategoryMetadataFile', () => { expect(validateCategoryMetadataFile(content)).toEqual(content); }); - test('rejects permalink', async () => { + it('rejects permalink', async () => { const content: CategoryMetadataFile = { className: 'className', label: 'Category Label', diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..bc57b3355bd0 --- /dev/null +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,105 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` +Array [ + Object { + "permalink": "/", + "source": "@site/src/pages/index.js", + "type": "jsx", + }, + Object { + "permalink": "/typescript", + "source": "@site/src/pages/typescript.tsx", + "type": "jsx", + }, + Object { + "description": "Markdown index page", + "frontMatter": Object {}, + "permalink": "/hello/", + "source": "@site/src/pages/hello/index.md", + "title": "Index", + "type": "mdx", + }, + Object { + "description": "my mdx page", + "frontMatter": Object { + "description": "my mdx page", + "title": "mdx page", + }, + "permalink": "/hello/mdxPage", + "source": "@site/src/pages/hello/mdxPage.mdx", + "title": "mdx page", + "type": "mdx", + }, + Object { + "permalink": "/hello/translatedJs", + "source": "@site/src/pages/hello/translatedJs.js", + "type": "jsx", + }, + Object { + "description": "translated markdown page", + "frontMatter": Object {}, + "permalink": "/hello/translatedMd", + "source": "@site/src/pages/hello/translatedMd.md", + "title": undefined, + "type": "mdx", + }, + Object { + "permalink": "/hello/world", + "source": "@site/src/pages/hello/world.js", + "type": "jsx", + }, +] +`; + +exports[`docusaurus-plugin-content-pages loads simple pages with french translations 1`] = ` +Array [ + Object { + "permalink": "/", + "source": "@site/src/pages/index.js", + "type": "jsx", + }, + Object { + "permalink": "/typescript", + "source": "@site/src/pages/typescript.tsx", + "type": "jsx", + }, + Object { + "description": "Markdown index page", + "frontMatter": Object {}, + "permalink": "/hello/", + "source": "@site/src/pages/hello/index.md", + "title": "Index", + "type": "mdx", + }, + Object { + "description": "my mdx page", + "frontMatter": Object { + "description": "my mdx page", + "title": "mdx page", + }, + "permalink": "/hello/mdxPage", + "source": "@site/src/pages/hello/mdxPage.mdx", + "title": "mdx page", + "type": "mdx", + }, + Object { + "permalink": "/hello/translatedJs", + "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedJs.js", + "type": "jsx", + }, + Object { + "description": "translated markdown page (fr)", + "frontMatter": Object {}, + "permalink": "/hello/translatedMd", + "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedMd.md", + "title": undefined, + "type": "mdx", + }, + Object { + "permalink": "/hello/world", + "source": "@site/src/pages/hello/world.js", + "type": "jsx", + }, +] +`; diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts index db1979436e7e..b71ffcdfad22 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts @@ -12,83 +12,23 @@ import pluginContentPages from '../index'; import {PluginOptionSchema} from '../pluginOptionSchema'; describe('docusaurus-plugin-content-pages', () => { - test('simple pages', async () => { + it('loads simple pages', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const context = await loadContext(siteDir); - const pluginPath = 'src/pages'; const plugin = await pluginContentPages( context, PluginOptionSchema.validate({ - path: pluginPath, + path: 'src/pages', }).value, ); - const pagesMetadata = await plugin.loadContent?.(); + const pagesMetadata = await plugin.loadContent!(); - expect(pagesMetadata).toEqual([ - { - type: 'jsx', - permalink: '/', - source: path.posix.join('@site', pluginPath, 'index.js'), - }, - { - type: 'jsx', - permalink: '/typescript', - source: path.posix.join('@site', pluginPath, 'typescript.tsx'), - }, - { - type: 'mdx', - permalink: '/hello/', - source: path.posix.join('@site', pluginPath, 'hello', 'index.md'), - description: 'Markdown index page', - frontMatter: {}, - title: 'Index', - }, - { - type: 'mdx', - permalink: '/hello/mdxPage', - source: path.posix.join('@site', pluginPath, 'hello', 'mdxPage.mdx'), - description: 'my mdx page', - title: 'mdx page', - frontMatter: { - description: 'my mdx page', - title: 'mdx page', - }, - }, - { - type: 'jsx', - permalink: '/hello/translatedJs', - source: path.posix.join( - '@site', - pluginPath, - 'hello', - 'translatedJs.js', - ), - }, - { - type: 'mdx', - permalink: '/hello/translatedMd', - source: path.posix.join( - '@site', - pluginPath, - 'hello', - 'translatedMd.md', - ), - description: 'translated markdown page', - frontMatter: {}, - title: undefined, - }, - { - type: 'jsx', - permalink: '/hello/world', - source: path.posix.join('@site', pluginPath, 'hello', 'world.js'), - }, - ]); + expect(pagesMetadata).toMatchSnapshot(); }); - test('simple pages with french translations', async () => { + it('loads simple pages with french translations', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const context = await loadContext(siteDir); - const pluginPath = 'src/pages'; const plugin = await pluginContentPages( { ...context, @@ -98,66 +38,11 @@ describe('docusaurus-plugin-content-pages', () => { }, }, PluginOptionSchema.validate({ - path: pluginPath, + path: 'src/pages', }).value, ); - const pagesMetadata = await plugin.loadContent?.(); - - const frTranslationsPath = path.posix.join( - '@site', - 'i18n', - 'fr', - 'docusaurus-plugin-content-pages', - ); + const pagesMetadata = await plugin.loadContent!(); - expect(pagesMetadata).toEqual([ - { - type: 'jsx', - permalink: '/', - source: path.posix.join('@site', pluginPath, 'index.js'), - }, - { - type: 'jsx', - permalink: '/typescript', - source: path.posix.join('@site', pluginPath, 'typescript.tsx'), - }, - { - type: 'mdx', - permalink: '/hello/', - source: path.posix.join('@site', pluginPath, 'hello', 'index.md'), - description: 'Markdown index page', - frontMatter: {}, - title: 'Index', - }, - { - type: 'mdx', - permalink: '/hello/mdxPage', - source: path.posix.join('@site', pluginPath, 'hello', 'mdxPage.mdx'), - description: 'my mdx page', - title: 'mdx page', - frontMatter: { - description: 'my mdx page', - title: 'mdx page', - }, - }, - { - type: 'jsx', - permalink: '/hello/translatedJs', - source: path.posix.join(frTranslationsPath, 'hello', 'translatedJs.js'), - }, - { - type: 'mdx', - permalink: '/hello/translatedMd', - source: path.posix.join(frTranslationsPath, 'hello', 'translatedMd.md'), - description: 'translated markdown page (fr)', - frontMatter: {}, - title: undefined, - }, - { - type: 'jsx', - permalink: '/hello/world', - source: path.posix.join('@site', pluginPath, 'hello', 'world.js'), - }, - ]); + expect(pagesMetadata).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts index a891d20dae97..484ffac9159d 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts @@ -22,17 +22,17 @@ function normalizePluginOptions( } describe('normalizePagesPluginOptions', () => { - test('should return default options for undefined user options', () => { + it('returns default options for undefined user options', () => { const value = normalizePluginOptions({}); expect(value).toEqual(DEFAULT_OPTIONS); }); - test('should fill in default options for partially defined user options', () => { + it('fills in default options for partially defined user options', () => { const value = normalizePluginOptions({path: 'src/pages'}); expect(value).toEqual(DEFAULT_OPTIONS); }); - test('should accept correctly defined user options', () => { + it('accepts correctly defined user options', () => { const userOptions = { path: 'src/my-pages', routeBasePath: 'my-pages', @@ -43,7 +43,7 @@ describe('normalizePagesPluginOptions', () => { expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); }); - test('should reject bad path inputs', () => { + it('rejects bad path inputs', () => { expect(() => { normalizePluginOptions({ // @ts-expect-error: bad attribute diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index 36edf71a3411..3c3fa1172f98 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -10,7 +10,7 @@ import type {DocusaurusConfig} from '@docusaurus/types'; import {EnumChangefreq} from 'sitemap'; describe('createSitemap', () => { - test('simple site', async () => { + it('simple site', async () => { const sitemap = await createSitemap( { url: 'https://example.com', @@ -26,14 +26,14 @@ describe('createSitemap', () => { ); }); - test('empty site', () => + it('empty site', () => expect(async () => { await createSitemap({} as DocusaurusConfig, [], {}); }).rejects.toThrow( 'URL in docusaurus.config.js cannot be empty/undefined.', )); - test('exclusion of 404 page', async () => { + it('exclusion of 404 page', async () => { const sitemap = await createSitemap( { url: 'https://example.com', @@ -47,7 +47,7 @@ describe('createSitemap', () => { expect(sitemap).not.toContain('404'); }); - test('keep trailing slash unchanged', async () => { + it('keep trailing slash unchanged', async () => { const sitemap = await createSitemap( { url: 'https://example.com', @@ -66,7 +66,7 @@ describe('createSitemap', () => { expect(sitemap).toContain('https://example.com/nested/test2/'); }); - test('add trailing slash', async () => { + it('add trailing slash', async () => { const sitemap = await createSitemap( { url: 'https://example.com', @@ -85,7 +85,7 @@ describe('createSitemap', () => { expect(sitemap).toContain('https://example.com/nested/test2/'); }); - test('remove trailing slash', async () => { + it('remove trailing slash', async () => { const sitemap = await createSitemap( { url: 'https://example.com', diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts index 9ac30edea870..b245be71375c 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts @@ -19,21 +19,21 @@ function normalizePluginOptions(options) { } describe('normalizeSitemapPluginOptions', () => { - test('should return default values for empty user options', async () => { - const {value} = await PluginOptionSchema.validate({}); + it('returns default values for empty user options', () => { + const {value} = PluginOptionSchema.validate({}); expect(value).toEqual(DEFAULT_OPTIONS); }); - test('should accept correctly defined user options', async () => { + it('accepts correctly defined user options', () => { const userOptions = { changefreq: 'yearly', priority: 0.9, }; - const {value} = await PluginOptionSchema.validate(userOptions); + const {value} = PluginOptionSchema.validate(userOptions); expect(value).toEqual(userOptions); }); - test('should reject out-of-range priority inputs', () => { + it('rejects out-of-range priority inputs', () => { expect(() => { normalizePluginOptions({ priority: 2, @@ -43,7 +43,7 @@ describe('normalizeSitemapPluginOptions', () => { ); }); - test('should reject bad changefreq inputs', () => { + it('rejects bad changefreq inputs', () => { expect(() => { normalizePluginOptions({ changefreq: 'annually', diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap index 03e53282c43b..82db48b367ad 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`npm2yarn plugin test: already imported tabs components above are not re-imported 1`] = ` +exports[`npm2yarn plugin does not re-import tabs components when already imported above 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -24,7 +24,7 @@ import TabItem from '@theme/TabItem'; " `; -exports[`npm2yarn plugin test: already imported tabs components below are not re-imported 1`] = ` +exports[`npm2yarn plugin tdoes not re-import tabs components when already imported below 1`] = ` " @@ -48,7 +48,7 @@ import TabItem from '@theme/TabItem'; " `; -exports[`npm2yarn plugin test: installation file 1`] = ` +exports[`npm2yarn plugin works on installation file 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -71,22 +71,7 @@ import TabItem from '@theme/TabItem'; " `; -exports[`npm2yarn plugin test: language was not set 1`] = ` -"\`\`\`npm2yarn -npm install --save docusaurus-plugin-name -\`\`\` - -\`\`\`bash -npm install --save docusaurus-plugin-name -\`\`\` - -\`\`\`shell -npm install --save docusaurus-plugin-name -\`\`\` -" -`; - -exports[`npm2yarn plugin test: plugin file 1`] = ` +exports[`npm2yarn plugin works on plugin file 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -112,3 +97,18 @@ yarn add docusaurus-plugin-name " `; + +exports[`npm2yarn plugin works when language is not set 1`] = ` +"\`\`\`npm2yarn +npm install --save docusaurus-plugin-name +\`\`\` + +\`\`\`bash +npm install --save docusaurus-plugin-name +\`\`\` + +\`\`\`shell +npm install --save docusaurus-plugin-name +\`\`\` +" +`; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts index c8459f70c17a..c33e7452ccdf 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts @@ -25,31 +25,31 @@ const processFixture = async (name: string, options?: {sync?: boolean}) => { }; describe('npm2yarn plugin', () => { - test('test: installation file', async () => { + it('works on installation file', async () => { const result = await processFixture('installation'); expect(result).toMatchSnapshot(); }); - test('test: plugin file', async () => { + it('works on plugin file', async () => { const result = await processFixture('plugin'); expect(result).toMatchSnapshot(); }); - test('test: language was not set', async () => { + it('works when language is not set', async () => { const result = await processFixture('syntax-not-properly-set'); expect(result).toMatchSnapshot(); }); - test('test: already imported tabs components above are not re-imported', async () => { + it('does not re-import tabs components when already imported above', async () => { const result = await processFixture('import-tabs-above'); expect(result).toMatchSnapshot(); }); - test('test: already imported tabs components below are not re-imported', async () => { + it('tdoes not re-import tabs components when already imported below', async () => { const result = await processFixture('import-tabs-below'); expect(result).toMatchSnapshot(); diff --git a/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap index 3f3ae40ed41f..6d539a18ccd5 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getTranslationFiles should return translation files matching snapshot 1`] = ` +exports[`getTranslationFiles returns translation files matching snapshot 1`] = ` Array [ Object { "content": Object { @@ -55,7 +55,7 @@ Array [ ] `; -exports[`getTranslationFiles should return translation files matching snapshot 2`] = ` +exports[`getTranslationFiles returns translation files matching snapshot 2`] = ` Array [ Object { "content": Object { @@ -98,7 +98,7 @@ Array [ ] `; -exports[`translateThemeConfig should return translated themeConfig matching snapshot 1`] = ` +exports[`translateThemeConfig returns translated themeConfig 1`] = ` Object { "announcementBar": Object {}, "colorMode": Object {}, diff --git a/packages/docusaurus-theme-classic/src/__tests__/translations.test.ts b/packages/docusaurus-theme-classic/src/__tests__/translations.test.ts index 8c8b4d908951..66d738519e1e 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/translations.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/translations.test.ts @@ -79,7 +79,7 @@ function getSampleTranslationFilesTranslated(themeConfig: ThemeConfig) { } describe('getTranslationFiles', () => { - test('should return translation files matching snapshot', () => { + it('returns translation files matching snapshot', () => { expect(getSampleTranslationFiles(ThemeConfigSample)).toMatchSnapshot(); expect( getSampleTranslationFiles(ThemeConfigSampleSimpleFooter), @@ -88,7 +88,7 @@ describe('getTranslationFiles', () => { }); describe('translateThemeConfig', () => { - test('should not translate anything if translation files are untranslated', () => { + it('does not translate anything if translation files are untranslated', () => { expect( translateThemeConfig({ themeConfig: ThemeConfigSample, @@ -97,7 +97,7 @@ describe('translateThemeConfig', () => { ).toEqual(ThemeConfigSample); }); - test('should return translated themeConfig matching snapshot', () => { + it('returns translated themeConfig', () => { expect( translateThemeConfig({ themeConfig: ThemeConfigSample, @@ -117,17 +117,17 @@ describe('getTranslationFiles and translateThemeConfig isomorphism', () => { expect(translatedThemeConfig).toEqual(themeConfig); } - test('should be verified for sample', () => { + it('is verified for sample', () => { verifyIsomorphism(ThemeConfigSample); }); - test('should be verified for sample with simple footer', () => { + it('is verified for sample with simple footer', () => { verifyIsomorphism(ThemeConfigSampleSimpleFooter); }); // undefined footer should not make the translation code crash // See https://github.com/facebook/docusaurus/issues/3936 - test('should be verified for sample without footer', () => { + it('is verified for sample without footer', () => { verifyIsomorphism({...ThemeConfigSample, footer: undefined}); }); }); diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index f9a97d31588d..44cb618bd3a3 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -29,7 +29,7 @@ function testOk(partialThemeConfig: Record) { } describe('themeConfig', () => { - test('should accept valid theme config', () => { + it('accepts valid theme config', () => { const userConfig = { prism: { theme, @@ -101,7 +101,7 @@ describe('themeConfig', () => { }); }); - test('should allow possible types of navbar items', () => { + it('allows possible types of navbar items', () => { const config = { navbar: { items: [ @@ -199,7 +199,7 @@ describe('themeConfig', () => { }); }); - test('should reject unknown navbar item type', () => { + it('rejects unknown navbar item type', () => { const config = { navbar: { items: [ @@ -216,7 +216,7 @@ describe('themeConfig', () => { ).toThrowErrorMatchingInlineSnapshot(`"Bad navbar item type joke"`); }); - test('should reject nested dropdowns', () => { + it('rejects nested dropdowns', () => { const config = { navbar: { items: [ @@ -243,7 +243,7 @@ describe('themeConfig', () => { ).toThrowErrorMatchingInlineSnapshot(`"Nested dropdowns are not allowed"`); }); - test('should reject nested dropdowns 2', () => { + it('rejects nested dropdowns 2', () => { const config = { navbar: { items: [ @@ -260,7 +260,7 @@ describe('themeConfig', () => { ).toThrowErrorMatchingInlineSnapshot(`"Nested dropdowns are not allowed"`); }); - test('should reject position attribute within dropdown', () => { + it('rejects position attribute within dropdown', () => { const config = { navbar: { items: [ @@ -285,7 +285,7 @@ describe('themeConfig', () => { ); }); - test('should give friendly error when href and to coexist', () => { + it('gives friendly error when href and to coexist', () => { const config = { navbar: { items: [ @@ -305,7 +305,7 @@ describe('themeConfig', () => { ); }); - test('should allow empty alt tags for the logo image in the header', () => { + it('allows empty alt tags for the logo image in the header', () => { const altTagConfig = { navbar: { logo: { @@ -324,7 +324,7 @@ describe('themeConfig', () => { }); }); - test('should allow empty alt tags for the logo image in the footer', () => { + it('allows empty alt tags for the logo image in the footer', () => { const partialConfig = { footer: { logo: { @@ -344,7 +344,7 @@ describe('themeConfig', () => { }); }); - test('should allow simple links in footer', () => { + it('allows simple links in footer', () => { const partialConfig = { footer: { links: [ @@ -378,7 +378,7 @@ describe('themeConfig', () => { }); }); - test('should allow footer column with no title', () => { + it('allows footer column with no title', () => { const partialConfig = { footer: { links: [ @@ -414,7 +414,7 @@ describe('themeConfig', () => { }); }); - test('should reject mix of simple and multi-column links in footer', () => { + it('rejects mix of simple and multi-column links in footer', () => { const partialConfig = { footer: { links: [ @@ -442,7 +442,7 @@ describe('themeConfig', () => { ); }); - test('should allow width and height specification for logo', () => { + it('allows width and height specification for logo', () => { const altTagConfig = { navbar: { logo: { @@ -463,7 +463,7 @@ describe('themeConfig', () => { }); }); - test('should accept valid prism config', () => { + it('accepts valid prism config', () => { const prismConfig = { prism: { additionalLanguages: ['kotlin', 'java'], @@ -476,25 +476,25 @@ describe('themeConfig', () => { }); describe('customCss config', () => { - test('should accept customCss undefined', () => { + it('accepts customCss undefined', () => { testOk({ customCss: undefined, }); }); - test('should accept customCss string', () => { + it('accepts customCss string', () => { testOk({ customCss: './path/to/cssFile.css', }); }); - test('should accept customCss string array', () => { + it('accepts customCss string array', () => { testOk({ customCss: ['./path/to/cssFile.css', './path/to/cssFile2.css'], }); }); - test('should reject customCss number', () => { + it('rejects customCss number', () => { expect(() => testValidateThemeConfig({ customCss: 42, @@ -509,7 +509,7 @@ describe('themeConfig', () => { const withDefaultValues = (colorMode) => _.merge({}, DEFAULT_CONFIG.colorMode, colorMode); - test('switch config', () => { + it('switch config', () => { const colorMode = { switchConfig: { darkIcon: '🌙', @@ -522,7 +522,7 @@ describe('themeConfig', () => { ); }); - test('max config', () => { + it('max config', () => { const colorMode = { defaultMode: 'dark', disableSwitch: false, @@ -534,7 +534,7 @@ describe('themeConfig', () => { }); }); - test('undefined config', () => { + it('undefined config', () => { const colorMode = undefined; expect(testValidateThemeConfig({colorMode})).toEqual({ ...DEFAULT_CONFIG, @@ -542,7 +542,7 @@ describe('themeConfig', () => { }); }); - test('empty config', () => { + it('empty config', () => { const colorMode = {}; expect(testValidateThemeConfig({colorMode})).toEqual({ ...DEFAULT_CONFIG, @@ -553,132 +553,132 @@ describe('themeConfig', () => { }); }); }); -}); -describe('themeConfig tableOfContents', () => { - test('toc undefined', () => { - const tableOfContents = undefined; - expect(testValidateThemeConfig({tableOfContents})).toEqual({ - ...DEFAULT_CONFIG, - tableOfContents: { - minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, - maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, - }, + describe('tableOfContents', () => { + it('accepts undefined', () => { + const tableOfContents = undefined; + expect(testValidateThemeConfig({tableOfContents})).toEqual({ + ...DEFAULT_CONFIG, + tableOfContents: { + minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, + maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, + }, + }); }); - }); - test('toc empty', () => { - const tableOfContents = {}; - expect(testValidateThemeConfig({tableOfContents})).toEqual({ - ...DEFAULT_CONFIG, - tableOfContents: { - minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, - maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, - }, + it('accepts empty', () => { + const tableOfContents = {}; + expect(testValidateThemeConfig({tableOfContents})).toEqual({ + ...DEFAULT_CONFIG, + tableOfContents: { + minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, + maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, + }, + }); }); - }); - test('toc with min', () => { - const tableOfContents = { - minHeadingLevel: 3, - }; - expect(testValidateThemeConfig({tableOfContents})).toEqual({ - ...DEFAULT_CONFIG, - tableOfContents: { + it('accepts min', () => { + const tableOfContents = { minHeadingLevel: 3, - maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, - }, + }; + expect(testValidateThemeConfig({tableOfContents})).toEqual({ + ...DEFAULT_CONFIG, + tableOfContents: { + minHeadingLevel: 3, + maxHeadingLevel: DEFAULT_CONFIG.tableOfContents.maxHeadingLevel, + }, + }); }); - }); - test('toc with max', () => { - const tableOfContents = { - maxHeadingLevel: 5, - }; - expect(testValidateThemeConfig({tableOfContents})).toEqual({ - ...DEFAULT_CONFIG, - tableOfContents: { - minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, + it('accepts max', () => { + const tableOfContents = { maxHeadingLevel: 5, - }, + }; + expect(testValidateThemeConfig({tableOfContents})).toEqual({ + ...DEFAULT_CONFIG, + tableOfContents: { + minHeadingLevel: DEFAULT_CONFIG.tableOfContents.minHeadingLevel, + maxHeadingLevel: 5, + }, + }); }); - }); - test('toc with min 2.5', () => { - const tableOfContents = { - minHeadingLevel: 2.5, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be an integer"`, - ); - }); + it('rejects min 2.5', () => { + const tableOfContents = { + minHeadingLevel: 2.5, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.minHeadingLevel\\" must be an integer"`, + ); + }); - test('toc with max 2.5', () => { - const tableOfContents = { - maxHeadingLevel: 2.5, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be an integer"`, - ); - }); + it('rejects max 2.5', () => { + const tableOfContents = { + maxHeadingLevel: 2.5, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.maxHeadingLevel\\" must be an integer"`, + ); + }); - test('toc with min 1', () => { - const tableOfContents = { - minHeadingLevel: 1, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be greater than or equal to 2"`, - ); - }); + it('rejects min 1', () => { + const tableOfContents = { + minHeadingLevel: 1, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.minHeadingLevel\\" must be greater than or equal to 2"`, + ); + }); - test('toc with min 7', () => { - const tableOfContents = { - minHeadingLevel: 7, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, - ); - }); + it('rejects min 7', () => { + const tableOfContents = { + minHeadingLevel: 7, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, + ); + }); - test('toc with max 1', () => { - const tableOfContents = { - maxHeadingLevel: 1, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be greater than or equal to 2"`, - ); - }); + it('rejects max 1', () => { + const tableOfContents = { + maxHeadingLevel: 1, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.maxHeadingLevel\\" must be greater than or equal to 2"`, + ); + }); - test('toc with max 7', () => { - const tableOfContents = { - maxHeadingLevel: 7, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be less than or equal to 6"`, - ); - }); + it('rejects max 7', () => { + const tableOfContents = { + maxHeadingLevel: 7, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.maxHeadingLevel\\" must be less than or equal to 6"`, + ); + }); - test('toc with bad min 5 + max 3', () => { - const tableOfContents = { - minHeadingLevel: 5, - maxHeadingLevel: 3, - }; - expect(() => - testValidateThemeConfig({tableOfContents}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, - ); + it('rejects min 5 + max 3', () => { + const tableOfContents = { + minHeadingLevel: 5, + maxHeadingLevel: 3, + }; + expect(() => + testValidateThemeConfig({tableOfContents}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, + ); + }); }); }); diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx index 432eed136d57..52966b9c2fa6 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx @@ -15,7 +15,7 @@ import { } from '@docusaurus/theme-common'; describe('Tabs', () => { - test('Should reject bad Tabs child', () => { + it('rejects bad Tabs child', () => { expect(() => { renderer.create( @@ -27,7 +27,7 @@ describe('Tabs', () => { `"Docusaurus error: Bad child
    : all children of the component should be , and every should have a unique \\"value\\" prop."`, ); }); - test('Should reject bad Tabs defaultValue', () => { + it('rejects bad Tabs defaultValue', () => { expect(() => { renderer.create( @@ -39,7 +39,7 @@ describe('Tabs', () => { `"Docusaurus error: The has a defaultValue \\"bad\\" but none of its children has the corresponding value. Available values are: v1, v2. If you intend to show no default tab, use defaultValue={null} instead."`, ); }); - test('Should reject duplicate values', () => { + it('rejects duplicate values', () => { expect(() => { renderer.create( @@ -55,7 +55,7 @@ describe('Tabs', () => { `"Docusaurus error: Duplicate values \\"v1, v2\\" found in . Every value needs to be unique."`, ); }); - test('Should accept valid Tabs config', () => { + it('accepts valid Tabs config', () => { expect(() => { renderer.create( @@ -110,7 +110,7 @@ describe('Tabs', () => { }).not.toThrow(); // TODO Better Jest infrastructure to mock the Layout }); // https://github.com/facebook/docusaurus/issues/5729 - test('Should accept dynamic Tabs with number values', () => { + it('accepts dynamic Tabs with number values', () => { expect(() => { const tabs = ['Apple', 'Banana', 'Carrot']; renderer.create( diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap new file mode 100644 index 000000000000..cf5493e481f5 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap @@ -0,0 +1,123 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseLines does not parse content with metastring 1`] = ` +Object { + "code": "aaaaa +bbbbb", + "highlightLines": Array [ + 0, + ], +} +`; + +exports[`parseLines does not parse content with metastring 2`] = ` +Object { + "code": "// highlight-next-line +aaaaa +bbbbb", + "highlightLines": Array [ + 0, + ], +} +`; + +exports[`parseLines does not parse content with metastring 3`] = ` +Object { + "code": "aaaaa +bbbbb", + "highlightLines": Array [ + 0, + ], +} +`; + +exports[`parseLines does not parse content with no language 1`] = ` +Object { + "code": "// highlight-next-line +aaaaa +bbbbb", + "highlightLines": Array [], +} +`; + +exports[`parseLines removes lines correctly 1`] = ` +Object { + "code": "aaaaa +bbbbb", + "highlightLines": Array [ + 0, + ], +} +`; + +exports[`parseLines removes lines correctly 2`] = ` +Object { + "code": "aaaaa +bbbbb", + "highlightLines": Array [ + 0, + ], +} +`; + +exports[`parseLines removes lines correctly 3`] = ` +Object { + "code": "aaaaa +bbbbbbb +bbbbb", + "highlightLines": Array [ + 0, + 2, + 0, + 1, + ], +} +`; + +exports[`parseLines respects language 1`] = ` +Object { + "code": "# highlight-next-line +aaaaa +bbbbb", + "highlightLines": Array [], +} +`; + +exports[`parseLines respects language 2`] = ` +Object { + "code": "/* highlight-next-line */ +aaaaa +bbbbb", + "highlightLines": Array [], +} +`; + +exports[`parseLines respects language 3`] = ` +Object { + "code": "// highlight-next-line +aaaa +/* highlight-next-line */ +bbbbb +ccccc + +dddd", + "highlightLines": Array [ + 4, + ], +} +`; + +exports[`parseLines respects language 4`] = ` +Object { + "code": "aaaa +bbbbb +ccccc +dddd", + "highlightLines": Array [ + 0, + 1, + 2, + 3, + ], +} +`; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts index aa7fc3053852..509a92f1ccf0 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts @@ -12,45 +12,45 @@ import { } from '../codeBlockUtils'; describe('parseCodeBlockTitle', () => { - test('should parse double quote delimited title', () => { + it('parses double quote delimited title', () => { expect(parseCodeBlockTitle(`title="index.js"`)).toEqual(`index.js`); }); - test('should parse single quote delimited title', () => { + it('parses single quote delimited title', () => { expect(parseCodeBlockTitle(`title='index.js'`)).toEqual(`index.js`); }); - test('should not parse mismatched quote delimiters', () => { + it('does not parse mismatched quote delimiters', () => { expect(parseCodeBlockTitle(`title="index.js'`)).toEqual(``); }); - test('should parse undefined metastring', () => { + it('parses undefined metastring', () => { expect(parseCodeBlockTitle(undefined)).toEqual(``); }); - test('should parse metastring with no title specified', () => { + it('parses metastring with no title specified', () => { expect(parseCodeBlockTitle(`{1,2-3}`)).toEqual(``); }); - test('should parse with multiple metadata title first', () => { + it('parses with multiple metadata title first', () => { expect(parseCodeBlockTitle(`title="index.js" label="JavaScript"`)).toEqual( `index.js`, ); }); - test('should parse with multiple metadata title last', () => { + it('parses with multiple metadata title last', () => { expect(parseCodeBlockTitle(`label="JavaScript" title="index.js"`)).toEqual( `index.js`, ); }); - test('should parse double quotes when delimited by single quotes', () => { + it('parses double quotes when delimited by single quotes', () => { expect(parseCodeBlockTitle(`title='console.log("Hello, World!")'`)).toEqual( `console.log("Hello, World!")`, ); }); - test('should parse single quotes when delimited by double quotes', () => { + it('parses single quotes when delimited by double quotes', () => { expect(parseCodeBlockTitle(`title="console.log('Hello, World!')"`)).toEqual( `console.log('Hello, World!')`, ); @@ -58,7 +58,7 @@ describe('parseCodeBlockTitle', () => { }); describe('parseLanguage', () => { - test('behaves correctly', () => { + it('works', () => { expect(parseLanguage('language-foo xxx yyy')).toEqual('foo'); expect(parseLanguage('xxxxx language-foo yyy')).toEqual('foo'); expect(parseLanguage('xx-language-foo yyyy')).toBeUndefined(); @@ -67,16 +67,8 @@ describe('parseLanguage', () => { }); describe('parseLines', () => { - test('does not parse content with metastring', () => { - expect(parseLines('aaaaa\nbbbbb', '{1}', 'js')).toMatchInlineSnapshot(` - Object { - "code": "aaaaa - bbbbb", - "highlightLines": Array [ - 0, - ], - } - `); + it('does not parse content with metastring', () => { + expect(parseLines('aaaaa\nbbbbb', '{1}', 'js')).toMatchSnapshot(); expect( parseLines( `// highlight-next-line @@ -85,33 +77,16 @@ bbbbb`, '{1}', 'js', ), - ).toMatchInlineSnapshot(` - Object { - "code": "// highlight-next-line - aaaaa - bbbbb", - "highlightLines": Array [ - 0, - ], - } - `); + ).toMatchSnapshot(); expect( parseLines( `aaaaa bbbbb`, '{1}', ), - ).toMatchInlineSnapshot(` - Object { - "code": "aaaaa - bbbbb", - "highlightLines": Array [ - 0, - ], - } - `); + ).toMatchSnapshot(); }); - test('does not parse content with no language', () => { + it('does not parse content with no language', () => { expect( parseLines( `// highlight-next-line @@ -120,16 +95,9 @@ bbbbb`, '', undefined, ), - ).toMatchInlineSnapshot(` - Object { - "code": "// highlight-next-line - aaaaa - bbbbb", - "highlightLines": Array [], - } - `); + ).toMatchSnapshot(); }); - test('removes lines correctly', () => { + it('removes lines correctly', () => { expect( parseLines( `// highlight-next-line @@ -138,15 +106,7 @@ bbbbb`, '', 'js', ), - ).toMatchInlineSnapshot(` - Object { - "code": "aaaaa - bbbbb", - "highlightLines": Array [ - 0, - ], - } - `); + ).toMatchSnapshot(); expect( parseLines( `// highlight-start @@ -156,15 +116,7 @@ bbbbb`, '', 'js', ), - ).toMatchInlineSnapshot(` - Object { - "code": "aaaaa - bbbbb", - "highlightLines": Array [ - 0, - ], - } - `); + ).toMatchSnapshot(); expect( parseLines( `// highlight-start @@ -177,21 +129,9 @@ bbbbb`, '', 'js', ), - ).toMatchInlineSnapshot(` - Object { - "code": "aaaaa - bbbbbbb - bbbbb", - "highlightLines": Array [ - 0, - 2, - 0, - 1, - ], - } - `); + ).toMatchSnapshot(); }); - test('respects language', () => { + it('respects language', () => { expect( parseLines( `# highlight-next-line @@ -200,14 +140,7 @@ bbbbb`, '', 'js', ), - ).toMatchInlineSnapshot(` - Object { - "code": "# highlight-next-line - aaaaa - bbbbb", - "highlightLines": Array [], - } - `); + ).toMatchSnapshot(); expect( parseLines( `/* highlight-next-line */ @@ -216,14 +149,7 @@ bbbbb`, '', 'py', ), - ).toMatchInlineSnapshot(` - Object { - "code": "/* highlight-next-line */ - aaaaa - bbbbb", - "highlightLines": Array [], - } - `); + ).toMatchSnapshot(); expect( parseLines( `// highlight-next-line @@ -237,20 +163,7 @@ dddd`, '', 'py', ), - ).toMatchInlineSnapshot(` - Object { - "code": "// highlight-next-line - aaaa - /* highlight-next-line */ - bbbbb - ccccc - - dddd", - "highlightLines": Array [ - 4, - ], - } - `); + ).toMatchSnapshot(); expect( parseLines( `// highlight-next-line @@ -264,19 +177,6 @@ dddd`, '', '', ), - ).toMatchInlineSnapshot(` - Object { - "code": "aaaa - bbbbb - ccccc - dddd", - "highlightLines": Array [ - 0, - 1, - 2, - 3, - ], - } - `); + ).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index b08b6862bf72..d5d4c2542703 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -65,365 +65,353 @@ function testVersion(data?: Partial): PropVersionMetadata { }; } -describe('docsUtils', () => { - describe('useDocsVersion', () => { - test('should throw if context provider is missing', () => { - expect( - () => renderHook(() => useDocsVersion()).result.current, - ).toThrowErrorMatchingInlineSnapshot( - `"Hook useDocsVersion is called outside the . "`, - ); - }); +describe('useDocsVersion', () => { + it('throws if context provider is missing', () => { + expect( + () => renderHook(() => useDocsVersion()).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Hook useDocsVersion is called outside the . "`, + ); + }); - test('should read value from context provider', () => { - const version = testVersion(); - const {result} = renderHook(() => useDocsVersion(), { - wrapper: ({children}) => ( - - {children} - - ), - }); - expect(result.current).toBe(version); + it('reads value from context provider', () => { + const version = testVersion(); + const {result} = renderHook(() => useDocsVersion(), { + wrapper: ({children}) => ( + {children} + ), }); + expect(result.current).toBe(version); }); +}); - describe('useDocsSidebar', () => { - test('should throw if context provider is missing', () => { - expect( - () => renderHook(() => useDocsSidebar()).result.current, - ).toThrowErrorMatchingInlineSnapshot( - `"Hook useDocsSidebar is called outside the . "`, - ); - }); +describe('useDocsSidebar', () => { + it('throws if context provider is missing', () => { + expect( + () => renderHook(() => useDocsSidebar()).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Hook useDocsSidebar is called outside the . "`, + ); + }); - test('should read value from context provider', () => { - const sidebar: PropSidebar = []; - const {result} = renderHook(() => useDocsSidebar(), { - wrapper: ({children}) => ( - - {children} - - ), - }); - expect(result.current).toBe(sidebar); + it('reads value from context provider', () => { + const sidebar: PropSidebar = []; + const {result} = renderHook(() => useDocsSidebar(), { + wrapper: ({children}) => ( + {children} + ), }); + expect(result.current).toBe(sidebar); }); +}); - describe('useDocById', () => { - const version = testVersion({ - docs: { - doc1: { - id: 'doc1', - title: 'Doc 1', - description: 'desc1', - sidebar: 'sidebar1', - }, - doc2: { - id: 'doc2', - title: 'Doc 2', - description: 'desc2', - sidebar: 'sidebar2', - }, +describe('useDocById', () => { + const version = testVersion({ + docs: { + doc1: { + id: 'doc1', + title: 'Doc 1', + description: 'desc1', + sidebar: 'sidebar1', }, - }); + doc2: { + id: 'doc2', + title: 'Doc 2', + description: 'desc2', + sidebar: 'sidebar2', + }, + }, + }); - function callHook(docId: string | undefined) { - const {result} = renderHook(() => useDocById(docId), { - wrapper: ({children}) => ( - - {children} - - ), - }); - return result.current; - } - - test('should accept undefined', () => { - expect(callHook(undefined)).toBeUndefined(); + function callHook(docId: string | undefined) { + const {result} = renderHook(() => useDocById(docId), { + wrapper: ({children}) => ( + {children} + ), }); + return result.current; + } - test('should find doc1', () => { - expect(callHook('doc1')).toMatchObject({id: 'doc1'}); - }); - test('should find doc2', () => { - expect(callHook('doc2')).toMatchObject({id: 'doc2'}); - }); - - test('should throw for doc3', () => { - expect(() => callHook('doc3')).toThrowErrorMatchingInlineSnapshot( - `"no version doc found by id=doc3"`, - ); - }); + it('accepts undefined', () => { + expect(callHook(undefined)).toBeUndefined(); }); - describe('findSidebarCategory', () => { - test('should be able to return undefined', () => { - expect(findSidebarCategory([], () => false)).toBeUndefined(); - expect( - findSidebarCategory([testCategory(), testCategory()], () => false), - ).toBeUndefined(); - }); + it('finds doc1', () => { + expect(callHook('doc1')).toMatchObject({id: 'doc1'}); + }); + it('finds doc2', () => { + expect(callHook('doc2')).toMatchObject({id: 'doc2'}); + }); - test('should return first element matching predicate', () => { - const first = testCategory(); - const second = testCategory(); - const third = testCategory(); - const sidebar = [first, second, third]; - expect(findSidebarCategory(sidebar, () => true)).toEqual(first); - expect(findSidebarCategory(sidebar, (item) => item === first)).toEqual( - first, - ); - expect(findSidebarCategory(sidebar, (item) => item === second)).toEqual( - second, - ); - expect(findSidebarCategory(sidebar, (item) => item === third)).toEqual( - third, - ); - }); + it('throws for doc3', () => { + expect(() => callHook('doc3')).toThrowErrorMatchingInlineSnapshot( + `"no version doc found by id=doc3"`, + ); + }); +}); - test('should be able to search in sub items', () => { - const subsub1 = testCategory(); - const subsub2 = testCategory(); - const sub1 = testCategory({ - items: [subsub1, subsub2], - }); - const sub2 = testCategory(); - const parent = testCategory({ - items: [sub1, sub2], - }); - const sidebar = [parent]; - - expect(findSidebarCategory(sidebar, () => true)).toEqual(parent); - expect(findSidebarCategory(sidebar, (item) => item === sub1)).toEqual( - sub1, - ); - expect(findSidebarCategory(sidebar, (item) => item === sub2)).toEqual( - sub2, - ); - expect(findSidebarCategory(sidebar, (item) => item === subsub1)).toEqual( - subsub1, - ); - expect(findSidebarCategory(sidebar, (item) => item === subsub2)).toEqual( - subsub2, - ); - }); +describe('findSidebarCategory', () => { + it('os able to return undefined', () => { + expect(findSidebarCategory([], () => false)).toBeUndefined(); + expect( + findSidebarCategory([testCategory(), testCategory()], () => false), + ).toBeUndefined(); }); - describe('findFirstCategoryLink', () => { - test('category without link nor child', () => { - expect( - findFirstCategoryLink( - testCategory({ - href: undefined, - }), - ), - ).toEqual(undefined); - }); + it('returns first element matching predicate', () => { + const first = testCategory(); + const second = testCategory(); + const third = testCategory(); + const sidebar = [first, second, third]; + expect(findSidebarCategory(sidebar, () => true)).toEqual(first); + expect(findSidebarCategory(sidebar, (item) => item === first)).toEqual( + first, + ); + expect(findSidebarCategory(sidebar, (item) => item === second)).toEqual( + second, + ); + expect(findSidebarCategory(sidebar, (item) => item === third)).toEqual( + third, + ); + }); - test('category with link', () => { - expect( - findFirstCategoryLink( - testCategory({ - href: '/itemPath', - }), - ), - ).toEqual('/itemPath'); + it('is able to search in sub items', () => { + const subsub1 = testCategory(); + const subsub2 = testCategory(); + const sub1 = testCategory({ + items: [subsub1, subsub2], }); - - test('category with deeply nested category link', () => { - expect( - findFirstCategoryLink( - testCategory({ - href: undefined, - items: [ - {type: 'html', value: '

    test1

    '}, - testCategory({ - href: undefined, - items: [ - {type: 'html', value: '

    test2

    '}, - testCategory({ - href: '/itemPath', - }), - ], - }), - ], - }), - ), - ).toEqual('/itemPath'); + const sub2 = testCategory(); + const parent = testCategory({ + items: [sub1, sub2], }); + const sidebar = [parent]; + + expect(findSidebarCategory(sidebar, () => true)).toEqual(parent); + expect(findSidebarCategory(sidebar, (item) => item === sub1)).toEqual(sub1); + expect(findSidebarCategory(sidebar, (item) => item === sub2)).toEqual(sub2); + expect(findSidebarCategory(sidebar, (item) => item === subsub1)).toEqual( + subsub1, + ); + expect(findSidebarCategory(sidebar, (item) => item === subsub2)).toEqual( + subsub2, + ); + }); +}); - test('category with deeply nested link', () => { - expect( - findFirstCategoryLink( - testCategory({ - href: undefined, - items: [ - testCategory({ - href: undefined, - items: [{type: 'link', href: '/itemPath', label: 'Label'}], - }), - ], - }), - ), - ).toEqual('/itemPath'); - }); +describe('findFirstCategoryLink', () => { + it('works with category without link nor child', () => { + expect( + findFirstCategoryLink( + testCategory({ + href: undefined, + }), + ), + ).toEqual(undefined); }); - describe('isActiveSidebarItem', () => { - test('with link href', () => { - const item: PropSidebarItem = { - type: 'link', - href: '/itemPath', - label: 'Label', - }; + it('works with category with link', () => { + expect( + findFirstCategoryLink( + testCategory({ + href: '/itemPath', + }), + ), + ).toEqual('/itemPath'); + }); - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + it('works with category with deeply nested category link', () => { + expect( + findFirstCategoryLink( + testCategory({ + href: undefined, + items: [ + {type: 'html', value: '

    test1

    '}, + testCategory({ + href: undefined, + items: [ + {type: 'html', value: '

    test2

    '}, + testCategory({ + href: '/itemPath', + }), + ], + }), + ], + }), + ), + ).toEqual('/itemPath'); + }); - expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); + it('works with category with deeply nested link', () => { + expect( + findFirstCategoryLink( + testCategory({ + href: undefined, + items: [ + testCategory({ + href: undefined, + items: [{type: 'link', href: '/itemPath', label: 'Label'}], + }), + ], + }), + ), + ).toEqual('/itemPath'); + }); +}); - // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); - expect( - isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), - ).toEqual(true); - }); +describe('isActiveSidebarItem', () => { + it('works with link href', () => { + const item: PropSidebarItem = { + type: 'link', + href: '/itemPath', + label: 'Label', + }; - test('with category href', () => { - const item: PropSidebarItem = testCategory({ - href: '/itemPath', - }); + expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); - expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); + // Ensure it's not trailing slash sensitive: + expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); + expect( + isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), + ).toEqual(true); + }); - // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); - expect( - isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), - ).toEqual(true); + it('works with category href', () => { + const item: PropSidebarItem = testCategory({ + href: '/itemPath', }); - test('with category nested items', () => { - const item: PropSidebarItem = testCategory({ - href: '/category-path', - items: [ - { - type: 'link', - href: '/sub-link-path', - label: 'Label', - }, - testCategory({ - href: '/sub-category-path', - items: [ - { - type: 'link', - href: '/sub-sub-link-path', - label: 'Label', - }, - ], - }), - ], - }); - - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); - - expect(isActiveSidebarItem(item, '/category-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-link-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-category-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-sub-link-path')).toEqual(true); - - // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/category-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-link-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-category-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-sub-link-path/')).toEqual(true); - }); + expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + + expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); + + // Ensure it's not trailing slash sensitive: + expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); + expect( + isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), + ).toEqual(true); }); - describe('getBreadcrumbs', () => { - test('should return empty for empty sidebar', () => { - expect( - getBreadcrumbs({ - sidebar: [], - pathname: '/doesNotExist', + it('works with category nested items', () => { + const item: PropSidebarItem = testCategory({ + href: '/category-path', + items: [ + { + type: 'link', + href: '/sub-link-path', + label: 'Label', + }, + testCategory({ + href: '/sub-category-path', + items: [ + { + type: 'link', + href: '/sub-sub-link-path', + label: 'Label', + }, + ], }), - ).toEqual([]); + ], }); - test('should return empty for sidebar but unknown pathname', () => { - const sidebar = [testCategory(), testLink()]; - expect( - getBreadcrumbs({ - sidebar, - pathname: '/doesNotExist', - }), - ).toEqual([]); - }); + expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); - test('should return first level category', () => { - const pathname = '/somePathName'; - const sidebar = [testCategory({href: pathname}), testLink()]; + expect(isActiveSidebarItem(item, '/category-path')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-link-path')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-category-path')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-sub-link-path')).toEqual(true); - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([sidebar[0]]); - }); + // Ensure it's not trailing slash sensitive: + expect(isActiveSidebarItem(item, '/category-path/')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-link-path/')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-category-path/')).toEqual(true); + expect(isActiveSidebarItem(item, '/sub-sub-link-path/')).toEqual(true); + }); +}); - test('should return first level link', () => { - const pathname = '/somePathName'; - const sidebar = [testCategory(), testLink({href: pathname})]; +describe('getBreadcrumbs', () => { + it('returns empty for empty sidebar', () => { + expect( + getBreadcrumbs({ + sidebar: [], + pathname: '/doesNotExist', + }), + ).toEqual([]); + }); - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([sidebar[1]]); - }); + it('returns empty for sidebar but unknown pathname', () => { + const sidebar = [testCategory(), testLink()]; + expect( + getBreadcrumbs({ + sidebar, + pathname: '/doesNotExist', + }), + ).toEqual([]); + }); - test('should return nested category', () => { - const pathname = '/somePathName'; + it('returns first level category', () => { + const pathname = '/somePathName'; + const sidebar = [testCategory({href: pathname}), testLink()]; - const categoryLevel3 = testCategory({ - href: pathname, - }); + expect( + getBreadcrumbs({ + sidebar, + pathname, + }), + ).toEqual([sidebar[0]]); + }); - const categoryLevel2 = testCategory({ - items: [ - testCategory(), - categoryLevel3, - testLink({href: pathname}), - testLink(), - ], - }); + it('returns first level link', () => { + const pathname = '/somePathName'; + const sidebar = [testCategory(), testLink({href: pathname})]; - const categoryLevel1 = testCategory({ - items: [testLink(), categoryLevel2], - }); + expect( + getBreadcrumbs({ + sidebar, + pathname, + }), + ).toEqual([sidebar[1]]); + }); - const sidebar = [ - testLink(), + it('returns nested category', () => { + const pathname = '/somePathName'; + + const categoryLevel3 = testCategory({ + href: pathname, + }); + + const categoryLevel2 = testCategory({ + items: [ testCategory(), - categoryLevel1, + categoryLevel3, + testLink({href: pathname}), testLink(), - testCategory(), - ]; + ], + }); - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([categoryLevel1, categoryLevel2, categoryLevel3]); + const categoryLevel1 = testCategory({ + items: [testLink(), categoryLevel2], }); + + const sidebar = [ + testLink(), + testCategory(), + categoryLevel1, + testLink(), + testCategory(), + ]; + + expect( + getBreadcrumbs({ + sidebar, + pathname, + }), + ).toEqual([categoryLevel1, categoryLevel2, categoryLevel3]); }); - test('should return nested link', () => { + it('returns nested link', () => { const pathname = '/somePathName'; const link = testLink({href: pathname}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/jsUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/jsUtils.test.ts index 99ba23fedf9f..9361063910d9 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/jsUtils.test.ts @@ -8,13 +8,13 @@ import {uniq, duplicates} from '../jsUtils'; describe('duplicates', () => { - test('gets duplicate values', () => { + it('gets duplicate values', () => { expect(duplicates(['a', 'b', 'c', 'd'])).toEqual([]); expect(duplicates(['a', 'b', 'b', 'b'])).toEqual(['b', 'b']); expect(duplicates(['c', 'b', 'b', 'c'])).toEqual(['b', 'c']); expect(duplicates([{a: 1}, {a: 1}, {a: 1}])).toEqual([]); }); - test('accepts custom comparator', () => { + it('accepts custom comparator', () => { expect(duplicates([{a: 1}, {a: 1}, {a: 1}], (a, b) => a.a === b.a)).toEqual( [{a: 1}, {a: 1}], ); @@ -28,7 +28,7 @@ describe('duplicates', () => { }); describe('uniq', () => { - test('remove duplicate primitives', () => { + it('remove duplicate primitives', () => { expect(uniq(['A', 'B', 'C', 'B', 'A', 'D'])).toEqual(['A', 'B', 'C', 'D']); expect(uniq([3, 3, 5, 1, 6, 3, 5])).toEqual([3, 5, 1, 6]); expect(uniq([null, undefined, 3, null, 4, 3])).toEqual([ @@ -39,7 +39,7 @@ describe('uniq', () => { ]); }); - test('remove duplicate objects/arrays by identity', () => { + it('remove duplicate objects/arrays by identity', () => { const obj1 = {}; const obj2 = {}; const obj3 = {}; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts index 1e7d436a76a0..a35cd30199b9 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts @@ -8,32 +8,32 @@ import {isSamePath} from '../pathUtils'; describe('isSamePath', () => { - test('should be true for compared path without trailing slash', () => { + it('returns true for compared path without trailing slash', () => { expect(isSamePath('/docs', '/docs')).toBeTruthy(); }); - test('should be true for compared path with trailing slash', () => { + it('returns true for compared path with trailing slash', () => { expect(isSamePath('/docs', '/docs/')).toBeTruthy(); }); - test('should be true for compared path with different case', () => { + it('returns true for compared path with different case', () => { expect(isSamePath('/doCS', '/DOcs')).toBeTruthy(); }); - test('should be true for compared path with different case + trailing slash', () => { + it('returns true for compared path with different case + trailing slash', () => { expect(isSamePath('/doCS', '/DOcs/')).toBeTruthy(); }); - test('should be false for compared path with double trailing slash', () => { + it('returns false for compared path with double trailing slash', () => { expect(isSamePath('/docs', '/docs//')).toBeFalsy(); }); - test('should be true for twice undefined/null', () => { + it('returns true for twice undefined/null', () => { expect(isSamePath(undefined, undefined)).toBeTruthy(); expect(isSamePath(undefined, undefined)).toBeTruthy(); }); - test('should be false when one undefined', () => { + it('returns false when one undefined', () => { expect(isSamePath('/docs', undefined)).toBeFalsy(); expect(isSamePath(undefined, '/docs')).toBeFalsy(); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts index a05f4812e106..692f5aad7466 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts @@ -8,7 +8,7 @@ import {isRegexpStringMatch} from '../regexpUtils'; describe('isRegexpStringMatch', () => { - test('behaves correctly', () => { + it('works', () => { expect(isRegexpStringMatch(undefined, 'foo')).toEqual(false); expect(isRegexpStringMatch('bar', undefined)).toEqual(false); expect(isRegexpStringMatch('foo', 'bar')).toEqual(false); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts index 9e398dbcac74..36837e3ce977 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts @@ -8,17 +8,17 @@ import {type Route} from '@generated/routes'; import {findHomePageRoute} from '../routesUtils'; -describe('routesUtils findHomePageRoute', () => { +describe('findHomePageRoute', () => { const homePage: Route = { path: '/', exact: true, }; - test('should return undefined for no routes', () => { + it('returns undefined for no routes', () => { expect(findHomePageRoute({baseUrl: '/', routes: []})).toEqual(undefined); }); - test('should return undefined for no homepage', () => { + it('returns undefined for no homepage', () => { expect( findHomePageRoute({ baseUrl: '/', @@ -40,7 +40,7 @@ describe('routesUtils findHomePageRoute', () => { ).toEqual(undefined); }); - test('should find top-level homepage', () => { + it('finds top-level homepage', () => { expect( findHomePageRoute({ baseUrl: '/', @@ -56,7 +56,7 @@ describe('routesUtils findHomePageRoute', () => { ).toEqual(homePage); }); - test('should find nested homepage', () => { + it('finds nested homepage', () => { expect( findHomePageRoute({ baseUrl: '/', @@ -80,7 +80,7 @@ describe('routesUtils findHomePageRoute', () => { ).toEqual(homePage); }); - test('should find nested homepage with baseUrl', () => { + it('finds nested homepage with baseUrl', () => { const baseUrl = '/baseUrl/'; const baseUrlHomePage = {...homePage, path: baseUrl}; expect( diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts index 1aa50b54af24..a3ca5378268f 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts @@ -8,7 +8,7 @@ import {docVersionSearchTag} from '../searchUtils'; describe('docVersionSearchTag', () => { - test('behaves correctly', () => { + it('works', () => { expect(docVersionSearchTag('foo', 'bar')).toEqual('docs-foo-bar'); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts index a4ec4d13cecb..495adad67bba 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts @@ -13,7 +13,7 @@ describe('listTagsByLetters', () => { type Tag = Param[number]; type Result = ReturnType; - test('Should create letters list', () => { + it('creates letters list', () => { const tag1: Tag = { name: 'tag1', permalink: '/tag1', diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts index 0474ae9a5943..2ac8a63fd434 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts @@ -10,7 +10,7 @@ import {renderHook} from '@testing-library/react-hooks'; import {useFilteredAndTreeifiedTOC} from '../tocUtils'; describe('useFilteredAndTreeifiedTOC', () => { - test('filter a toc with all heading levels', () => { + it('filters a toc with all heading levels', () => { const toc: TOCItem[] = [ { id: 'alpha', @@ -137,7 +137,7 @@ describe('useFilteredAndTreeifiedTOC', () => { // It's not 100% clear exactly how the TOC should behave under weird heading // levels provided by the user. Adding a test so that behavior stays the same // over time - test('filter invalid heading levels (but possible) TOC', () => { + it('filters invalid heading levels (but possible) TOC', () => { const toc: TOCItem[] = [ { id: 'charlie', diff --git a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts index 0feddebd0f97..a855ccba3a5f 100644 --- a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts @@ -22,7 +22,7 @@ function testValidateThemeConfig(themeConfig) { } describe('validateThemeConfig', () => { - test('undefined config', () => { + it('undefined config', () => { const liveCodeBlock = undefined; expect(testValidateThemeConfig({liveCodeBlock})).toEqual({ liveCodeBlock: { @@ -31,7 +31,7 @@ describe('validateThemeConfig', () => { }); }); - test('unexist config', () => { + it('unexist config', () => { expect(testValidateThemeConfig({})).toEqual({ liveCodeBlock: { ...DEFAULT_CONFIG, @@ -39,7 +39,7 @@ describe('validateThemeConfig', () => { }); }); - test('empty config', () => { + it('empty config', () => { const liveCodeBlock = {}; expect(testValidateThemeConfig({liveCodeBlock})).toEqual({ liveCodeBlock: { @@ -48,7 +48,7 @@ describe('validateThemeConfig', () => { }); }); - test('playgroundPosition top', () => { + it('playgroundPosition top', () => { const liveCodeBlock = { playgroundPosition: 'top', }; @@ -60,7 +60,7 @@ describe('validateThemeConfig', () => { }); }); - test('playgroundPosition bottom', () => { + it('playgroundPosition bottom', () => { const liveCodeBlock = { playgroundPosition: 'bottom', }; @@ -72,7 +72,7 @@ describe('validateThemeConfig', () => { }); }); - test('playgroundPosition invalid string', () => { + it('playgroundPosition invalid string', () => { const liveCodeBlock = {playgroundPosition: 'invalid'}; expect(() => testValidateThemeConfig({liveCodeBlock}), @@ -80,7 +80,7 @@ describe('validateThemeConfig', () => { `"\\"liveCodeBlock.playgroundPosition\\" must be one of [top, bottom]"`, ); }); - test('playgroundPosition invalid boolean', () => { + it('playgroundPosition invalid boolean', () => { const liveCodeBlock = {playgroundPosition: true}; expect(() => testValidateThemeConfig({liveCodeBlock}), diff --git a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts index 09711b2f9146..7f753e496ef9 100644 --- a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts @@ -23,7 +23,7 @@ function testValidateThemeConfig(themeConfig: Record) { } describe('validateThemeConfig', () => { - test('minimal config', () => { + it('minimal config', () => { const algolia = { indexName: 'index', apiKey: 'apiKey', @@ -37,7 +37,7 @@ describe('validateThemeConfig', () => { }); }); - test('unknown attributes', () => { + it('unknown attributes', () => { const algolia = { indexName: 'index', apiKey: 'apiKey', @@ -52,7 +52,7 @@ describe('validateThemeConfig', () => { }); }); - test('undefined config', () => { + it('undefined config', () => { const algolia = undefined; expect(() => testValidateThemeConfig({algolia}), @@ -61,7 +61,7 @@ describe('validateThemeConfig', () => { ); }); - test('undefined config 2', () => { + it('undefined config 2', () => { expect(() => testValidateThemeConfig({}), ).toThrowErrorMatchingInlineSnapshot( @@ -69,7 +69,7 @@ describe('validateThemeConfig', () => { ); }); - test('missing indexName config', () => { + it('missing indexName config', () => { const algolia = {apiKey: 'apiKey', appId: 'BH4D9OD16A'}; expect(() => testValidateThemeConfig({algolia}), @@ -78,14 +78,14 @@ describe('validateThemeConfig', () => { ); }); - test('missing apiKey config', () => { + it('missing apiKey config', () => { const algolia = {indexName: 'indexName', appId: 'BH4D9OD16A'}; expect(() => testValidateThemeConfig({algolia}), ).toThrowErrorMatchingInlineSnapshot(`"\\"algolia.apiKey\\" is required"`); }); - test('missing appId config', () => { + it('missing appId config', () => { const algolia = {indexName: 'indexName', apiKey: 'apiKey'}; expect(() => testValidateThemeConfig({algolia}), @@ -94,7 +94,7 @@ describe('validateThemeConfig', () => { ); }); - test('contextualSearch config', () => { + it('contextualSearch config', () => { const algolia = { appId: 'BH4D9OD16A', indexName: 'index', @@ -109,7 +109,7 @@ describe('validateThemeConfig', () => { }); }); - test('externalUrlRegex config', () => { + it('externalUrlRegex config', () => { const algolia = { appId: 'BH4D9OD16A', indexName: 'index', @@ -124,7 +124,7 @@ describe('validateThemeConfig', () => { }); }); - test('searchParameters.facetFilters search config', () => { + it('searchParameters.facetFilters search config', () => { const algolia = { appId: 'BH4D9OD16A', indexName: 'index', diff --git a/packages/docusaurus-theme-translations/__tests__/update.test.ts b/packages/docusaurus-theme-translations/__tests__/update.test.ts index 23778fb85445..d9b23c69d003 100644 --- a/packages/docusaurus-theme-translations/__tests__/update.test.ts +++ b/packages/docusaurus-theme-translations/__tests__/update.test.ts @@ -14,29 +14,27 @@ import _ from 'lodash'; // Seems the 5s default timeout fails sometimes jest.setTimeout(15000); -describe('theme-translations package', () => { - test(`to have base messages files contain EXACTLY all the translations extracted from the theme. Please run "yarn workspace @docusaurus/theme-translations update" to keep base messages files up-to-date.`, async () => { +describe('theme translations', () => { + it('has base messages files contain EXACTLY all the translations extracted from the theme. Please run "yarn workspace @docusaurus/theme-translations update" to keep base messages files up-to-date', async () => { const baseMessagesDirPath = path.join(__dirname, '../locales/base'); const baseMessages = Object.fromEntries( - ( - await Promise.all( - ( - await fs.readdir(baseMessagesDirPath) - ).map(async (baseMessagesFile) => - Object.entries( - JSON.parse( - ( - await fs.readFile( - path.join(baseMessagesDirPath, baseMessagesFile), - ) - ).toString(), - ) as Record, - ), + await Promise.all( + ( + await fs.readdir(baseMessagesDirPath) + ).map(async (baseMessagesFile) => + Object.entries( + JSON.parse( + ( + await fs.readFile( + path.join(baseMessagesDirPath, baseMessagesFile), + ) + ).toString(), + ) as Record, ), - ) - ) - .flat() - .filter(([key]) => !key.endsWith('___DESCRIPTION')), + ), + ).then((translations) => + translations.flat().filter(([key]) => !key.endsWith('___DESCRIPTION')), + ), ); const codeMessages = _.mapValues( await extractThemeCodeMessages(), diff --git a/packages/docusaurus-theme-translations/src/__tests__/index.test.ts b/packages/docusaurus-theme-translations/src/__tests__/index.test.ts index 3607e0fda04f..5d7bb1199bdb 100644 --- a/packages/docusaurus-theme-translations/src/__tests__/index.test.ts +++ b/packages/docusaurus-theme-translations/src/__tests__/index.test.ts @@ -13,7 +13,7 @@ import { } from '../index'; describe('codeTranslationLocalesToTry', () => { - test('should return appropriate locale lists', () => { + it('returns appropriate locale lists', () => { expect(codeTranslationLocalesToTry('fr')).toEqual([ 'fr', 'fr-FR', @@ -56,7 +56,7 @@ describe('readDefaultCodeTranslationMessages', () => { ); } - test('for empty locale', async () => { + it('for empty locale', async () => { await expect( readDefaultCodeTranslationMessages({ locale: '', @@ -67,7 +67,7 @@ describe('readDefaultCodeTranslationMessages', () => { ); }); - test('for unexisting locale', async () => { + it('for unexisting locale', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'es', @@ -77,7 +77,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual({}); }); - test('for fr but bad folder', async () => { + it('for fr but bad folder', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'fr', @@ -87,7 +87,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual({}); }); - test('for fr', async () => { + it('for fr', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'fr', @@ -97,7 +97,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual(await readAsJSON('fr')); }); - test('for fr-FR', async () => { + it('for fr-FR', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'fr-FR', @@ -107,7 +107,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual(await readAsJSON('fr-FR')); }); - test('for en', async () => { + it('for en', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'en', @@ -117,7 +117,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual(await readAsJSON('en')); }); - test('for en-US', async () => { + it('for en-US', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'en-US', @@ -127,7 +127,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual(await readAsJSON('en')); }); - test('for en-WHATEVER', async () => { + it('for en-WHATEVER', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'en-WHATEVER', @@ -137,7 +137,7 @@ describe('readDefaultCodeTranslationMessages', () => { ).resolves.toEqual(await readAsJSON('en')); }); - test('default locale', async () => { + it('default locale', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'zh', diff --git a/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts b/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts index 810a700277b8..18afd34afc7c 100644 --- a/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts +++ b/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts @@ -17,13 +17,13 @@ function params( } describe('applyTrailingSlash', () => { - test('should apply to empty', () => { + it('applies to empty', () => { expect(applyTrailingSlash('', params(true))).toEqual('/'); expect(applyTrailingSlash('', params(false))).toEqual(''); expect(applyTrailingSlash('', params(undefined))).toEqual(''); }); - test('should not apply to /', () => { + it('does not apply to /', () => { expect(applyTrailingSlash('/', params(true))).toEqual('/'); expect(applyTrailingSlash('/', params(false))).toEqual('/'); expect(applyTrailingSlash('/', params(undefined))).toEqual('/'); @@ -39,7 +39,7 @@ describe('applyTrailingSlash', () => { ); }); - test('should not apply to /baseUrl/', () => { + it('does not apply to /baseUrl/', () => { const baseUrl = '/baseUrl/'; expect(applyTrailingSlash('/baseUrl/', params(true, baseUrl))).toEqual( '/baseUrl/', @@ -62,7 +62,7 @@ describe('applyTrailingSlash', () => { ).toEqual('/baseUrl/?query#anchor'); }); - test('should not apply to #anchor links', () => { + it('does not apply to #anchor links', () => { expect(applyTrailingSlash('#', params(true))).toEqual('#'); expect(applyTrailingSlash('#', params(false))).toEqual('#'); expect(applyTrailingSlash('#', params(undefined))).toEqual('#'); @@ -71,7 +71,7 @@ describe('applyTrailingSlash', () => { expect(applyTrailingSlash('#anchor', params(undefined))).toEqual('#anchor'); }); - test('should apply to simple paths', () => { + it('applies to simple paths', () => { expect(applyTrailingSlash('abc', params(true))).toEqual('abc/'); expect(applyTrailingSlash('abc', params(false))).toEqual('abc'); expect(applyTrailingSlash('abc', params(undefined))).toEqual('abc'); @@ -86,7 +86,7 @@ describe('applyTrailingSlash', () => { expect(applyTrailingSlash('/abc/', params(undefined))).toEqual('/abc/'); }); - test('should apply to path with #anchor', () => { + it('applies to path with #anchor', () => { expect(applyTrailingSlash('/abc#anchor', params(true))).toEqual( '/abc/#anchor', ); @@ -107,7 +107,7 @@ describe('applyTrailingSlash', () => { ); }); - test('should apply to path with ?search', () => { + it('applies to path with ?search', () => { expect(applyTrailingSlash('/abc?search', params(true))).toEqual( '/abc/?search', ); @@ -128,7 +128,7 @@ describe('applyTrailingSlash', () => { ); }); - test('should apply to path with ?search#anchor', () => { + it('applies to path with ?search#anchor', () => { expect(applyTrailingSlash('/abc?search#anchor', params(true))).toEqual( '/abc/?search#anchor', ); @@ -149,7 +149,7 @@ describe('applyTrailingSlash', () => { ).toEqual('/abc/?search#anchor'); }); - test('should apply to fully qualified urls', () => { + it('applies to fully qualified urls', () => { expect( applyTrailingSlash('https://xyz.com/abc?search#anchor', params(true)), ).toEqual('https://xyz.com/abc/?search#anchor'); diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index 0650b13f0ae1..e4882b22b35c 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -1,67 +1,67 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validation schemas AdmonitionsSchema: for value=[] 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=[] 1`] = `"\\"value\\" must be of type object"`; -exports[`validation schemas AdmonitionsSchema: for value=3 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=3 1`] = `"\\"value\\" must be of type object"`; -exports[`validation schemas AdmonitionsSchema: for value=null 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=null 1`] = `"\\"value\\" must be of type object"`; -exports[`validation schemas AdmonitionsSchema: for value=true 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=true 1`] = `"\\"value\\" must be of type object"`; -exports[`validation schemas PathnameSchema: for value="foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validation schemas pathnameSchema: for value="foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validation schemas PathnameSchema: for value="https://github.com/foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validation schemas pathnameSchema: for value="https://github.com/foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validation schemas PluginIdSchema: for value="/docs" 1`] = `"Illegal plugin ID value \\"/docs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="/docs" 1`] = `"Illegal plugin ID value \\"/docs\\": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas PluginIdSchema: for value="do cs" 1`] = `"Illegal plugin ID value \\"do cs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="do cs" 1`] = `"Illegal plugin ID value \\"do cs\\": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas PluginIdSchema: for value="do/cs" 1`] = `"Illegal plugin ID value \\"do/cs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="do/cs" 1`] = `"Illegal plugin ID value \\"do/cs\\": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas PluginIdSchema: for value="docs/" 1`] = `"Illegal plugin ID value \\"docs/\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="docs/" 1`] = `"Illegal plugin ID value \\"docs/\\": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas PluginIdSchema: for value=[] 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=[] 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas PluginIdSchema: for value=3 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=3 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas PluginIdSchema: for value=null 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=null 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas PluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas RehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas RehypePluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas RehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas RemarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas RemarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas RemarkPluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas RemarkPluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas URISchema: for value="spaces are invalid in a URL" 1`] = `"\\"value\\" does not look like a valid url (value='')"`; +exports[`validation schemas uRISchema: for value="spaces are invalid in a URL" 1`] = `"\\"value\\" does not look like a valid url (value='')"`; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts index 527304885749..6f6f28f31536 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts @@ -59,7 +59,7 @@ function testMarkdownPluginSchemas(schema: Joi.Schema) { } describe('validation schemas', () => { - test('PluginIdSchema', () => { + it('pluginIdSchema', () => { const {testOK, testFail} = createTestHelpers({ schema: PluginIdSchema, defaultValue: 'default', @@ -81,7 +81,7 @@ describe('validation schemas', () => { testFail([]); }); - test('AdmonitionsSchema', () => { + it('admonitionsSchema', () => { const {testOK, testFail} = createTestHelpers({ schema: AdmonitionsSchema, defaultValue: {}, @@ -97,15 +97,15 @@ describe('validation schemas', () => { testFail([]); }); - test('RemarkPluginsSchema', () => { + it('remarkPluginsSchema', () => { testMarkdownPluginSchemas(RemarkPluginsSchema); }); - test('RehypePluginsSchema', () => { + it('rehypePluginsSchema', () => { testMarkdownPluginSchemas(RehypePluginsSchema); }); - test('URISchema', () => { + it('uRISchema', () => { const {testFail, testOK} = createTestHelpers({schema: URISchema}); const validURL = 'https://docusaurus.io'; @@ -127,7 +127,7 @@ describe('validation schemas', () => { testOK(protocolRelativeUrl2); }); - test('PathnameSchema', () => { + it('pathnameSchema', () => { const {testFail, testOK} = createTestHelpers({schema: PathnameSchema}); testOK('/foo'); diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts index f52ec99b0bea..b67cba10415c 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts @@ -11,7 +11,7 @@ import {JoiFrontMatter} from '../JoiFrontMatter'; import {validateFrontMatter} from '../validationUtils'; describe('validateFrontMatter', () => { - test('should accept good values', () => { + it('accepts good values', () => { const schema = Joi.object<{test: string}>({ test: Joi.string(), }); @@ -21,7 +21,7 @@ describe('validateFrontMatter', () => { expect(validateFrontMatter(frontMatter, schema)).toEqual(frontMatter); }); - test('should reject bad values', () => { + it('rejects bad values', () => { const consoleError = jest .spyOn(console, 'error') .mockImplementation(() => {}); @@ -39,7 +39,7 @@ describe('validateFrontMatter', () => { ); }); - test('should not convert simple values', () => { + it('does not convert simple values', () => { const schema = Joi.object({ test: JoiFrontMatter.string(), }); @@ -53,7 +53,7 @@ describe('validateFrontMatter', () => { // Fix Yaml trying to convert strings to numbers automatically // We only want to deal with a single type in the final front matter // (not string | number) - test('should convert number values to string when string schema', () => { + it('converts number values to string when string schema', () => { const schema = Joi.object<{test: string}>({ test: JoiFrontMatter.string(), }); @@ -66,7 +66,7 @@ describe('validateFrontMatter', () => { // Helps to fix Yaml trying to convert strings to dates automatically // We only want to deal with a single type in the final front matter // (not string | Date) - test('should convert date values when string schema', () => { + it('converts date values when string schema', () => { const schema = Joi.object<{test: string}>({ test: JoiFrontMatter.string(), }); diff --git a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap new file mode 100644 index 000000000000..1d0e85e558c7 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap @@ -0,0 +1,136 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`replaceMarkdownLinks does basic replace 1`] = ` +Object { + "brokenMarkdownLinks": Array [ + Object { + "contentPaths": Object { + "contentPath": "docs", + "contentPathLocalized": "i18n/docs-localized", + }, + "filePath": "docs/intro.md", + "link": "hmmm.md", + }, + ], + "newContent": " +[foo](/doc/foo) +[baz](/doc/baz) +[foo](/doc/foo) +[http](http://github.com/facebook/docusaurus/README.md) +[https](https://github.com/facebook/docusaurus/README.md) +[asset](./foo.js) +[asset as well](@site/docs/_partial.md) +[looks like http...](/doc/http) +[nonexistent](hmmm.md) +", +} +`; + +exports[`replaceMarkdownLinks ignores links in HTML comments 1`] = ` +Object { + "brokenMarkdownLinks": Array [ + Object { + "contentPaths": Object { + "contentPath": "docs", + "contentPathLocalized": "i18n/docs-localized", + }, + "filePath": "docs/intro.md", + "link": "./foo.md", + }, + Object { + "contentPaths": Object { + "contentPath": "docs", + "contentPathLocalized": "i18n/docs-localized", + }, + "filePath": "docs/intro.md", + "link": "./foo.md", + }, + ], + "newContent": " + + +", +} +`; + +exports[`replaceMarkdownLinks ignores links in fenced blocks 1`] = ` +Object { + "brokenMarkdownLinks": Array [], + "newContent": " +\`\`\` +[foo](foo.md) +\`\`\` + +\`\`\`\`js +[foo](foo.md) +\`\`\` +[foo](foo.md) +\`\`\` +[foo](foo.md) +\`\`\`\` + +\`\`\`\`js +[foo](foo.md) +\`\`\` +[foo](foo.md) +\`\`\`\` +", +} +`; + +exports[`replaceMarkdownLinks ignores links in inline code 1`] = ` +Object { + "brokenMarkdownLinks": Array [ + Object { + "contentPaths": Object { + "contentPath": "docs", + "contentPathLocalized": "i18n/docs-localized", + }, + "filePath": "docs/intro.md", + "link": "foo.md", + }, + ], + "newContent": " +\`[foo](foo.md)\` +", +} +`; + +exports[`replaceMarkdownLinks replaces links with same title as URL 1`] = ` +Object { + "brokenMarkdownLinks": Array [], + "newContent": " +[/docs/foo](foo.md) +[/docs/foo](./foo.md) +[foo.md](/docs/foo) +[.//docs/foo](foo.md) +", +} +`; + +exports[`replaceMarkdownLinks replaces multiple links on same line 1`] = ` +Object { + "brokenMarkdownLinks": Array [], + "newContent": " +[a](/docs/a), [a](/docs/a), [b](/docs/b), [c](/docs/c) +", +} +`; + +exports[`replaceMarkdownLinks replaces reference style Markdown links 1`] = ` +Object { + "brokenMarkdownLinks": Array [], + "newContent": " +The following operations are defined for [URI]s: + +* [info]: Returns metadata about the resource, +* [list]: Returns metadata about the resource's children (like getting the content of a local directory). + +[URI]: /docs/api/classes/uri +[info]: /docs/api/classes/uri#info +[list]: /docs/api/classes/uri#list + ", +} +`; diff --git a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap new file mode 100644 index 000000000000..50b866f0b5e2 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap @@ -0,0 +1,200 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseMarkdownString deletes only first heading 1`] = ` +Object { + "content": "# Markdown Title + +test test test # test bar + +# Markdown Title 2 + +### Markdown Title h3", + "contentTitle": "Markdown Title", + "excerpt": "test test test # test bar", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString deletes only first heading 2 1`] = ` +Object { + "content": "# test + +test test test test test test +test test test # test bar +# test2 +### test +test3", + "contentTitle": "test", + "excerpt": "test test test test test test", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString does not warn for duplicate title if markdown title is not at the top 1`] = ` +Object { + "content": "foo + +# Markdown Title", + "contentTitle": undefined, + "excerpt": "foo", + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; + +exports[`parseMarkdownString handles code blocks 1`] = ` +Object { + "content": "\`\`\`js +code +\`\`\` + +Content", + "contentTitle": undefined, + "excerpt": "Content", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString handles code blocks 2`] = ` +Object { + "content": "\`\`\`\`js +Foo +\`\`\`diff +code +\`\`\` +Bar +\`\`\`\` + +Content", + "contentTitle": undefined, + "excerpt": "Content", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString handles code blocks 3`] = ` +Object { + "content": "\`\`\`\`js +Foo +\`\`\`diff +code +\`\`\`\` + +Content", + "contentTitle": undefined, + "excerpt": "Content", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString ignores markdown title if its not a first text 1`] = ` +Object { + "content": "foo +# test", + "contentTitle": undefined, + "excerpt": "foo", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString parse markdown with front matter 1`] = ` +Object { + "content": "Some text", + "contentTitle": undefined, + "excerpt": "Some text", + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; + +exports[`parseMarkdownString parses first heading as contentTitle 1`] = ` +Object { + "content": "# Markdown Title + +Some text", + "contentTitle": "Markdown Title", + "excerpt": "Some text", + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString parses front-matter and ignore h2 1`] = ` +Object { + "content": "## test", + "contentTitle": undefined, + "excerpt": "test", + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; + +exports[`parseMarkdownString parses title only 1`] = ` +Object { + "content": "# test", + "contentTitle": "test", + "excerpt": undefined, + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString parses title only alternate 1`] = ` +Object { + "content": "test +===", + "contentTitle": "test", + "excerpt": undefined, + "frontMatter": Object {}, +} +`; + +exports[`parseMarkdownString reads front matter only 1`] = ` +Object { + "content": "", + "contentTitle": undefined, + "excerpt": undefined, + "frontMatter": Object { + "title": "test", + }, +} +`; + +exports[`parseMarkdownString warns about duplicate titles (front matter + markdown alternate) 1`] = ` +Object { + "content": "Markdown Title alternate +================ + +Some text", + "contentTitle": "Markdown Title alternate", + "excerpt": "Some text", + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; + +exports[`parseMarkdownString warns about duplicate titles (front matter + markdown) 1`] = ` +Object { + "content": "# Markdown Title + +Some text", + "contentTitle": "Markdown Title", + "excerpt": "Some text", + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; + +exports[`parseMarkdownString warns about duplicate titles 1`] = ` +Object { + "content": "# test", + "contentTitle": "test", + "excerpt": undefined, + "frontMatter": Object { + "title": "Frontmatter title", + }, +} +`; diff --git a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts index f58a155e9992..689e338f6cff 100644 --- a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts @@ -22,7 +22,7 @@ describe('getDataFilePath', () => { const contentPathEmpty = path.join(fixturesDir, 'contentPathEmpty'); const contentPathNestedYml = path.join(fixturesDir, 'contentPathNestedYml'); - test('getDataFilePath returns localized Yml path in priority', async () => { + it('getDataFilePath returns localized Yml path in priority', async () => { await expect( getDataFilePath({ filePath: 'authors.yml', @@ -43,7 +43,7 @@ describe('getDataFilePath', () => { ).resolves.toEqual(path.join(contentPathYml2, 'authors.yml')); }); - test('getDataFilePath returns localized Json path in priority', async () => { + it('getDataFilePath returns localized Json path in priority', async () => { await expect( getDataFilePath({ filePath: 'authors.json', @@ -64,7 +64,7 @@ describe('getDataFilePath', () => { ).resolves.toEqual(path.join(contentPathJson2, 'authors.json')); }); - test('getDataFilePath returns unlocalized Yml path as fallback', async () => { + it('getDataFilePath returns unlocalized Yml path as fallback', async () => { await expect( getDataFilePath({ filePath: 'authors.yml', @@ -76,7 +76,7 @@ describe('getDataFilePath', () => { ).resolves.toEqual(path.join(contentPathYml2, 'authors.yml')); }); - test('getDataFilePath returns unlocalized Json path as fallback', async () => { + it('getDataFilePath returns unlocalized Json path as fallback', async () => { await expect( getDataFilePath({ filePath: 'authors.json', @@ -88,7 +88,7 @@ describe('getDataFilePath', () => { ).resolves.toEqual(path.join(contentPathJson1, 'authors.json')); }); - test('getDataFilePath can return undefined (file not found)', async () => { + it('getDataFilePath can return undefined (file not found)', async () => { await expect( getDataFilePath({ filePath: 'authors.json', @@ -109,7 +109,7 @@ describe('getDataFilePath', () => { ).resolves.toBeUndefined(); }); - test('getDataFilePath can return nested path', async () => { + it('getDataFilePath can return nested path', async () => { await expect( getDataFilePath({ filePath: 'sub/folder/authors.yml', @@ -143,25 +143,25 @@ describe('getDataFileData', () => { ); } - test('returns undefined for nonexistent file', async () => { + it('returns undefined for nonexistent file', async () => { await expect(readDataFile('nonexistent.yml')).resolves.toBeUndefined(); }); - test('read valid yml author file', async () => { + it('read valid yml author file', async () => { await expect(readDataFile('valid.yml')).resolves.toEqual({a: 1}); }); - test('read valid json author file', async () => { + it('read valid json author file', async () => { await expect(readDataFile('valid.json')).resolves.toEqual({a: 1}); }); - test('fail to read invalid yml', async () => { + it('fail to read invalid yml', async () => { await expect( readDataFile('bad.yml'), ).rejects.toThrowErrorMatchingInlineSnapshot(`"Nope"`); }); - test('fail to read invalid json', async () => { + it('fail to read invalid json', async () => { await expect( readDataFile('bad.json'), ).rejects.toThrowErrorMatchingInlineSnapshot(`"Nope"`); @@ -169,7 +169,7 @@ describe('getDataFileData', () => { }); describe('findFolderContainingFile', () => { - test('find appropriate folder', async () => { + it('find appropriate folder', async () => { await expect( findFolderContainingFile( ['/abcdef', '/gehij', __dirname, '/klmn'], @@ -178,7 +178,7 @@ describe('findFolderContainingFile', () => { ).resolves.toEqual(__dirname); }); - test('return undefined if no folder contain such file', async () => { + it('return undefined if no folder contain such file', async () => { await expect( findFolderContainingFile(['/abcdef', '/gehij', '/klmn'], 'index.test.ts'), ).resolves.toBeUndefined(); @@ -186,7 +186,7 @@ describe('findFolderContainingFile', () => { }); describe('getFolderContainingFile', () => { - test('get appropriate folder', async () => { + it('get appropriate folder', async () => { await expect( getFolderContainingFile( ['/abcdef', '/gehij', __dirname, '/klmn'], @@ -195,7 +195,7 @@ describe('getFolderContainingFile', () => { ).resolves.toEqual(__dirname); }); - test('throw if no folder contain such file', async () => { + it('throw if no folder contain such file', async () => { await expect( getFolderContainingFile( ['/abcdef', '/gehij', '/klmn'], diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 8f10d21b1a7e..7ee81d98e436 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -10,53 +10,57 @@ import {genChunkName, readOutputHTMLFile, generate} from '../emitUtils'; import path from 'path'; import fs from 'fs-extra'; -test('genChunkName', () => { - const firstAssert: Record = { - '/docs/adding-blog': 'docs-adding-blog-062', - '/docs/versioning': 'docs-versioning-8a8', - '/': 'index', - '/blog/2018/04/30/How-I-Converted-Profilo-To-Docusaurus': - 'blog-2018-04-30-how-i-converted-profilo-to-docusaurus-4f2', - '/youtube': 'youtube-429', - '/users/en/': 'users-en-f7a', - '/blog': 'blog-c06', - }; - Object.keys(firstAssert).forEach((str) => { - expect(genChunkName(str)).toBe(firstAssert[str]); +describe('genChunkName', () => { + it('works', () => { + const firstAssert: Record = { + '/docs/adding-blog': 'docs-adding-blog-062', + '/docs/versioning': 'docs-versioning-8a8', + '/': 'index', + '/blog/2018/04/30/How-I-Converted-Profilo-To-Docusaurus': + 'blog-2018-04-30-how-i-converted-profilo-to-docusaurus-4f2', + '/youtube': 'youtube-429', + '/users/en/': 'users-en-f7a', + '/blog': 'blog-c06', + }; + Object.keys(firstAssert).forEach((str) => { + expect(genChunkName(str)).toBe(firstAssert[str]); + }); }); - // Don't allow different chunk name for same path. - expect(genChunkName('path/is/similar', 'oldPrefix')).toEqual( - genChunkName('path/is/similar', 'newPrefix'), - ); + it("doesn't allow different chunk name for same path", () => { + expect(genChunkName('path/is/similar', 'oldPrefix')).toEqual( + genChunkName('path/is/similar', 'newPrefix'), + ); + }); - // Even with same preferred name, still different chunk name for - // different path - const secondAssert: Record = { - '/blog/1': 'blog-85-f-089', - '/blog/2': 'blog-353-489', - }; - Object.keys(secondAssert).forEach((str) => { - expect(genChunkName(str, undefined, 'blog')).toBe(secondAssert[str]); + it('emits different chunk names for different paths even with same preferred name', () => { + const secondAssert: Record = { + '/blog/1': 'blog-85-f-089', + '/blog/2': 'blog-353-489', + }; + Object.keys(secondAssert).forEach((str) => { + expect(genChunkName(str, undefined, 'blog')).toBe(secondAssert[str]); + }); }); - // Only generate short unique id - const thirdAssert: Record = { - a: '0cc175b9', - b: '92eb5ffe', - c: '4a8a08f0', - d: '8277e091', - }; - Object.keys(thirdAssert).forEach((str) => { - expect(genChunkName(str, undefined, undefined, true)).toBe( - thirdAssert[str], - ); + it('only generates short unique IDs', () => { + const thirdAssert: Record = { + a: '0cc175b9', + b: '92eb5ffe', + c: '4a8a08f0', + d: '8277e091', + }; + Object.keys(thirdAssert).forEach((str) => { + expect(genChunkName(str, undefined, undefined, true)).toBe( + thirdAssert[str], + ); + }); + expect(genChunkName('d', undefined, undefined, true)).toBe('8277e091'); }); - expect(genChunkName('d', undefined, undefined, true)).toBe('8277e091'); }); describe('readOutputHTMLFile', () => { - test('trailing slash undefined', async () => { + it('trailing slash undefined', async () => { await expect( readOutputHTMLFile( '/file', @@ -86,7 +90,7 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toEqual('folder\n'); }); - test('trailing slash true', async () => { + it('trailing slash true', async () => { await expect( readOutputHTMLFile( '/folder', @@ -102,7 +106,7 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toEqual('folder\n'); }); - test('trailing slash false', async () => { + it('trailing slash false', async () => { await expect( readOutputHTMLFile( '/file', @@ -120,36 +124,40 @@ describe('readOutputHTMLFile', () => { }); }); -test('generate', async () => { +describe('generate', () => { const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {}); const existsMock = jest.spyOn(fs, 'pathExists'); const readMock = jest.spyOn(fs, 'readFile'); - // First call: no file, no cache - existsMock.mockImplementationOnce(() => false); - await generate(__dirname, 'foo', 'bar'); - expect(writeMock).toHaveBeenNthCalledWith( - 1, - path.join(__dirname, 'foo'), - 'bar', - ); + it('works with no file and no cache', async () => { + existsMock.mockImplementationOnce(() => false); + await generate(__dirname, 'foo', 'bar'); + expect(writeMock).toHaveBeenNthCalledWith( + 1, + path.join(__dirname, 'foo'), + 'bar', + ); + }); - // Second call: cache exists - await generate(__dirname, 'foo', 'bar'); - expect(writeMock).toBeCalledTimes(1); + it('works with existing cache', async () => { + await generate(__dirname, 'foo', 'bar'); + expect(writeMock).toBeCalledTimes(1); + }); - // Generate another: file exists, cache doesn't - existsMock.mockImplementationOnce(() => true); - // @ts-expect-error: seems the typedef doesn't understand overload - readMock.mockImplementationOnce(() => Promise.resolve('bar')); - await generate(__dirname, 'baz', 'bar'); - expect(writeMock).toBeCalledTimes(1); + it('works with existing file but no cache', async () => { + existsMock.mockImplementationOnce(() => true); + // @ts-expect-error: seems the typedef doesn't understand overload + readMock.mockImplementationOnce(() => Promise.resolve('bar')); + await generate(__dirname, 'baz', 'bar'); + expect(writeMock).toBeCalledTimes(1); + }); - // Generate again: force skip cache - await generate(__dirname, 'foo', 'bar', true); - expect(writeMock).toHaveBeenNthCalledWith( - 2, - path.join(__dirname, 'foo'), - 'bar', - ); + it('works when force skipping cache', async () => { + await generate(__dirname, 'foo', 'bar', true); + expect(writeMock).toHaveBeenNthCalledWith( + 2, + path.join(__dirname, 'foo'), + 'bar', + ); + }); }); diff --git a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts index 95555e08d788..9bcac88b84aa 100644 --- a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts @@ -14,7 +14,7 @@ import { describe('createMatcher', () => { const matcher = createMatcher(GlobExcludeDefault); - test('match default exclude MD/MDX partials correctly', () => { + it('match default exclude MD/MDX partials correctly', () => { expect(matcher('doc.md')).toEqual(false); expect(matcher('category/doc.md')).toEqual(false); expect(matcher('category/subcategory/doc.md')).toEqual(false); @@ -31,7 +31,7 @@ describe('createMatcher', () => { expect(matcher('category/_subcategory/doc.md')).toEqual(true); }); - test('match default exclude tests correctly', () => { + it('match default exclude tests correctly', () => { expect(matcher('xyz.js')).toEqual(false); expect(matcher('xyz.ts')).toEqual(false); expect(matcher('xyz.jsx')).toEqual(false); @@ -73,7 +73,7 @@ describe('createAbsoluteFilePathMatcher', () => { rootFolders, ); - test('match default exclude MD/MDX partials correctly', () => { + it('match default exclude MD/MDX partials correctly', () => { expect(matcher('/_root/docs/myDoc.md')).toEqual(false); expect(matcher('/_root/docs/myDoc.mdx')).toEqual(false); expect(matcher('/root/_docs/myDoc.md')).toEqual(false); @@ -93,13 +93,13 @@ describe('createAbsoluteFilePathMatcher', () => { expect(matcher('/root/_docs/_category/myDoc.mdx')).toEqual(true); }); - test('match default exclude tests correctly', () => { + it('match default exclude tests correctly', () => { expect(matcher('/__test__/website/src/xyz.js')).toEqual(false); expect(matcher('/__test__/website/src/__test__/xyz.js')).toEqual(true); expect(matcher('/__test__/website/src/xyz.test.js')).toEqual(true); }); - test('throw if file is not contained in any root doc', () => { + it('throw if file is not contained in any root doc', () => { expect(() => matcher('/bad/path/myDoc.md'), ).toThrowErrorMatchingInlineSnapshot( diff --git a/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts b/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts index 4fae659dae6b..ab73d5073701 100644 --- a/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts @@ -8,7 +8,7 @@ import {simpleHash, docuHash} from '../hashUtils'; describe('hashUtils', () => { - test('simpleHash', () => { + it('simpleHash', () => { const asserts: Record = { '': 'd41', '/foo-bar': '096', @@ -29,7 +29,7 @@ describe('hashUtils', () => { }); describe('docuHash', () => { - test('docuHash works', () => { + it('docuHash works', () => { const asserts: Record = { '': '-d41', '/': 'index', diff --git a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts index 39fc8aae7be5..b5321520b6b2 100644 --- a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts @@ -11,52 +11,56 @@ import { getPluginI18nPath, } from '../i18nUtils'; -test('mergeTranslations', () => { - expect( - mergeTranslations([ - { - T1: {message: 'T1 message', description: 'T1 desc'}, - T2: {message: 'T2 message', description: 'T2 desc'}, - T3: {message: 'T3 message', description: 'T3 desc'}, - }, - { - T4: {message: 'T4 message', description: 'T4 desc'}, - }, - {T2: {message: 'T2 message 2', description: 'T2 desc 2'}}, - ]), - ).toEqual({ - T1: {message: 'T1 message', description: 'T1 desc'}, - T2: {message: 'T2 message 2', description: 'T2 desc 2'}, - T3: {message: 'T3 message', description: 'T3 desc'}, - T4: {message: 'T4 message', description: 'T4 desc'}, +describe('mergeTranslations', () => { + it('works', () => { + expect( + mergeTranslations([ + { + T1: {message: 'T1 message', description: 'T1 desc'}, + T2: {message: 'T2 message', description: 'T2 desc'}, + T3: {message: 'T3 message', description: 'T3 desc'}, + }, + { + T4: {message: 'T4 message', description: 'T4 desc'}, + }, + {T2: {message: 'T2 message 2', description: 'T2 desc 2'}}, + ]), + ).toEqual({ + T1: {message: 'T1 message', description: 'T1 desc'}, + T2: {message: 'T2 message 2', description: 'T2 desc 2'}, + T3: {message: 'T3 message', description: 'T3 desc'}, + T4: {message: 'T4 message', description: 'T4 desc'}, + }); }); }); -test('updateTranslationFileMessages', () => { - expect( - updateTranslationFileMessages( - { - path: 'abc', - content: { - t1: {message: 't1 message', description: 't1 desc'}, - t2: {message: 't2 message', description: 't2 desc'}, - t3: {message: 't3 message', description: 't3 desc'}, +describe('updateTranslationFileMessages', () => { + it('works', () => { + expect( + updateTranslationFileMessages( + { + path: 'abc', + content: { + t1: {message: 't1 message', description: 't1 desc'}, + t2: {message: 't2 message', description: 't2 desc'}, + t3: {message: 't3 message', description: 't3 desc'}, + }, }, + (message) => `prefix ${message} suffix`, + ), + ).toEqual({ + path: 'abc', + content: { + t1: {message: 'prefix t1 message suffix', description: 't1 desc'}, + t2: {message: 'prefix t2 message suffix', description: 't2 desc'}, + t3: {message: 'prefix t3 message suffix', description: 't3 desc'}, }, - (message) => `prefix ${message} suffix`, - ), - ).toEqual({ - path: 'abc', - content: { - t1: {message: 'prefix t1 message suffix', description: 't1 desc'}, - t2: {message: 'prefix t2 message suffix', description: 't2 desc'}, - t3: {message: 'prefix t3 message suffix', description: 't3 desc'}, - }, + }); }); }); describe('getPluginI18nPath', () => { - test('gets correct path', () => { + it('gets correct path', () => { expect( getPluginI18nPath({ siteDir: __dirname, @@ -69,7 +73,7 @@ describe('getPluginI18nPath', () => { `"/packages/docusaurus-utils/src/__tests__/i18n/zh-Hans/plugin-content-docs-community/foo"`, ); }); - test('gets correct path for default plugin', () => { + it('gets correct path for default plugin', () => { expect( getPluginI18nPath({ siteDir: __dirname, @@ -79,7 +83,7 @@ describe('getPluginI18nPath', () => { }).replace(__dirname, ''), ).toMatchInlineSnapshot(`"/i18n/zh-Hans/plugin-content-docs/foo"`); }); - test('gets correct path when no subpaths', () => { + it('gets correct path when no subpaths', () => { expect( getPluginI18nPath({ siteDir: __dirname, diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index acba208ffbc0..2716091437ee 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -17,37 +17,29 @@ import { import _ from 'lodash'; describe('removeSuffix', () => { - test('should no-op 1', () => { + it("is no-op when suffix doesn't exist", () => { expect(removeSuffix('abcdef', 'ijk')).toEqual('abcdef'); - }); - test('should no-op 2', () => { expect(removeSuffix('abcdef', 'abc')).toEqual('abcdef'); - }); - test('should no-op 3', () => { expect(removeSuffix('abcdef', '')).toEqual('abcdef'); }); - test('should remove suffix', () => { + it('removes suffix', () => { expect(removeSuffix('abcdef', 'ef')).toEqual('abcd'); }); }); describe('removePrefix', () => { - test('should no-op 1', () => { + it("is no-op when prefix doesn't exist", () => { expect(removePrefix('abcdef', 'ijk')).toEqual('abcdef'); - }); - test('should no-op 2', () => { expect(removePrefix('abcdef', 'def')).toEqual('abcdef'); - }); - test('should no-op 3', () => { expect(removePrefix('abcdef', '')).toEqual('abcdef'); }); - test('should remove prefix', () => { + it('removes prefix', () => { expect(removePrefix('abcdef', 'ab')).toEqual('cdef'); }); }); describe('getElementsAround', () => { - test('can return elements around', () => { + it('returns elements around', () => { expect(getElementsAround(['a', 'b', 'c', 'd'], 0)).toEqual({ previous: undefined, next: 'b', @@ -66,7 +58,7 @@ describe('getElementsAround', () => { }); }); - test('throws if bad index is provided', () => { + it('throws if bad index is provided', () => { expect(() => getElementsAround(['a', 'b', 'c', 'd'], -1), ).toThrowErrorMatchingInlineSnapshot( @@ -87,7 +79,7 @@ describe('mapAsyncSequential', () => { }); } - test('map sequentially', async () => { + it('maps sequentially', async () => { const itemToTimeout: Record = { '1': 200, '2': 600, @@ -132,7 +124,7 @@ describe('findAsyncSequential', () => { }); } - test('find sequentially', async () => { + it('finds sequentially', async () => { const items = ['1', '2', '3']; const findFn = jest.fn(async (item: string) => { @@ -155,7 +147,7 @@ describe('findAsyncSequential', () => { }); describe('reportMessage', () => { - test('all severities', () => { + it('works with all severities', () => { const consoleLog = jest.spyOn(console, 'info').mockImplementation(() => {}); const consoleWarn = jest .spyOn(console, 'warn') diff --git a/packages/docusaurus-utils/src/__tests__/markdownLinks.test.ts b/packages/docusaurus-utils/src/__tests__/markdownLinks.test.ts index 8bc7fac4ee2f..586a0ab7302d 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownLinks.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownLinks.test.ts @@ -8,7 +8,7 @@ import {replaceMarkdownLinks} from '../markdownLinks'; describe('replaceMarkdownLinks', () => { - test('basic replace', () => { + it('does basic replace', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -35,34 +35,10 @@ describe('replaceMarkdownLinks', () => { [nonexistent](hmmm.md) `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { - "contentPath": "docs", - "contentPathLocalized": "i18n/docs-localized", - }, - "filePath": "docs/intro.md", - "link": "hmmm.md", - }, - ], - "newContent": " - [foo](/doc/foo) - [baz](/doc/baz) - [foo](/doc/foo) - [http](http://github.com/facebook/docusaurus/README.md) - [https](https://github.com/facebook/docusaurus/README.md) - [asset](./foo.js) - [asset as well](@site/docs/_partial.md) - [looks like http...](/doc/http) - [nonexistent](hmmm.md) - ", - } - `); + ).toMatchSnapshot(); }); - test('reference style Markdown links', () => { + it('replaces reference style Markdown links', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -88,25 +64,11 @@ The following operations are defined for [URI]s: [list]: ../api/classes/divine_uri.URI.md#list `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [], - "newContent": " - The following operations are defined for [URI]s: - - * [info]: Returns metadata about the resource, - * [list]: Returns metadata about the resource's children (like getting the content of a local directory). - - [URI]: /docs/api/classes/uri - [info]: /docs/api/classes/uri#info - [list]: /docs/api/classes/uri#list - ", - } - `); + ).toMatchSnapshot(); }); // TODO bad - test('links in HTML comments', () => { + it('ignores links in HTML comments', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -125,37 +87,10 @@ The following operations are defined for [URI]s: --> `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { - "contentPath": "docs", - "contentPathLocalized": "i18n/docs-localized", - }, - "filePath": "docs/intro.md", - "link": "./foo.md", - }, - Object { - "contentPaths": Object { - "contentPath": "docs", - "contentPathLocalized": "i18n/docs-localized", - }, - "filePath": "docs/intro.md", - "link": "./foo.md", - }, - ], - "newContent": " - - - ", - } - `); + ).toMatchSnapshot(); }); - test('links in fenced blocks', () => { + it('ignores links in fenced blocks', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -187,34 +122,11 @@ The following operations are defined for [URI]s: \`\`\`\` `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [], - "newContent": " - \`\`\` - [foo](foo.md) - \`\`\` - - \`\`\`\`js - [foo](foo.md) - \`\`\` - [foo](foo.md) - \`\`\` - [foo](foo.md) - \`\`\`\` - - \`\`\`\`js - [foo](foo.md) - \`\`\` - [foo](foo.md) - \`\`\`\` - ", - } - `); + ).toMatchSnapshot(); }); // TODO bad - test('links in inline code', () => { + it('ignores links in inline code', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -230,27 +142,11 @@ The following operations are defined for [URI]s: \`[foo](foo.md)\` `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { - "contentPath": "docs", - "contentPathLocalized": "i18n/docs-localized", - }, - "filePath": "docs/intro.md", - "link": "foo.md", - }, - ], - "newContent": " - \`[foo](foo.md)\` - ", - } - `); + ).toMatchSnapshot(); }); // TODO bad - test('links with same title as URL', () => { + it('replaces links with same title as URL', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -270,20 +166,10 @@ The following operations are defined for [URI]s: [./foo.md](foo.md) `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [], - "newContent": " - [/docs/foo](foo.md) - [/docs/foo](./foo.md) - [foo.md](/docs/foo) - [.//docs/foo](foo.md) - ", - } - `); + ).toMatchSnapshot(); }); - test('multiple links on same line', () => { + it('replaces multiple links on same line', () => { expect( replaceMarkdownLinks({ siteDir: '.', @@ -302,13 +188,6 @@ The following operations are defined for [URI]s: [a](a.md), [a](a.md), [b](b.md), [c](c.md) `, }), - ).toMatchInlineSnapshot(` - Object { - "brokenMarkdownLinks": Array [], - "newContent": " - [a](/docs/a), [a](/docs/a), [b](/docs/b), [c](/docs/c) - ", - } - `); + ).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts index 1943593c3c7b..e928c02fc0c5 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts @@ -14,7 +14,7 @@ import { import dedent from 'dedent'; describe('createExcerpt', () => { - test('should create excerpt for text-only content', () => { + it('creates excerpt for text-only content', () => { expect( createExcerpt(dedent` Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo. @@ -26,7 +26,7 @@ describe('createExcerpt', () => { ); }); - test('should create excerpt for regular content with regular title', () => { + it('creates excerpt for regular content with regular title', () => { expect( createExcerpt(dedent` @@ -43,7 +43,7 @@ describe('createExcerpt', () => { ); }); - test('should create excerpt for regular content with alternate title', () => { + it('creates excerpt for regular content with alternate title', () => { expect( createExcerpt(dedent` @@ -61,7 +61,7 @@ describe('createExcerpt', () => { ); }); - test('should create excerpt for content with h2 heading', () => { + it('creates excerpt for content with h2 heading', () => { expect( createExcerpt(dedent` ## Lorem ipsum dolor sit amet @@ -71,7 +71,7 @@ describe('createExcerpt', () => { ).toEqual('Lorem ipsum dolor sit amet'); }); - test('should create excerpt for content beginning with blockquote', () => { + it('creates excerpt for content beginning with blockquote', () => { expect( createExcerpt(dedent` > Lorem ipsum dolor sit amet @@ -81,7 +81,7 @@ describe('createExcerpt', () => { ).toEqual('Lorem ipsum dolor sit amet'); }); - test('should create excerpt for content beginning with image (eg. blog post)', () => { + it('creates excerpt for content beginning with image (eg. blog post)', () => { expect( createExcerpt(dedent` ![Lorem ipsum](/img/lorem-ipsum.svg) @@ -89,7 +89,7 @@ describe('createExcerpt', () => { ).toEqual('Lorem ipsum'); }); - test('should create excerpt for content beginning with admonitions', () => { + it('creates excerpt for content beginning with admonitions', () => { expect( createExcerpt(dedent` import Component from '@site/src/components/Component' @@ -105,7 +105,7 @@ describe('createExcerpt', () => { ).toEqual('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); }); - test('should create excerpt for content with imports/exports declarations and Markdown markup, as well as Emoji', () => { + it('creates excerpt for content with imports/exports declarations and Markdown markup, as well as Emoji', () => { expect( createExcerpt(dedent` import Component from '@site/src/components/Component'; @@ -125,7 +125,7 @@ describe('createExcerpt', () => { ); }); - test('should create excerpt for heading specified with anchor-id syntax', () => { + it('creates excerpt for heading specified with anchor-id syntax', () => { expect( createExcerpt(dedent` ## Markdown title {#my-anchor-id} @@ -133,7 +133,7 @@ describe('createExcerpt', () => { ).toEqual('Markdown title'); }); - test('should create excerpt for content with various code blocks', () => { + it('creates excerpt for content with various code blocks', () => { expect( createExcerpt(dedent` \`\`\`jsx @@ -148,7 +148,7 @@ describe('createExcerpt', () => { }); describe('parseMarkdownContentTitle', () => { - test('Should parse markdown h1 title at the top', () => { + it('parses markdown h1 title at the top', () => { const markdown = dedent` # Markdown Title @@ -162,7 +162,7 @@ describe('parseMarkdownContentTitle', () => { }); }); - test('Should parse markdown h1 title at the top and remove it', () => { + it('parses markdown h1 title at the top and remove it', () => { const markdown = dedent` # Markdown Title @@ -178,7 +178,7 @@ describe('parseMarkdownContentTitle', () => { }); }); - test('Should parse markdown h1 title at the top and unwrap inline code block', () => { + it('parses markdown h1 title at the top and unwrap inline code block', () => { const markdown = dedent` # \`Markdown Title\` @@ -192,7 +192,7 @@ describe('parseMarkdownContentTitle', () => { }); }); - test('Should parse markdown h1 title and trim content', () => { + it('parses markdown h1 title and trim content', () => { const markdown = ` # Markdown Title @@ -209,7 +209,7 @@ Lorem Ipsum }); }); - test('Should parse not parse markdown h1 title and trim content', () => { + it('parses not parse markdown h1 title and trim content', () => { const markdown = ` Lorem Ipsum @@ -222,7 +222,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title with fixed anchor-id syntax', () => { + it('parses markdown h1 title with fixed anchor-id syntax', () => { const markdown = dedent` # Markdown Title {#my-anchor-id} @@ -236,7 +236,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title at the top (atx style with closing #)', () => { + it('parses markdown h1 title at the top (atx style with closing #)', () => { const markdown = dedent` # Markdown Title # @@ -250,7 +250,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title at the top followed by h2 title', () => { + it('parses markdown h1 title at the top followed by h2 title', () => { const markdown = dedent` # Markdown Title @@ -266,7 +266,7 @@ Lorem Ipsum }); }); - test('Should parse only first h1 title', () => { + it('parses only first h1 title', () => { const markdown = dedent` # Markdown Title @@ -282,7 +282,7 @@ Lorem Ipsum }); }); - test('Should not parse title that is not at the top', () => { + it('does not parse title that is not at the top', () => { const markdown = dedent` Lorem Ipsum @@ -298,7 +298,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 alternate title', () => { + it('parses markdown h1 alternate title', () => { const markdown = dedent` Markdown Title @@ -313,7 +313,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 alternate title and remove it', () => { + it('parses markdown h1 alternate title and remove it', () => { const markdown = dedent` Markdown Title @@ -330,7 +330,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title placed after import declarations', () => { + it('parses markdown h1 title placed after import declarations', () => { const markdown = dedent` import Component1 from '@site/src/components/Component1'; @@ -351,7 +351,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title placed after various import declarations', () => { + it('parses markdown h1 title placed after various import declarations', () => { const markdown = ` import DefaultComponent from '@site/src/components/Component1'; import DefaultComponent2 from '../relative/path/Component2'; @@ -379,7 +379,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title placed after various import declarations and remove it', () => { + it('parses markdown h1 title placed after various import declarations and remove it', () => { const markdown = ` import DefaultComponent from '@site/src/components/Component1'; import DefaultComponent2 from '../relative/path/Component2'; @@ -409,7 +409,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 alternate title placed after import declarations', () => { + it('parses markdown h1 alternate title placed after import declarations', () => { const markdown = dedent` import Component from '@site/src/components/Component'; @@ -428,7 +428,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 alternate title placed after import declarations and remove it', () => { + it('parses markdown h1 alternate title placed after import declarations and remove it', () => { const markdown = dedent` import Component from '@site/src/components/Component'; @@ -449,7 +449,7 @@ Lorem Ipsum }); }); - test('Should parse title-only', () => { + it('parses title-only', () => { const markdown = '# Document With Only A Title'; expect(parseMarkdownContentTitle(markdown)).toEqual({ content: markdown, @@ -457,7 +457,7 @@ Lorem Ipsum }); }); - test('Should not parse markdown h1 title in the middle of a doc', () => { + it('does not parse markdown h1 title in the middle of a doc', () => { const markdown = dedent` Lorem Ipsum @@ -473,7 +473,7 @@ Lorem Ipsum }); }); - test('Should not parse markdown h1 alternate title in the middle of the doc', () => { + it('does not parse markdown h1 alternate title in the middle of the doc', () => { const markdown = dedent` Lorem Ipsum @@ -490,7 +490,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title placed after multiple import declarations', () => { + it('parses markdown h1 title placed after multiple import declarations', () => { const markdown = dedent` import Component1 from '@site/src/components/Component1'; import Component2 from '@site/src/components/Component2'; @@ -520,7 +520,7 @@ Lorem Ipsum }); }); - test('Should parse markdown h1 title placed after multiple import declarations and remove it', () => { + it('parses markdown h1 title placed after multiple import declarations and remove it', () => { const markdown = dedent` import Component1 from '@site/src/components/Component1'; import Component2 from '@site/src/components/Component2'; @@ -554,7 +554,7 @@ Lorem Ipsum }); describe('parseMarkdownString', () => { - test('parse markdown with front matter', () => { + it('parse markdown with front matter', () => { expect( parseMarkdownString(dedent` --- @@ -563,38 +563,20 @@ describe('parseMarkdownString', () => { Some text `), - ).toMatchInlineSnapshot(` - Object { - "content": "Some text", - "contentTitle": undefined, - "excerpt": "Some text", - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should parse first heading as contentTitle', () => { + it('parses first heading as contentTitle', () => { expect( parseMarkdownString(dedent` # Markdown Title Some text `), - ).toMatchInlineSnapshot(` - Object { - "content": "# Markdown Title - - Some text", - "contentTitle": "Markdown Title", - "excerpt": "Some text", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('should warn about duplicate titles (front matter + markdown)', () => { + it('warns about duplicate titles (front matter + markdown)', () => { expect( parseMarkdownString(dedent` --- @@ -605,21 +587,10 @@ describe('parseMarkdownString', () => { Some text `), - ).toMatchInlineSnapshot(` - Object { - "content": "# Markdown Title - - Some text", - "contentTitle": "Markdown Title", - "excerpt": "Some text", - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should warn about duplicate titles (front matter + markdown alternate)', () => { + it('warns about duplicate titles (front matter + markdown alternate)', () => { expect( parseMarkdownString(dedent` --- @@ -631,22 +602,10 @@ describe('parseMarkdownString', () => { Some text `), - ).toMatchInlineSnapshot(` - Object { - "content": "Markdown Title alternate - ================ - - Some text", - "contentTitle": "Markdown Title alternate", - "excerpt": "Some text", - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should not warn for duplicate title if markdown title is not at the top', () => { + it('does not warn for duplicate title if markdown title is not at the top', () => { expect( parseMarkdownString(dedent` --- @@ -657,21 +616,10 @@ describe('parseMarkdownString', () => { # Markdown Title `), - ).toMatchInlineSnapshot(` - Object { - "content": "foo - - # Markdown Title", - "contentTitle": undefined, - "excerpt": "foo", - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should delete only first heading', () => { + it('deletes only first heading', () => { expect( parseMarkdownString(dedent` # Markdown Title @@ -682,23 +630,10 @@ describe('parseMarkdownString', () => { ### Markdown Title h3 `), - ).toMatchInlineSnapshot(` - Object { - "content": "# Markdown Title - - test test test # test bar - - # Markdown Title 2 - - ### Markdown Title h3", - "contentTitle": "Markdown Title", - "excerpt": "test test test # test bar", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('should parse front-matter and ignore h2', () => { + it('parses front-matter and ignore h2', () => { expect( parseMarkdownString( dedent` @@ -708,66 +643,33 @@ describe('parseMarkdownString', () => { ## test `, ), - ).toMatchInlineSnapshot(` - Object { - "content": "## test", - "contentTitle": undefined, - "excerpt": "test", - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should read front matter only', () => { + it('reads front matter only', () => { expect( parseMarkdownString(dedent` --- title: test --- `), - ).toMatchInlineSnapshot(` - Object { - "content": "", - "contentTitle": undefined, - "excerpt": undefined, - "frontMatter": Object { - "title": "test", - }, - } - `); + ).toMatchSnapshot(); }); - test('should parse title only', () => { - expect(parseMarkdownString('# test')).toMatchInlineSnapshot(` - Object { - "content": "# test", - "contentTitle": "test", - "excerpt": undefined, - "frontMatter": Object {}, - } - `); + it('parses title only', () => { + expect(parseMarkdownString('# test')).toMatchSnapshot(); }); - test('should parse title only alternate', () => { + it('parses title only alternate', () => { expect( parseMarkdownString(dedent` test === `), - ).toMatchInlineSnapshot(` - Object { - "content": "test - ===", - "contentTitle": "test", - "excerpt": undefined, - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('should warn about duplicate titles', () => { + it('warns about duplicate titles', () => { expect( parseMarkdownString(dedent` --- @@ -775,36 +677,19 @@ describe('parseMarkdownString', () => { --- # test `), - ).toMatchInlineSnapshot(` - Object { - "content": "# test", - "contentTitle": "test", - "excerpt": undefined, - "frontMatter": Object { - "title": "Frontmatter title", - }, - } - `); + ).toMatchSnapshot(); }); - test('should ignore markdown title if its not a first text', () => { + it('ignores markdown title if its not a first text', () => { expect( parseMarkdownString(dedent` foo # test `), - ).toMatchInlineSnapshot(` - Object { - "content": "foo - # test", - "contentTitle": undefined, - "excerpt": "foo", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('should delete only first heading 2', () => { + it('deletes only first heading 2', () => { expect( parseMarkdownString(dedent` # test @@ -815,23 +700,10 @@ describe('parseMarkdownString', () => { ### test test3 `), - ).toMatchInlineSnapshot(` - Object { - "content": "# test - - test test test test test test - test test test # test bar - # test2 - ### test - test3", - "contentTitle": "test", - "excerpt": "test test test test test test", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('should handle code blocks', () => { + it('handles code blocks', () => { expect( parseMarkdownString(dedent` \`\`\`js @@ -840,18 +712,7 @@ describe('parseMarkdownString', () => { Content `), - ).toMatchInlineSnapshot(` - Object { - "content": "\`\`\`js - code - \`\`\` - - Content", - "contentTitle": undefined, - "excerpt": "Content", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); expect( parseMarkdownString(dedent` \`\`\`\`js @@ -864,22 +725,7 @@ describe('parseMarkdownString', () => { Content `), - ).toMatchInlineSnapshot(` - Object { - "content": "\`\`\`\`js - Foo - \`\`\`diff - code - \`\`\` - Bar - \`\`\`\` - - Content", - "contentTitle": undefined, - "excerpt": "Content", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); expect( parseMarkdownString(dedent` \`\`\`\`js @@ -890,23 +736,10 @@ describe('parseMarkdownString', () => { Content `), - ).toMatchInlineSnapshot(` - Object { - "content": "\`\`\`\`js - Foo - \`\`\`diff - code - \`\`\`\` - - Content", - "contentTitle": undefined, - "excerpt": "Content", - "frontMatter": Object {}, - } - `); + ).toMatchSnapshot(); }); - test('throws for invalid front matter', () => { + it('throws for invalid front matter', () => { expect(() => parseMarkdownString(dedent` --- @@ -922,35 +755,35 @@ describe('parseMarkdownString', () => { }); describe('parseMarkdownHeadingId', () => { - test('can parse simple heading without id', () => { + it('can parse simple heading without id', () => { expect(parseMarkdownHeadingId('## Some heading')).toEqual({ text: '## Some heading', id: undefined, }); }); - test('can parse simple heading with id', () => { + it('can parse simple heading with id', () => { expect(parseMarkdownHeadingId('## Some heading {#custom-_id}')).toEqual({ text: '## Some heading', id: 'custom-_id', }); }); - test('can parse heading not ending with the id', () => { + it('can parse heading not ending with the id', () => { expect(parseMarkdownHeadingId('## {#custom-_id} Some heading')).toEqual({ text: '## {#custom-_id} Some heading', id: undefined, }); }); - test('can parse heading with multiple id', () => { + it('can parse heading with multiple id', () => { expect(parseMarkdownHeadingId('## Some heading {#id1} {#id2}')).toEqual({ text: '## Some heading {#id1}', id: 'id2', }); }); - test('can parse heading with link and id', () => { + it('can parse heading with link and id', () => { expect( parseMarkdownHeadingId( '## Some heading [facebook](https://facebook.com) {#id}', @@ -961,7 +794,7 @@ describe('parseMarkdownHeadingId', () => { }); }); - test('can parse heading with only id', () => { + it('can parse heading with only id', () => { expect(parseMarkdownHeadingId('## {#id}')).toEqual({ text: '##', id: 'id', diff --git a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts index 96089fa13a52..c6eabf9d12db 100644 --- a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {jest} from '@jest/globals'; import { isNameTooLong, shortName, @@ -17,7 +18,7 @@ import { import path from 'path'; describe('isNameTooLong', () => { - test('behaves correctly', () => { + it('works', () => { const asserts = { '': false, 'foo-bar-096': false, @@ -58,7 +59,7 @@ describe('isNameTooLong', () => { }); describe('shortName', () => { - test('works', () => { + it('works', () => { const asserts = { '': '', 'foo-bar': 'foo-bar', @@ -104,76 +105,87 @@ describe('shortName', () => { const VERY_LONG_PATH = `/${`x`.repeat(256)}/`; const VERY_LONG_PATH_NON_LATIN = `/${`あ`.repeat(255)}/`; - test('Truncates long paths correctly', () => { + it('truncates long paths correctly', () => { const truncatedPathLatin = shortName(VERY_LONG_PATH); const truncatedPathNonLatin = shortName(VERY_LONG_PATH_NON_LATIN); expect(truncatedPathLatin.length).toBeLessThanOrEqual(255); expect(truncatedPathNonLatin.length).toBeLessThanOrEqual(255); }); - test('Does not truncate short paths', () => { + it('does not truncate short paths', () => { const truncatedPath = shortName(SHORT_PATH); expect(truncatedPath).toEqual(SHORT_PATH); }); }); -test('toMessageRelativeFilePath', () => { - jest - .spyOn(process, 'cwd') - .mockImplementationOnce(() => path.join(__dirname, '..')); - expect(toMessageRelativeFilePath(path.join(__dirname, 'foo/bar.js'))).toEqual( - '__tests__/foo/bar.js', - ); +describe('toMessageRelativeFilePath', () => { + it('works', () => { + jest + .spyOn(process, 'cwd') + .mockImplementationOnce(() => path.join(__dirname, '..')); + expect( + toMessageRelativeFilePath(path.join(__dirname, 'foo/bar.js')), + ).toEqual('__tests__/foo/bar.js'); + }); }); -test('escapePath', () => { - const asserts: Record = { - 'c:/aaaa\\bbbb': 'c:/aaaa\\\\bbbb', - 'c:\\aaaa\\bbbb\\★': 'c:\\\\aaaa\\\\bbbb\\\\★', - '\\\\?\\c:\\aaaa\\bbbb': '\\\\\\\\?\\\\c:\\\\aaaa\\\\bbbb', - 'c:\\aaaa\\bbbb': 'c:\\\\aaaa\\\\bbbb', - 'foo\\bar': 'foo\\\\bar', - 'foo\\bar/lol': 'foo\\\\bar/lol', - 'website\\docs/**/*.{md,mdx}': 'website\\\\docs/**/*.{md,mdx}', - }; - Object.keys(asserts).forEach((file) => { - expect(escapePath(file)).toBe(asserts[file]); +describe('escapePath', () => { + it('works', () => { + const asserts: Record = { + 'c:/aaaa\\bbbb': 'c:/aaaa\\\\bbbb', + 'c:\\aaaa\\bbbb\\★': 'c:\\\\aaaa\\\\bbbb\\\\★', + '\\\\?\\c:\\aaaa\\bbbb': '\\\\\\\\?\\\\c:\\\\aaaa\\\\bbbb', + 'c:\\aaaa\\bbbb': 'c:\\\\aaaa\\\\bbbb', + 'foo\\bar': 'foo\\\\bar', + 'foo\\bar/lol': 'foo\\\\bar/lol', + 'website\\docs/**/*.{md,mdx}': 'website\\\\docs/**/*.{md,mdx}', + }; + Object.keys(asserts).forEach((file) => { + expect(escapePath(file)).toBe(asserts[file]); + }); }); }); -test('posixPath', () => { - const asserts: Record = { - 'c:/aaaa\\bbbb': 'c:/aaaa/bbbb', - 'c:\\aaaa\\bbbb\\★': 'c:\\aaaa\\bbbb\\★', - '\\\\?\\c:\\aaaa\\bbbb': '\\\\?\\c:\\aaaa\\bbbb', - 'c:\\aaaa\\bbbb': 'c:/aaaa/bbbb', - 'foo\\bar': 'foo/bar', - 'foo\\bar/lol': 'foo/bar/lol', - 'website\\docs/**/*.{md,mdx}': 'website/docs/**/*.{md,mdx}', - }; - Object.keys(asserts).forEach((file) => { - expect(posixPath(file)).toBe(asserts[file]); +describe('posixPath', () => { + it('works', () => { + const asserts: Record = { + 'c:/aaaa\\bbbb': 'c:/aaaa/bbbb', + 'c:\\aaaa\\bbbb\\★': 'c:\\aaaa\\bbbb\\★', + '\\\\?\\c:\\aaaa\\bbbb': '\\\\?\\c:\\aaaa\\bbbb', + 'c:\\aaaa\\bbbb': 'c:/aaaa/bbbb', + 'foo\\bar': 'foo/bar', + 'foo\\bar/lol': 'foo/bar/lol', + 'website\\docs/**/*.{md,mdx}': 'website/docs/**/*.{md,mdx}', + }; + Object.keys(asserts).forEach((file) => { + expect(posixPath(file)).toBe(asserts[file]); + }); }); }); -test('aliasedSitePath', () => { - const asserts: Record = { - 'user/website/docs/asd.md': '@site/docs/asd.md', - 'user/website/versioned_docs/foo/bar.md': '@site/versioned_docs/foo/bar.md', - 'user/docs/test.md': '@site/../docs/test.md', - }; - Object.keys(asserts).forEach((file) => { - expect(posixPath(aliasedSitePath(file, 'user/website'))).toBe( - asserts[file], - ); +describe('aliasedSitePath', () => { + it('works', () => { + const asserts: Record = { + 'user/website/docs/asd.md': '@site/docs/asd.md', + 'user/website/versioned_docs/foo/bar.md': + '@site/versioned_docs/foo/bar.md', + 'user/docs/test.md': '@site/../docs/test.md', + }; + Object.keys(asserts).forEach((file) => { + expect(posixPath(aliasedSitePath(file, 'user/website'))).toBe( + asserts[file], + ); + }); }); }); -test('addTrailingPathSeparator', () => { - expect(addTrailingPathSeparator('foo')).toEqual( - process.platform === 'win32' ? 'foo\\' : 'foo/', - ); - expect(addTrailingPathSeparator('foo/')).toEqual( - process.platform === 'win32' ? 'foo\\' : 'foo/', - ); +describe('addTrailingPathSeparator', () => { + it('works', () => { + expect(addTrailingPathSeparator('foo')).toEqual( + process.platform === 'win32' ? 'foo\\' : 'foo/', + ); + expect(addTrailingPathSeparator('foo/')).toEqual( + process.platform === 'win32' ? 'foo\\' : 'foo/', + ); + }); }); diff --git a/packages/docusaurus-utils/src/__tests__/slugger.test.ts b/packages/docusaurus-utils/src/__tests__/slugger.test.ts index d075aff7c494..310e4cf33af3 100644 --- a/packages/docusaurus-utils/src/__tests__/slugger.test.ts +++ b/packages/docusaurus-utils/src/__tests__/slugger.test.ts @@ -8,7 +8,7 @@ import {createSlugger} from '../slugger'; describe('createSlugger', () => { - test('can create unique slugs', () => { + it('can create unique slugs', () => { const slugger = createSlugger(); expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue'); expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue-1'); @@ -16,7 +16,7 @@ describe('createSlugger', () => { expect(slugger.slug('Some$/vaLue$!^-1')).toEqual('somevalue-1-1'); }); - test('can create unique slugs respecting case', () => { + it('can create unique slugs respecting case', () => { const slugger = createSlugger(); const opt = {maintainCase: true}; expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue'); diff --git a/packages/docusaurus-utils/src/__tests__/tags.test.ts b/packages/docusaurus-utils/src/__tests__/tags.test.ts index 908d602516f7..743b75068225 100644 --- a/packages/docusaurus-utils/src/__tests__/tags.test.ts +++ b/packages/docusaurus-utils/src/__tests__/tags.test.ts @@ -16,7 +16,7 @@ describe('normalizeFrontMatterTag', () => { type Input = Parameters[1]; type Output = ReturnType; - test('should normalize simple string tag', () => { + it('normalizes simple string tag', () => { const tagsPath = '/all/tags'; const input: Input = 'tag'; const expectedOutput: Output = { @@ -26,7 +26,7 @@ describe('normalizeFrontMatterTag', () => { expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); }); - test('should normalize complex string tag', () => { + it('normalizes complex string tag', () => { const tagsPath = '/all/tags'; const input: Input = 'some more Complex_tag'; const expectedOutput: Output = { @@ -36,7 +36,7 @@ describe('normalizeFrontMatterTag', () => { expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); }); - test('should normalize simple object tag', () => { + it('normalizes simple object tag', () => { const tagsPath = '/all/tags'; const input: Input = {label: 'tag', permalink: 'tagPermalink'}; const expectedOutput: Output = { @@ -46,7 +46,7 @@ describe('normalizeFrontMatterTag', () => { expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); }); - test('should normalize complex string tag with object tag', () => { + it('normalizes complex string tag with object tag', () => { const tagsPath = '/all/tags'; const input: Input = { label: 'tag complex Label', @@ -64,7 +64,7 @@ describe('normalizeFrontMatterTags', () => { type Input = Parameters[1]; type Output = ReturnType; - test('should normalize string list', () => { + it('normalizes string list', () => { const tagsPath = '/all/tags'; const input: Input = ['tag 1', 'tag-1', 'tag 3', 'tag1', 'tag-2']; // Keep user input order but remove tags that lead to same permalink @@ -85,11 +85,11 @@ describe('normalizeFrontMatterTags', () => { expect(normalizeFrontMatterTags(tagsPath, input)).toEqual(expectedOutput); }); - test('succeeds for empty list', () => { + it('succeeds for empty list', () => { expect(normalizeFrontMatterTags('/foo')).toEqual([]); }); - test('should normalize complex mixed list', () => { + it('normalizes complex mixed list', () => { const tagsPath = '/all/tags'; const input: Input = [ 'tag 1', @@ -131,7 +131,7 @@ describe('groupTaggedItems', () => { type Input = Parameters[0]; type Output = ReturnType; - test('should group items by tag permalink', () => { + it('groups items by tag permalink', () => { const tagGuide = {label: 'Guide', permalink: '/guide'}; const tagTutorial = {label: 'Tutorial', permalink: '/tutorial'}; const tagAPI = {label: 'API', permalink: '/api'}; diff --git a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts index 22410a8e76a0..306b12bb6e17 100644 --- a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts @@ -18,7 +18,7 @@ import { } from '../urlUtils'; describe('normalizeUrl', () => { - test('should normalize urls correctly', () => { + it('normalizes urls correctly', () => { const asserts = [ { input: ['/', ''], @@ -143,7 +143,7 @@ describe('normalizeUrl', () => { }); describe('getEditUrl', () => { - test('returns right path', () => { + it('returns right path', () => { expect( getEditUrl('foo/bar.md', 'https://github.com/facebook/docusaurus'), ).toEqual('https://github.com/facebook/docusaurus/foo/bar.md'); @@ -151,91 +151,99 @@ describe('getEditUrl', () => { getEditUrl('foo/你好.md', 'https://github.com/facebook/docusaurus'), ).toEqual('https://github.com/facebook/docusaurus/foo/你好.md'); }); - test('always returns valid URL', () => { + it('always returns valid URL', () => { expect( getEditUrl('foo\\你好.md', 'https://github.com/facebook/docusaurus'), ).toEqual('https://github.com/facebook/docusaurus/foo/你好.md'); }); - test('returns undefined for undefined', () => { + it('returns undefined for undefined', () => { expect(getEditUrl('foo/bar.md')).toBeUndefined(); }); }); -test('fileToPath', () => { - const asserts: Record = { - 'index.md': '/', - 'hello/index.md': '/hello/', - 'foo.md': '/foo', - 'foo/bar.md': '/foo/bar', - 'index.js': '/', - 'hello/index.js': '/hello/', - 'foo.js': '/foo', - 'foo/bar.js': '/foo/bar', - }; - Object.keys(asserts).forEach((file) => { - expect(fileToPath(file)).toBe(asserts[file]); +describe('fileToPath', () => { + it('works', () => { + const asserts: Record = { + 'index.md': '/', + 'hello/index.md': '/hello/', + 'foo.md': '/foo', + 'foo/bar.md': '/foo/bar', + 'index.js': '/', + 'hello/index.js': '/hello/', + 'foo.js': '/foo', + 'foo/bar.js': '/foo/bar', + }; + Object.keys(asserts).forEach((file) => { + expect(fileToPath(file)).toBe(asserts[file]); + }); }); }); -test('isValidPathname', () => { - expect(isValidPathname('/')).toBe(true); - expect(isValidPathname('/hey')).toBe(true); - expect(isValidPathname('/hey/ho')).toBe(true); - expect(isValidPathname('/hey/ho/')).toBe(true); - expect(isValidPathname('/hey/h%C3%B4/')).toBe(true); - expect(isValidPathname('/hey///ho///')).toBe(true); // Unexpected but valid - expect(isValidPathname('/hey/héllô you')).toBe(true); +describe('isValidPathname', () => { + it('works', () => { + expect(isValidPathname('/')).toBe(true); + expect(isValidPathname('/hey')).toBe(true); + expect(isValidPathname('/hey/ho')).toBe(true); + expect(isValidPathname('/hey/ho/')).toBe(true); + expect(isValidPathname('/hey/h%C3%B4/')).toBe(true); + expect(isValidPathname('/hey///ho///')).toBe(true); // Unexpected but valid + expect(isValidPathname('/hey/héllô you')).toBe(true); - expect(isValidPathname('')).toBe(false); - expect(isValidPathname('hey')).toBe(false); - expect(isValidPathname('/hey?qs=ho')).toBe(false); - expect(isValidPathname('https://fb.com/hey')).toBe(false); - expect(isValidPathname('//hey')).toBe(false); - expect(isValidPathname('////')).toBe(false); + expect(isValidPathname('')).toBe(false); + expect(isValidPathname('hey')).toBe(false); + expect(isValidPathname('/hey?qs=ho')).toBe(false); + expect(isValidPathname('https://fb.com/hey')).toBe(false); + expect(isValidPathname('//hey')).toBe(false); + expect(isValidPathname('////')).toBe(false); + }); }); describe('addTrailingSlash', () => { - test('should no-op', () => { + it('is no-op for path with trailing slash', () => { expect(addTrailingSlash('/abcd/')).toEqual('/abcd/'); }); - test('should add /', () => { + it('adds / for path without trailing slash', () => { expect(addTrailingSlash('/abcd')).toEqual('/abcd/'); }); }); describe('addLeadingSlash', () => { - test('should no-op', () => { + it('is no-op for path with leading slash', () => { expect(addLeadingSlash('/abc')).toEqual('/abc'); }); - test('should add /', () => { + it('adds / for path without leading slash', () => { expect(addLeadingSlash('abc')).toEqual('/abc'); }); }); describe('removeTrailingSlash', () => { - test('should no-op', () => { + it('is no-op for path without trailing slash', () => { expect(removeTrailingSlash('/abcd')).toEqual('/abcd'); }); - test('should remove /', () => { + it('removes / for path with trailing slash', () => { expect(removeTrailingSlash('/abcd/')).toEqual('/abcd'); }); }); -test('resolvePathname', () => { - // These tests are directly copied from https://github.com/mjackson/resolve-pathname/blob/master/modules/__tests__/resolvePathname-test.js - // Maybe we want to wrap that logic in the future? - expect(resolvePathname('c')).toEqual('c'); - expect(resolvePathname('c', 'a/b')).toEqual('a/c'); - expect(resolvePathname('/c', '/a/b')).toEqual('/c'); - expect(resolvePathname('', '/a/b')).toEqual('/a/b'); - expect(resolvePathname('../c', '/a/b')).toEqual('/c'); - expect(resolvePathname('c', '/a/b')).toEqual('/a/c'); - expect(resolvePathname('c', '/a/')).toEqual('/a/c'); - expect(resolvePathname('..', '/a/b')).toEqual('/'); +describe('resolvePathname', () => { + it('works', () => { + // These tests are directly copied from https://github.com/mjackson/resolve-pathname/blob/master/modules/__tests__/resolvePathname-test.js + // Maybe we want to wrap that logic in the future? + expect(resolvePathname('c')).toEqual('c'); + expect(resolvePathname('c', 'a/b')).toEqual('a/c'); + expect(resolvePathname('/c', '/a/b')).toEqual('/c'); + expect(resolvePathname('', '/a/b')).toEqual('/a/b'); + expect(resolvePathname('../c', '/a/b')).toEqual('/c'); + expect(resolvePathname('c', '/a/b')).toEqual('/a/c'); + expect(resolvePathname('c', '/a/')).toEqual('/a/c'); + expect(resolvePathname('..', '/a/b')).toEqual('/'); + }); }); -test('encodePath', () => { - expect(encodePath('a/foo/')).toEqual('a/foo/'); - expect(encodePath('a//')).toEqual('a/%3Cfoo%3E/'); - expect(encodePath('a/你好/')).toEqual('a/%E4%BD%A0%E5%A5%BD/'); +describe('encodePath', () => { + it('works', () => { + expect(encodePath('a/foo/')).toEqual('a/foo/'); + expect(encodePath('a//')).toEqual('a/%3Cfoo%3E/'); + expect(encodePath('a/你好/')).toEqual('a/%E4%BD%A0%E5%A5%BD/'); + }); }); diff --git a/packages/docusaurus-utils/src/__tests__/webpackUtils.test.ts b/packages/docusaurus-utils/src/__tests__/webpackUtils.test.ts index 824cd3419559..f4ce3578bf1b 100644 --- a/packages/docusaurus-utils/src/__tests__/webpackUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/webpackUtils.test.ts @@ -8,7 +8,7 @@ import {getFileLoaderUtils} from '../webpackUtils'; describe('getFileLoaderUtils()', () => { - test('plugin svgo/removeViewBox and removeTitle should be disabled', () => { + it('plugin svgo/removeViewBox and removeTitle should be disabled', () => { const {oneOf} = getFileLoaderUtils().rules.svg(); expect(oneOf[0].use).toContainEqual( expect.objectContaining({ diff --git a/packages/docusaurus/src/client/__tests__/flat.test.ts b/packages/docusaurus/src/client/__tests__/flat.test.ts index 4d176c008643..f931108938bb 100644 --- a/packages/docusaurus/src/client/__tests__/flat.test.ts +++ b/packages/docusaurus/src/client/__tests__/flat.test.ts @@ -8,7 +8,7 @@ import flat from '../flat'; describe('flat', () => { - test('nested', () => { + it('nested', () => { expect( flat({ foo: { @@ -32,7 +32,7 @@ describe('flat', () => { }); }); - test('primitives', () => { + it('primitives', () => { const primitives = { String: 'good morning', Number: 1234.99, @@ -55,7 +55,7 @@ describe('flat', () => { }); }); - test('multiple keys', () => { + it('multiple keys', () => { expect( flat({ foo: { @@ -69,7 +69,7 @@ describe('flat', () => { }); }); - test('empty object', () => { + it('empty object', () => { expect( flat({ foo: { @@ -81,7 +81,7 @@ describe('flat', () => { }); }); - test('array', () => { + it('array', () => { expect( flat({ hello: [{world: {again: 'foo'}}, {lorem: 'ipsum'}], diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts index 478c1f146a5c..df6294b60c15 100644 --- a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts +++ b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts @@ -9,7 +9,7 @@ import {jest} from '@jest/globals'; import normalizeLocation from '../normalizeLocation'; describe('normalizeLocation', () => { - test('rewrite locations with index.html', () => { + it('rewrite locations with index.html', () => { expect( normalizeLocation({ pathname: '/docs/introduction/index.html', @@ -35,7 +35,7 @@ describe('normalizeLocation', () => { }); }); - test('untouched pathnames', () => { + it('untouched pathnames', () => { const replaceMock = jest.spyOn(String.prototype, 'replace'); expect( diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index c1264c22161b..0de095ad048e 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -13,7 +13,7 @@ import BrowserOnly from '../BrowserOnly'; jest.mock('@docusaurus/useIsBrowser', () => () => true); describe('BrowserOnly', () => { - test('Should reject react element children', () => { + it('rejects react element children', () => { process.env.NODE_ENV = 'development'; expect(() => { renderer.create( @@ -27,7 +27,7 @@ describe('BrowserOnly', () => { Current type: React element" `); }); - test('Should reject string children', () => { + it('rejects string children', () => { expect(() => { renderer.create( // @ts-expect-error test @@ -38,7 +38,7 @@ describe('BrowserOnly', () => { Current type: string" `); }); - test('Should accept valid children', () => { + it('accepts valid children', () => { expect( renderer .create( diff --git a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx index 3a3b4ec046d2..7cd315572283 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx @@ -9,12 +9,12 @@ import React from 'react'; import {interpolate} from '../Interpolate'; describe('Interpolate', () => { - test('without placeholders', () => { + it('without placeholders', () => { const text = 'Hello how are you?'; expect(interpolate(text)).toEqual(text); }); - test('placeholders with string values', () => { + it('placeholders with string values', () => { const text = 'Hello {name} how are you {day}?'; const values = {name: 'Sébastien', day: 'today'}; expect(interpolate(text, values)).toMatchInlineSnapshot( @@ -22,7 +22,7 @@ describe('Interpolate', () => { ); }); - test('placeholders with string values 2', () => { + it('placeholders with string values 2', () => { const text = '{number} {string} {object} {array}'; const values = { number: 42, @@ -36,7 +36,7 @@ describe('Interpolate', () => { ); }); - test('placeholders with falsy values', () => { + it('placeholders with falsy values', () => { const text = '{number} {string} {boolean}'; const values = { number: 0, @@ -47,7 +47,7 @@ describe('Interpolate', () => { expect(interpolate(text, values)).toMatchInlineSnapshot(`"0 false"`); }); - test('placeholders with string values mismatch', () => { + it('placeholders with string values mismatch', () => { // Should we emit warnings in such case? const text = 'Hello {name} how are you {unprovidedValue}?'; const values = {name: 'Sébastien', extraValue: 'today'}; @@ -56,26 +56,26 @@ describe('Interpolate', () => { ); }); - test('placeholders with values not provided', () => { + it('placeholders with values not provided', () => { // Should we emit warnings in such case? const text = 'Hello {name} how are you {day}?'; expect(interpolate(text)).toEqual(text); expect(interpolate(text, {})).toEqual(text); }); - test('placeholders with JSX values', () => { + it('placeholders with JSX values', () => { const text = 'Hello {name} how are you {day}?'; const values = {name: Sébastien, day: today}; expect(interpolate(text, values)).toMatchSnapshot(); }); - test('placeholders with mixed vales', () => { + it('placeholders with mixed vales', () => { const text = 'Hello {name} how are you {day}?'; const values = {name: 'Sébastien', day: today}; expect(interpolate(text, values)).toMatchSnapshot(); }); - test('acceptance test', () => { + it('acceptance test', () => { const text = 'Hello {name} how are you {day}? Another {unprovidedValue}!'; const values = { name: 'Sébastien', diff --git a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx index 24e20d745440..2b8c3d27e3cd 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx @@ -8,21 +8,21 @@ import {translate} from '../Translate'; describe('translate', () => { - test('accept id and use it as fallback', () => { + it('accept id and use it as fallback', () => { expect(translate({id: 'some-id'})).toEqual('some-id'); }); - test('accept message and use it as fallback', () => { + it('accept message and use it as fallback', () => { expect(translate({message: 'some-message'})).toEqual('some-message'); }); - test('accept id+message and use message as fallback', () => { + it('accept id+message and use message as fallback', () => { expect(translate({id: 'some-id', message: 'some-message'})).toEqual( 'some-message', ); }); - test('reject when no id or message', () => { + it('reject when no id or message', () => { // TODO tests are not resolving type defs correctly // @ts-expect-error: TS should protect when both id/message are missing expect(() => translate({})).toThrowErrorMatchingInlineSnapshot( diff --git a/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts index cbb52102aeab..a91476457447 100644 --- a/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts +++ b/packages/docusaurus/src/client/exports/__tests__/isInternalUrl.test.ts @@ -8,39 +8,39 @@ import isInternalUrl from '../isInternalUrl'; describe('isInternalUrl', () => { - test('should be true for empty links', () => { + it('returns true for empty links', () => { expect(isInternalUrl('')).toBeTruthy(); }); - test('should be true for root relative links', () => { + it('returns true for root relative links', () => { expect(isInternalUrl('/foo/bar')).toBeTruthy(); }); - test('should be true for relative links', () => { + it('returns true for relative links', () => { expect(isInternalUrl('foo/bar')).toBeTruthy(); }); - test('should be false for HTTP links', () => { + it('returns false for HTTP links', () => { expect(isInternalUrl('http://foo.com')).toBeFalsy(); }); - test('should be false for HTTPS links', () => { + it('returns false for HTTPS links', () => { expect(isInternalUrl('https://foo.com')).toBeFalsy(); }); - test('should be false for whatever protocol links', () => { + it('returns false for whatever protocol links', () => { expect(isInternalUrl('//foo.com')).toBeFalsy(); }); - test('should be false for telephone links', () => { + it('returns false for telephone links', () => { expect(isInternalUrl('tel:+1234567890')).toBeFalsy(); }); - test('should be false for mailto links', () => { + it('returns false for mailto links', () => { expect(isInternalUrl('mailto:someone@example.com')).toBeFalsy(); }); - test('should be false for undefined links', () => { + it('returns false for undefined links', () => { expect(isInternalUrl(undefined)).toBeFalsy(); }); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts index e6c8dbc612f8..7b713ffa8be7 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts @@ -16,7 +16,7 @@ const mockedContext = useDocusaurusContext as jest.Mock; const forcePrepend = {forcePrependBaseUrl: true}; describe('useBaseUrl', () => { - test('empty base URL', () => { + it('empty base URL', () => { mockedContext.mockImplementation(() => ({ siteConfig: { baseUrl: '/', @@ -44,7 +44,7 @@ describe('useBaseUrl', () => { expect(useBaseUrl('#hello')).toEqual('#hello'); }); - test('non-empty base URL', () => { + it('non-empty base URL', () => { mockedContext.mockImplementation(() => ({ siteConfig: { baseUrl: '/docusaurus/', @@ -78,7 +78,7 @@ describe('useBaseUrl', () => { }); describe('useBaseUrlUtils().withBaseUrl()', () => { - test('empty base URL', () => { + it('empty base URL', () => { mockedContext.mockImplementation(() => ({ siteConfig: { baseUrl: '/', @@ -107,7 +107,7 @@ describe('useBaseUrlUtils().withBaseUrl()', () => { expect(withBaseUrl('#hello')).toEqual('#hello'); }); - test('non-empty base URL', () => { + it('non-empty base URL', () => { mockedContext.mockImplementation(() => ({ siteConfig: { baseUrl: '/docusaurus/', diff --git a/packages/docusaurus/src/commands/__tests__/deploy.test.ts b/packages/docusaurus/src/commands/__tests__/deploy.test.ts index bd35291b19f3..ca5dd0645883 100644 --- a/packages/docusaurus/src/commands/__tests__/deploy.test.ts +++ b/packages/docusaurus/src/commands/__tests__/deploy.test.ts @@ -8,15 +8,15 @@ import {buildSshUrl, buildHttpsUrl, hasSSHProtocol} from '../deploy'; describe('remoteBranchUrl', () => { - test('should build a normal ssh url', () => { + it('builds a normal ssh url', () => { const url = buildSshUrl('github.com', 'facebook', 'docusaurus'); expect(url).toEqual('git@github.com:facebook/docusaurus.git'); }); - test('should build a ssh url with port', () => { + it('builds a ssh url with port', () => { const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422'); expect(url).toEqual('ssh://git@github.com:422/facebook/docusaurus.git'); }); - test('should build a normal http url', () => { + it('builds a normal http url', () => { const url = buildHttpsUrl( 'user:pass', 'github.com', @@ -25,7 +25,7 @@ describe('remoteBranchUrl', () => { ); expect(url).toEqual('https://user:pass@github.com/facebook/docusaurus.git'); }); - test('should build a normal http url with port', () => { + it('builds a normal http url with port', () => { const url = buildHttpsUrl( 'user:pass', 'github.com', @@ -40,22 +40,22 @@ describe('remoteBranchUrl', () => { }); describe('hasSSHProtocol', () => { - test('should recognize explicit SSH protocol', () => { + it('recognizes explicit SSH protocol', () => { const url = 'ssh://git@github.com:422/facebook/docusaurus.git'; expect(hasSSHProtocol(url)).toEqual(true); }); - test('should recognize implied SSH protocol', () => { + it('recognizes implied SSH protocol', () => { const url = 'git@github.com:facebook/docusaurus.git'; expect(hasSSHProtocol(url)).toEqual(true); }); - test('should not recognize HTTPS with credentials', () => { + it('does not recognize HTTPS with credentials', () => { const url = 'https://user:pass@github.com/facebook/docusaurus.git'; expect(hasSSHProtocol(url)).toEqual(false); }); - test('should not recognize plain HTTPS URL', () => { + it('does not recognize plain HTTPS URL', () => { const url = 'https://github.com:5433/facebook/docusaurus.git'; expect(hasSSHProtocol(url)).toEqual(false); }); diff --git a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts index abdf868d725c..05f43abd7152 100644 --- a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts +++ b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts @@ -8,45 +8,45 @@ import {transformMarkdownContent} from '../writeHeadingIds'; describe('transformMarkdownContent', () => { - test('works for simple level-2 heading', () => { + it('works for simple level-2 heading', () => { expect(transformMarkdownContent('## ABC')).toEqual('## ABC {#abc}'); }); - test('works for simple level-3 heading', () => { + it('works for simple level-3 heading', () => { expect(transformMarkdownContent('### ABC')).toEqual('### ABC {#abc}'); }); - test('works for simple level-4 heading', () => { + it('works for simple level-4 heading', () => { expect(transformMarkdownContent('#### ABC')).toEqual('#### ABC {#abc}'); }); - test('unwraps markdown links', () => { + it('unwraps markdown links', () => { const input = `## hello [facebook](https://facebook.com) [crowdin](https://crowdin.com/translate/docusaurus-v2/126/en-fr?filter=basic&value=0)`; expect(transformMarkdownContent(input)).toEqual( `${input} {#hello-facebook-crowdin}`, ); }); - test('can slugify complex headings', () => { + it('can slugify complex headings', () => { const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756'; expect(transformMarkdownContent(input)).toEqual( `${input} {#abc-hello-how-are-you-sébastien_-_---56756}`, ); }); - test('does not duplicate duplicate id', () => { + it('does not duplicate duplicate id', () => { expect(transformMarkdownContent('## hello world {#hello-world}')).toEqual( '## hello world {#hello-world}', ); }); - test('respects existing heading', () => { + it('respects existing heading', () => { expect(transformMarkdownContent('## New heading {#old-heading}')).toEqual( '## New heading {#old-heading}', ); }); - test('overwrites heading ID when asked to', () => { + it('overwrites heading ID when asked to', () => { expect( transformMarkdownContent('## New heading {#old-heading}', { overwrite: true, @@ -54,7 +54,7 @@ describe('transformMarkdownContent', () => { ).toEqual('## New heading {#new-heading}'); }); - test('maintains casing when asked to', () => { + it('maintains casing when asked to', () => { expect( transformMarkdownContent('## getDataFromAPI()', { maintainCase: true, @@ -62,7 +62,7 @@ describe('transformMarkdownContent', () => { ).toEqual('## getDataFromAPI() {#getDataFromAPI}'); }); - test('transform the headings', () => { + it('transform the headings', () => { const input = ` # Ignored title diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap new file mode 100644 index 000000000000..7473f7a0233d --- /dev/null +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`wrap JavaScript wrap ComponentInFolder 2`] = ` +"import React from 'react'; +import ComponentInFolder from '@theme-original/ComponentInFolder'; + +export default function ComponentInFolderWrapper(props) { + return ( + <> + + + ); +} +" +`; + +exports[`wrap JavaScript wrap ComponentInFolder/ComponentInSubFolder 2`] = ` +"import React from 'react'; +import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; + +export default function ComponentInSubFolderWrapper(props) { + return ( + <> + + + ); +} +" +`; + +exports[`wrap JavaScript wrap FirstLevelComponent 2`] = ` +"import React from 'react'; +import FirstLevelComponent from '@theme-original/FirstLevelComponent'; + +export default function FirstLevelComponentWrapper(props) { + return ( + <> + + + ); +} +" +`; + +exports[`wrap TypeScript wrap ComponentInFolder 2`] = ` +"import React, {ComponentProps} from 'react'; +import type ComponentInFolderType from '@theme/ComponentInFolder'; +import ComponentInFolder from '@theme-original/ComponentInFolder'; + +type Props = ComponentProps + +export default function ComponentInFolderWrapper(props: Props): JSX.Element { + return ( + <> + + + ); +} +" +`; + +exports[`wrap TypeScript wrap ComponentInFolder/ComponentInSubFolder 2`] = ` +"import React, {ComponentProps} from 'react'; +import type ComponentInSubFolderType from '@theme/ComponentInFolder/ComponentInSubFolder'; +import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; + +type Props = ComponentProps + +export default function ComponentInSubFolderWrapper(props: Props): JSX.Element { + return ( + <> + + + ); +} +" +`; + +exports[`wrap TypeScript wrap FirstLevelComponent 2`] = ` +"import React, {ComponentProps} from 'react'; +import type FirstLevelComponentType from '@theme/FirstLevelComponent'; +import FirstLevelComponent from '@theme-original/FirstLevelComponent'; + +type Props = ComponentProps + +export default function FirstLevelComponentWrapper(props: Props): JSX.Element { + return ( + <> + + + ); +} +" +`; diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap new file mode 100644 index 000000000000..eeba7c337e96 --- /dev/null +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`normalizeSwizzleConfig normalize partial config 1`] = ` +Object { + "components": Object { + "Other/Component": Object { + "actions": Object { + "eject": "unsafe", + "wrap": "forbidden", + }, + }, + "SomeComponent": Object { + "actions": Object { + "eject": "safe", + "wrap": "unsafe", + }, + "description": "SomeComponent description", + }, + }, +} +`; diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/actions.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/actions.test.ts index af5c322d1552..90ef17ba783e 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/actions.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/actions.test.ts @@ -40,7 +40,7 @@ describe('eject', () => { }; } - test(`eject ${Components.FirstLevelComponent}`, async () => { + it(`eject ${Components.FirstLevelComponent}`, async () => { const result = await testEject('eject', Components.FirstLevelComponent); expect(result.createdFiles).toEqual([ 'FirstLevelComponent.css', @@ -53,7 +53,7 @@ describe('eject', () => { `); }); - test(`eject ${Components.ComponentInSubFolder}`, async () => { + it(`eject ${Components.ComponentInSubFolder}`, async () => { const result = await testEject('eject', Components.ComponentInSubFolder); expect(result.createdFiles).toEqual([ 'ComponentInFolder/ComponentInSubFolder/index.css', @@ -72,7 +72,7 @@ describe('eject', () => { `); }); - test(`eject ${Components.ComponentInFolder}`, async () => { + it(`eject ${Components.ComponentInFolder}`, async () => { const result = await testEject('eject', Components.ComponentInFolder); expect(result.createdFiles).toEqual([ // TODO do we really want to copy those Sibling components? @@ -124,29 +124,17 @@ describe('wrap', () => { }); } - test(`wrap ${Components.FirstLevelComponent}`, async () => { + it(`wrap ${Components.FirstLevelComponent}`, async () => { const result = await doWrap(Components.FirstLevelComponent); expect(result.createdFiles).toEqual(['FirstLevelComponent.js']); expect(result.tree).toMatchInlineSnapshot(` "theme └── FirstLevelComponent.js" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React from 'react'; - import FirstLevelComponent from '@theme-original/FirstLevelComponent'; - - export default function FirstLevelComponentWrapper(props) { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); - test(`wrap ${Components.ComponentInSubFolder}`, async () => { + it(`wrap ${Components.ComponentInSubFolder}`, async () => { const result = await doWrap(Components.ComponentInSubFolder); expect(result.createdFiles).toEqual([ 'ComponentInFolder/ComponentInSubFolder/index.js', @@ -157,22 +145,10 @@ describe('wrap', () => { └── ComponentInSubFolder └── index.js" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React from 'react'; - import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; - - export default function ComponentInSubFolderWrapper(props) { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); - test(`wrap ${Components.ComponentInFolder}`, async () => { + it(`wrap ${Components.ComponentInFolder}`, async () => { const result = await doWrap(Components.ComponentInFolder); expect(result.createdFiles).toEqual(['ComponentInFolder/index.js']); expect(result.tree).toMatchInlineSnapshot(` @@ -180,19 +156,7 @@ describe('wrap', () => { └── ComponentInFolder └── index.js" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React from 'react'; - import ComponentInFolder from '@theme-original/ComponentInFolder'; - - export default function ComponentInFolderWrapper(props) { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); }); @@ -203,32 +167,17 @@ describe('wrap', () => { }); } - test(`wrap ${Components.FirstLevelComponent}`, async () => { + it(`wrap ${Components.FirstLevelComponent}`, async () => { const result = await doWrap(Components.FirstLevelComponent); expect(result.createdFiles).toEqual(['FirstLevelComponent.tsx']); expect(result.tree).toMatchInlineSnapshot(` "theme └── FirstLevelComponent.tsx" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React, {ComponentProps} from 'react'; - import type FirstLevelComponentType from '@theme/FirstLevelComponent'; - import FirstLevelComponent from '@theme-original/FirstLevelComponent'; - - type Props = ComponentProps - - export default function FirstLevelComponentWrapper(props: Props): JSX.Element { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); - test(`wrap ${Components.ComponentInSubFolder}`, async () => { + it(`wrap ${Components.ComponentInSubFolder}`, async () => { const result = await doWrap(Components.ComponentInSubFolder); expect(result.createdFiles).toEqual([ 'ComponentInFolder/ComponentInSubFolder/index.tsx', @@ -239,25 +188,10 @@ describe('wrap', () => { └── ComponentInSubFolder └── index.tsx" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React, {ComponentProps} from 'react'; - import type ComponentInSubFolderType from '@theme/ComponentInFolder/ComponentInSubFolder'; - import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; - - type Props = ComponentProps - - export default function ComponentInSubFolderWrapper(props: Props): JSX.Element { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); - test(`wrap ${Components.ComponentInFolder}`, async () => { + it(`wrap ${Components.ComponentInFolder}`, async () => { const result = await doWrap(Components.ComponentInFolder); expect(result.createdFiles).toEqual(['ComponentInFolder/index.tsx']); expect(result.tree).toMatchInlineSnapshot(` @@ -265,22 +199,7 @@ describe('wrap', () => { └── ComponentInFolder └── index.tsx" `); - await expect(result.firstFileContent()).resolves.toMatchInlineSnapshot(` - "import React, {ComponentProps} from 'react'; - import type ComponentInFolderType from '@theme/ComponentInFolder'; - import ComponentInFolder from '@theme-original/ComponentInFolder'; - - type Props = ComponentProps - - export default function ComponentInFolderWrapper(props: Props): JSX.Element { - return ( - <> - - - ); - } - " - `); + await expect(result.firstFileContent()).resolves.toMatchSnapshot(); }); }); }); diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts index 56718724af23..41a68aaebf01 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts @@ -13,7 +13,7 @@ import {Components} from './testUtils'; const FixtureThemePath = path.join(__dirname, '__fixtures__/theme'); describe('readComponentNames', () => { - test('read theme', async () => { + it('read theme', async () => { await expect(readComponentNames(FixtureThemePath)).resolves.toEqual([ Components.ComponentInFolder, Components.ComponentInSubFolder, @@ -45,7 +45,7 @@ describe('getThemeComponents', () => { }, }; - test('read name', async () => { + it('read name', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -54,7 +54,7 @@ describe('getThemeComponents', () => { expect(themeComponents.themeName).toEqual(themeName); }); - test('read all', async () => { + it('read all', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -69,7 +69,7 @@ describe('getThemeComponents', () => { ]); }); - test('getConfig', async () => { + it('getConfig', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -112,7 +112,7 @@ describe('getThemeComponents', () => { ); }); - test('getDescription', async () => { + it('getDescription', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -129,7 +129,7 @@ describe('getThemeComponents', () => { ).toEqual('N/A'); }); - test('getActionStatus', async () => { + it('getActionStatus', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -157,7 +157,7 @@ describe('getThemeComponents', () => { ).toEqual('unsafe'); }); - test('isSafeAction', async () => { + it('isSafeAction', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, @@ -185,7 +185,7 @@ describe('getThemeComponents', () => { ).toEqual(false); }); - test('hasAnySafeAction', async () => { + it('hasAnySafeAction', async () => { const themeComponents = await getThemeComponents({ themeName, themePath, diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts index 3bedcb2086b3..d5f17399e9bc 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts @@ -9,14 +9,14 @@ import type {SwizzleConfig} from '@docusaurus/types'; import {normalizeSwizzleConfig} from '../config'; describe('normalizeSwizzleConfig', () => { - test(`validate no components config`, async () => { + it(`validate no components config`, async () => { const config: SwizzleConfig = { components: {}, }; expect(normalizeSwizzleConfig(config)).toEqual(config); }); - test(`validate complete config`, async () => { + it(`validate complete config`, async () => { const config: SwizzleConfig = { components: { SomeComponent: { @@ -38,7 +38,7 @@ describe('normalizeSwizzleConfig', () => { expect(normalizeSwizzleConfig(config)).toEqual(config); }); - test(`normalize partial config`, async () => { + it(`normalize partial config`, async () => { const config: SwizzleConfig = { components: { SomeComponent: { @@ -56,28 +56,10 @@ describe('normalizeSwizzleConfig', () => { }, }, }; - expect(normalizeSwizzleConfig(config)).toMatchInlineSnapshot(` - Object { - "components": Object { - "Other/Component": Object { - "actions": Object { - "eject": "unsafe", - "wrap": "forbidden", - }, - }, - "SomeComponent": Object { - "actions": Object { - "eject": "safe", - "wrap": "unsafe", - }, - "description": "SomeComponent description", - }, - }, - } - `); + expect(normalizeSwizzleConfig(config)).toMatchSnapshot(); }); - test(`reject missing components`, async () => { + it(`reject missing components`, async () => { // @ts-expect-error: incomplete actions map const config: SwizzleConfig = {}; @@ -88,7 +70,7 @@ describe('normalizeSwizzleConfig', () => { ); }); - test(`reject invalid action name`, async () => { + it(`reject invalid action name`, async () => { const config: SwizzleConfig = { components: { MyComponent: { @@ -109,7 +91,7 @@ describe('normalizeSwizzleConfig', () => { ); }); - test(`reject invalid action status`, async () => { + it(`reject invalid action status`, async () => { const config: SwizzleConfig = { components: { MyComponent: { diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts index 37504725f299..3e45151411f3 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts @@ -57,11 +57,13 @@ class MockExitError extends Error { function createExitMock() { let mock: jest.SpyInstance; + // eslint-disable-next-line jest/require-top-level-describe beforeEach(async () => { mock = jest.spyOn(process, 'exit').mockImplementation((code) => { - throw new MockExitError(code as number); + throw new MockExitError(code); }); }); + // eslint-disable-next-line jest/require-top-level-describe afterEach(async () => { mock?.mockRestore(); }); @@ -142,7 +144,7 @@ async function createTestSite() { describe('swizzle wrap', () => { const exitMock = createExitMock(); - test(`${Components.FirstLevelComponent} JS`, async () => { + it(`${Components.FirstLevelComponent} JS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.FirstLevelComponent, @@ -151,7 +153,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.FirstLevelComponent} TS`, async () => { + it(`${Components.FirstLevelComponent} TS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.FirstLevelComponent, @@ -160,7 +162,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInFolder} JS`, async () => { + it(`${Components.ComponentInFolder} JS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.ComponentInFolder, @@ -169,7 +171,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInFolder} TS`, async () => { + it(`${Components.ComponentInFolder} TS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.ComponentInFolder, @@ -179,7 +181,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInSubFolder} JS`, async () => { + it(`${Components.ComponentInSubFolder} JS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.ComponentInSubFolder, @@ -188,7 +190,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInSubFolder} TS`, async () => { + it(`${Components.ComponentInSubFolder} TS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.ComponentInSubFolder, @@ -198,7 +200,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.Sibling} JS`, async () => { + it(`${Components.Sibling} JS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.Sibling, @@ -207,7 +209,7 @@ describe('swizzle wrap', () => { await snapshotThemeDir(); }); - test(`${Components.Sibling} TS`, async () => { + it(`${Components.Sibling} TS`, async () => { const {snapshotThemeDir, testWrap} = await createTestSite(); await testWrap({ component: Components.Sibling, @@ -221,7 +223,7 @@ describe('swizzle wrap', () => { describe('swizzle eject', () => { const exitMock = createExitMock(); - test(`${Components.FirstLevelComponent} JS`, async () => { + it(`${Components.FirstLevelComponent} JS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.FirstLevelComponent, @@ -230,7 +232,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.FirstLevelComponent} TS`, async () => { + it(`${Components.FirstLevelComponent} TS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.FirstLevelComponent, @@ -239,7 +241,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInFolder} JS`, async () => { + it(`${Components.ComponentInFolder} JS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.ComponentInFolder, @@ -248,7 +250,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInFolder} TS`, async () => { + it(`${Components.ComponentInFolder} TS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.ComponentInFolder, @@ -258,7 +260,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInSubFolder} JS`, async () => { + it(`${Components.ComponentInSubFolder} JS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.ComponentInSubFolder, @@ -267,7 +269,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.ComponentInSubFolder} TS`, async () => { + it(`${Components.ComponentInSubFolder} TS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.ComponentInSubFolder, @@ -277,7 +279,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.Sibling} JS`, async () => { + it(`${Components.Sibling} JS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.Sibling, @@ -286,7 +288,7 @@ describe('swizzle eject', () => { await snapshotThemeDir(); }); - test(`${Components.Sibling} TS`, async () => { + it(`${Components.Sibling} TS`, async () => { const {snapshotThemeDir, testEject} = await createTestSite(); await testEject({ component: Components.Sibling, diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap index db52b1256e05..aad69e1e286d 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -1,34 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`normalizeConfig should throw error for baseUrl without trailing \`/\` 1`] = ` -"\\"baseUrl\\" must be a string with a trailing slash. -" -`; - -exports[`normalizeConfig should throw error for required fields 1`] = ` -"\\"baseUrl\\" is required -\\"title\\" is required -\\"url\\" is required -\\"themes\\" must be an array -\\"presets\\" must be an array -\\"scripts\\" must be an array -\\"stylesheets\\" must be an array -These field(s) (\\"invalidField\\",) are not recognized in docusaurus.config.js. -If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/docusaurus.config.js/#customfields" -`; - -exports[`normalizeConfig should throw error for unknown field 1`] = ` -"These field(s) (\\"invalid\\",) are not recognized in docusaurus.config.js. -If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/docusaurus.config.js/#customfields" -`; - -exports[`normalizeConfig should throw error if css doesn't have href 1`] = ` -"\\"stylesheets[1]\\" does not match any of the allowed types -" -`; - exports[`normalizeConfig should throw error if plugins is not a string and it's not an array #1 for the input of: [123] 1`] = ` " => Bad Docusaurus plugin value as path [plugins,0]. Example valid plugin config: @@ -98,16 +69,6 @@ exports[`normalizeConfig should throw error if plugins is not array for the inpu " `; -exports[`normalizeConfig should throw error if presets is not array 1`] = ` -"\\"presets\\" must be an array -" -`; - -exports[`normalizeConfig should throw error if scripts doesn't have src 1`] = ` -"\\"scripts[1]\\" does not match any of the allowed types -" -`; - exports[`normalizeConfig should throw error if themes is not a string and it's not an array #1 for the input of: [123] 1`] = ` " => Bad Docusaurus theme value as path [themes,0]. Example valid theme config: @@ -172,12 +133,51 @@ Example valid theme config: " `; -exports[`normalizeConfig should throw error if themes is not array 1`] = ` +exports[`normalizeConfig should throw error if themes is not array for the input of: {} 1`] = ` "\\"themes\\" must be an array " `; -exports[`normalizeConfig should throw error if themes is not array for the input of: {} 1`] = ` +exports[`normalizeConfig throws error for baseUrl without trailing \`/\` 1`] = ` +"\\"baseUrl\\" must be a string with a trailing slash. +" +`; + +exports[`normalizeConfig throws error for required fields 1`] = ` +"\\"baseUrl\\" is required +\\"title\\" is required +\\"url\\" is required +\\"themes\\" must be an array +\\"presets\\" must be an array +\\"scripts\\" must be an array +\\"stylesheets\\" must be an array +These field(s) (\\"invalidField\\",) are not recognized in docusaurus.config.js. +If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. +See https://docusaurus.io/docs/docusaurus.config.js/#customfields" +`; + +exports[`normalizeConfig throws error for unknown field 1`] = ` +"These field(s) (\\"invalid\\",) are not recognized in docusaurus.config.js. +If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. +See https://docusaurus.io/docs/docusaurus.config.js/#customfields" +`; + +exports[`normalizeConfig throws error if css doesn't have href 1`] = ` +"\\"stylesheets[1]\\" does not match any of the allowed types +" +`; + +exports[`normalizeConfig throws error if presets is not array 1`] = ` +"\\"presets\\" must be an array +" +`; + +exports[`normalizeConfig throws error if scripts doesn't have src 1`] = ` +"\\"scripts[1]\\" does not match any of the allowed types +" +`; + +exports[`normalizeConfig throws error if themes is not array 1`] = ` "\\"themes\\" must be an array " `; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap index fbac55042a7e..77e5891b69d6 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`handleDuplicateRoutes 1`] = ` +exports[`handleDuplicateRoutes works 1`] = ` "Duplicate routes found! - Attempting to create page at /search, but a page already exists at this route. - Attempting to create page at /sameDoc, but a page already exists at this route. diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index fa6b77131dcc..ef427a200fd3 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`loadRoutes flat route config 1`] = ` +exports[`loadRoutes loads flat route config 1`] = ` Object { "registry": Object { "component---theme-blog-list-pagea-6-a-7ba": Object { @@ -58,7 +58,7 @@ export default [ } `; -exports[`loadRoutes nested route config 1`] = ` +exports[`loadRoutes loads nested route config 1`] = ` Object { "registry": Object { "component---theme-doc-item-178-a40": Object { @@ -142,7 +142,7 @@ export default [ } `; -exports[`loadRoutes route config with empty (but valid) path string 1`] = ` +exports[`loadRoutes loads route config with empty (but valid) path string 1`] = ` Object { "registry": Object { "component---hello-world-jse-0-f-b6c": Object { diff --git a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts index 8e923a24818f..ad25d5ffde36 100644 --- a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts +++ b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts @@ -104,7 +104,7 @@ describe('handleBrokenLinks', () => { const outDir = path.resolve(__dirname, '__fixtures__/brokenLinks/outDir'); - test('do not report anything for correct paths', async () => { + it('do not report anything for correct paths', async () => { const consoleMock = jest .spyOn(console, 'error') .mockImplementation(() => {}); @@ -143,7 +143,7 @@ describe('handleBrokenLinks', () => { expect(consoleMock).toBeCalledTimes(0); }); - test('reports all broken links', async () => { + it('reports all broken links', async () => { await expect(() => handleBrokenLinks({ allCollectedLinks, @@ -155,7 +155,7 @@ describe('handleBrokenLinks', () => { ).rejects.toThrowErrorMatchingSnapshot(); }); - test('no-op for ignore', async () => { + it('no-op for ignore', async () => { // In any case, _.mapValues will always be called, unless handleBrokenLinks // has already bailed const lodashMock = jest.spyOn(_, 'mapValues'); @@ -170,7 +170,7 @@ describe('handleBrokenLinks', () => { lodashMock.mockRestore(); }); - test('reports frequent broken links', async () => { + it('reports frequent broken links', async () => { Object.values(allCollectedLinks).forEach((links) => links.push( '/frequent', diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index fa248987e9f3..0b32cca4d1bf 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -9,7 +9,7 @@ import path from 'path'; import loadConfig from '../config'; describe('loadConfig', () => { - test('website with valid siteConfig', async () => { + it('website with valid siteConfig', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -21,7 +21,7 @@ describe('loadConfig', () => { expect(config).not.toEqual({}); }); - test('website with valid config creator function', async () => { + it('website with valid config creator function', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -33,7 +33,7 @@ describe('loadConfig', () => { expect(config).not.toEqual({}); }); - test('website with valid async config', async () => { + it('website with valid async config', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -45,7 +45,7 @@ describe('loadConfig', () => { expect(config).not.toEqual({}); }); - test('website with valid async config creator function', async () => { + it('website with valid async config creator function', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -57,7 +57,7 @@ describe('loadConfig', () => { expect(config).not.toEqual({}); }); - test('website with incomplete siteConfig', async () => { + it('website with incomplete siteConfig', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -67,7 +67,7 @@ describe('loadConfig', () => { await expect(loadConfig(siteDir)).rejects.toThrowErrorMatchingSnapshot(); }); - test('website with useless field (wrong field) in siteConfig', async () => { + it('website with useless field (wrong field) in siteConfig', async () => { const siteDir = path.join( __dirname, '__fixtures__', @@ -77,7 +77,7 @@ describe('loadConfig', () => { await expect(loadConfig(siteDir)).rejects.toThrowErrorMatchingSnapshot(); }); - test('website with no siteConfig', async () => { + it('website with no siteConfig', async () => { const siteDir = path.join( __dirname, '__fixtures__', diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 24a483de30dd..c8b3d6942eee 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -21,7 +21,7 @@ const baseConfig: DocusaurusConfig = { const normalizeConfig = (config) => validateConfig({...baseConfig, ...config}); describe('normalizeConfig', () => { - test('should normalize empty config', () => { + it('normalizes empty config', () => { const value = normalizeConfig({}); expect(value).toEqual({ ...DEFAULT_CONFIG, @@ -29,7 +29,7 @@ describe('normalizeConfig', () => { }); }); - test('should accept correctly defined config options', () => { + it('accepts correctly defined config options', () => { const userConfig = { ...DEFAULT_CONFIG, ...baseConfig, @@ -60,7 +60,7 @@ describe('normalizeConfig', () => { expect(normalizedConfig).toEqual(userConfig); }); - test('should accept custom field in config', () => { + it('accepts custom field in config', () => { const value = normalizeConfig({ customFields: { author: 'anshul', @@ -75,7 +75,7 @@ describe('normalizeConfig', () => { }); }); - test('should throw error for unknown field', () => { + it('throws error for unknown field', () => { expect(() => { normalizeConfig({ invalid: true, @@ -83,7 +83,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test('should throw error for baseUrl without trailing `/`', () => { + it('throws error for baseUrl without trailing `/`', () => { expect(() => { normalizeConfig({ baseUrl: 'noslash', @@ -91,7 +91,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test.each([ + it.each([ ['should throw error if plugins is not array', {}], [ "should throw error if plugins is not a string and it's not an array #1", @@ -117,7 +117,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test.each([ + it.each([ ['should throw error if themes is not array', {}], [ "should throw error if themes is not a string and it's not an array #1", @@ -143,7 +143,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test.each([ + it.each([ ['should accept [string] for plugins', ['plain/string']], [ 'should accept string[] for plugins', @@ -184,7 +184,7 @@ describe('normalizeConfig', () => { }).not.toThrowError(); }); - test.each([ + it.each([ ['should accept [string] for themes', ['plain/string']], [ 'should accept string[] for themes', @@ -225,7 +225,7 @@ describe('normalizeConfig', () => { }).not.toThrowError(); }); - test('should throw error if themes is not array', () => { + it('throws error if themes is not array', () => { expect(() => { normalizeConfig({ themes: {}, @@ -233,7 +233,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test('should throw error if presets is not array', () => { + it('throws error if presets is not array', () => { expect(() => { normalizeConfig({ presets: {}, @@ -241,7 +241,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test("should throw error if scripts doesn't have src", () => { + it("throws error if scripts doesn't have src", () => { expect(() => { normalizeConfig({ scripts: ['https://some.com', {}], @@ -249,7 +249,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test("should throw error if css doesn't have href", () => { + it("throws error if css doesn't have href", () => { expect(() => { normalizeConfig({ stylesheets: ['https://somescript.com', {type: 'text/css'}], @@ -257,7 +257,7 @@ describe('normalizeConfig', () => { }).toThrowErrorMatchingSnapshot(); }); - test('should throw error for required fields', () => { + it('throws error for required fields', () => { expect( () => validateConfig({ @@ -276,12 +276,12 @@ describe('config warnings', () => { return ConfigSchema.validate(config).warning; } - test('baseConfig has no warning', () => { + it('baseConfig has no warning', () => { const warning = getWarning(baseConfig); expect(warning).toBeUndefined(); }); - test('site url has warning when using subpath', () => { + it('site url has warning when using subpath', () => { const warning = getWarning({ ...baseConfig, url: 'https://mysite.com/someSubpath', diff --git a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts b/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts index 61308eef0207..055e59cef7aa 100644 --- a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts +++ b/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts @@ -41,11 +41,13 @@ const routes: RouteConfig[] = [ }, ]; -test('handleDuplicateRoutes', () => { - expect(() => { - handleDuplicateRoutes(routes, 'throw'); - }).toThrowErrorMatchingSnapshot(); - const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); - handleDuplicateRoutes(routes, 'ignore'); - expect(consoleMock).toBeCalledTimes(0); +describe('handleDuplicateRoutes', () => { + it('works', () => { + expect(() => { + handleDuplicateRoutes(routes, 'throw'); + }).toThrowErrorMatchingSnapshot(); + const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); + handleDuplicateRoutes(routes, 'ignore'); + expect(consoleMock).toBeCalledTimes(0); + }); }); diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index d78679ff70e3..cb47daeb4471 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -30,7 +30,7 @@ function loadI18nTest(i18nConfig: I18nConfig, locale?: string) { describe('defaultLocaleConfig', () => { const canComputeLabel = typeof Intl.DisplayNames !== 'undefined'; - test('returns correct labels', () => { + it('returns correct labels', () => { expect(getDefaultLocaleConfig('fr')).toEqual({ label: canComputeLabel ? 'Français' : 'fr', direction: 'ltr', @@ -85,7 +85,7 @@ describe('loadI18n', () => { consoleSpy.mockClear(); }); - test('should load I18n for default config', async () => { + it('loads I18n for default config', async () => { await expect(loadI18nTest(DEFAULT_I18N_CONFIG)).resolves.toEqual({ defaultLocale: 'en', locales: ['en'], @@ -94,7 +94,7 @@ describe('loadI18n', () => { }); }); - test('should load I18n for multi-lang config', async () => { + it('loads I18n for multi-lang config', async () => { await expect( loadI18nTest({ defaultLocale: 'fr', @@ -109,7 +109,7 @@ describe('loadI18n', () => { }); }); - test('should load I18n for multi-locale config with specified locale', async () => { + it('loads I18n for multi-locale config with specified locale', async () => { await expect( loadI18nTest( { @@ -127,7 +127,7 @@ describe('loadI18n', () => { }); }); - test('should load I18n for multi-locale config with some xcustom locale configs', async () => { + it('loads I18n for multi-locale config with some xcustom locale configs', async () => { await expect( loadI18nTest( { @@ -152,7 +152,7 @@ describe('loadI18n', () => { }); }); - test('should warn when trying to load undeclared locale', async () => { + it('warns when trying to load undeclared locale', async () => { await loadI18nTest( { defaultLocale: 'fr', @@ -168,7 +168,7 @@ describe('loadI18n', () => { }); describe('localizePath', () => { - test('should localize url path with current locale', () => { + it('localizes url path with current locale', () => { expect( localizePath({ pathType: 'url', @@ -184,7 +184,7 @@ describe('localizePath', () => { ).toEqual('/baseUrl/fr/'); }); - test('should localize fs path with current locale', () => { + it('localizes fs path with current locale', () => { expect( localizePath({ pathType: 'fs', @@ -200,7 +200,7 @@ describe('localizePath', () => { ).toEqual(`${path.sep}baseFsPath${path.sep}fr`); }); - test('should localize path for default locale, if requested', () => { + it('localizes path for default locale, if requested', () => { expect( localizePath({ pathType: 'url', @@ -216,7 +216,7 @@ describe('localizePath', () => { ).toEqual('/baseUrl/en/'); }); - test('should not localize path for default locale by default', () => { + it('does not localize path for default locale by default', () => { expect( localizePath({ pathType: 'url', @@ -232,7 +232,7 @@ describe('localizePath', () => { ).toEqual('/baseUrl/'); }); - test('should localize path for non-default locale by default', () => { + it('localizes path for non-default locale by default', () => { expect( localizePath({ pathType: 'url', diff --git a/packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts b/packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts index 095fc6d53d7f..239811e3427b 100644 --- a/packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts +++ b/packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts @@ -8,7 +8,7 @@ import {getNamePatterns, resolveModuleName} from '../moduleShorthand'; describe('getNamePatterns', () => { - test('should resolve plain names', () => { + it('resolves plain names', () => { expect(getNamePatterns('awesome', 'plugin')).toEqual([ 'awesome', '@docusaurus/plugin-awesome', @@ -22,7 +22,7 @@ describe('getNamePatterns', () => { ]); }); - test('should expand bare scopes', () => { + it('expands bare scopes', () => { expect(getNamePatterns('@joshcena', 'plugin')).toEqual([ '@joshcena/docusaurus-plugin', ]); @@ -32,7 +32,7 @@ describe('getNamePatterns', () => { ]); }); - test('should expand scoped names', () => { + it('expands scoped names', () => { expect(getNamePatterns('@joshcena/awesome', 'plugin')).toEqual([ '@joshcena/awesome', '@joshcena/docusaurus-plugin-awesome', @@ -44,7 +44,7 @@ describe('getNamePatterns', () => { ]); }); - test('should expand deep scoped paths', () => { + it('expands deep scoped paths', () => { expect(getNamePatterns('@joshcena/awesome/web', 'plugin')).toEqual([ '@joshcena/awesome/web', '@joshcena/docusaurus-plugin-awesome/web', @@ -58,17 +58,17 @@ describe('getNamePatterns', () => { }); describe('resolveModuleName', () => { - test('should resolve longhand', () => { + it('resolves longhand', () => { expect( resolveModuleName('@docusaurus/plugin-content-docs', require, 'plugin'), ).toBeDefined(); }); - test('should resolve shorthand', () => { + it('resolves shorthand', () => { expect(resolveModuleName('content-docs', require, 'plugin')).toBeDefined(); }); - test('should throw good error message for longhand', () => { + it('throws good error message for longhand', () => { expect(() => resolveModuleName('@docusaurus/plugin-content-doc', require, 'plugin'), ).toThrowErrorMatchingInlineSnapshot(` @@ -78,7 +78,7 @@ describe('resolveModuleName', () => { `); }); - test('should throw good error message for shorthand', () => { + it('throws good error message for shorthand', () => { expect(() => resolveModuleName('content-doc', require, 'plugin')) .toThrowErrorMatchingInlineSnapshot(` "Docusaurus was unable to resolve the \\"content-doc\\" plugin. Make sure one of the following packages are installed: diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index f9dfbca2da4e..1a8029336eb7 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -9,7 +9,7 @@ import loadRoutes from '../routes'; import type {RouteConfig} from '@docusaurus/types'; describe('loadRoutes', () => { - test('nested route config', async () => { + it('loads nested route config', async () => { const nestedRouteConfig: RouteConfig = { component: '@theme/DocPage', path: '/docs:route', @@ -38,11 +38,12 @@ describe('loadRoutes', () => { }, ], }; - const result = await loadRoutes([nestedRouteConfig], '/'); - expect(result).toMatchSnapshot(); + await expect( + loadRoutes([nestedRouteConfig], '/'), + ).resolves.toMatchSnapshot(); }); - test('flat route config', async () => { + it('loads flat route config', async () => { const flatRouteConfig: RouteConfig = { path: '/blog', component: '@theme/BlogListPage', @@ -66,39 +67,37 @@ describe('loadRoutes', () => { ], }, }; - const result = await loadRoutes([flatRouteConfig], '/'); - expect(result).toMatchSnapshot(); + await expect(loadRoutes([flatRouteConfig], '/')).resolves.toMatchSnapshot(); }); - test('invalid route config', async () => { + it('rejects invalid route config', async () => { const routeConfigWithoutPath = { component: 'hello/world.js', } as RouteConfig; await expect(loadRoutes([routeConfigWithoutPath], '/')).rejects - .toMatchInlineSnapshot(` - [Error: Invalid route config: path must be a string and component is required. - {"component":"hello/world.js"}] - `); + .toThrowErrorMatchingInlineSnapshot(` + "Invalid route config: path must be a string and component is required. + {\\"component\\":\\"hello/world.js\\"}" + `); const routeConfigWithoutComponent = { path: '/hello/world', } as RouteConfig; await expect(loadRoutes([routeConfigWithoutComponent], '/')).rejects - .toMatchInlineSnapshot(` - [Error: Invalid route config: path must be a string and component is required. - {"path":"/hello/world"}] - `); + .toThrowErrorMatchingInlineSnapshot(` + "Invalid route config: path must be a string and component is required. + {\\"path\\":\\"/hello/world\\"}" + `); }); - test('route config with empty (but valid) path string', async () => { + it('loads route config with empty (but valid) path string', async () => { const routeConfig = { path: '', component: 'hello/world.js', } as RouteConfig; - const result = await loadRoutes([routeConfig], '/'); - expect(result).toMatchSnapshot(); + await expect(loadRoutes([routeConfig], '/')).resolves.toMatchSnapshot(); }); }); diff --git a/packages/docusaurus/src/server/__tests__/utils.test.ts b/packages/docusaurus/src/server/__tests__/utils.test.ts index 0cea2621b1a3..b8ef5b59faaa 100644 --- a/packages/docusaurus/src/server/__tests__/utils.test.ts +++ b/packages/docusaurus/src/server/__tests__/utils.test.ts @@ -9,7 +9,7 @@ import type {RouteConfig} from '@docusaurus/types'; import {getAllFinalRoutes} from '../utils'; describe('getAllFinalRoutes', () => { - test('should get final routes correctly', () => { + it('gets final routes correctly', () => { const routes: RouteConfig[] = [ { path: '/docs', diff --git a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts index 55feae00455f..de01447dc00d 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts @@ -12,12 +12,12 @@ import pluginFooBar from './__fixtures__/plugin-foo-bar'; import pluginHelloWorld from './__fixtures__/plugin-hello-world'; describe('loadClientModules', () => { - test('empty', () => { + it('empty', () => { const clientModules = loadClientModules([pluginEmpty()]); expect(clientModules).toMatchInlineSnapshot(`Array []`); }); - test('non-empty', () => { + it('non-empty', () => { const clientModules = loadClientModules([pluginFooBar()]); expect(clientModules).toMatchInlineSnapshot(` Array [ @@ -27,7 +27,7 @@ describe('loadClientModules', () => { `); }); - test('multiple non-empty', () => { + it('multiple non-empty', () => { const clientModules = loadClientModules([ pluginFooBar(), pluginHelloWorld(), @@ -42,7 +42,7 @@ describe('loadClientModules', () => { `); }); - test('multiple non-empty different order', () => { + it('multiple non-empty different order', () => { const clientModules = loadClientModules([ pluginHelloWorld(), pluginFooBar(), @@ -57,7 +57,7 @@ describe('loadClientModules', () => { `); }); - test('empty and non-empty', () => { + it('empty and non-empty', () => { const clientModules = loadClientModules([ pluginHelloWorld(), pluginEmpty(), @@ -73,7 +73,7 @@ describe('loadClientModules', () => { `); }); - test('empty and non-empty different order', () => { + it('empty and non-empty different order', () => { const clientModules = loadClientModules([ pluginHelloWorld(), pluginFooBar(), diff --git a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts index fa931c50d673..ccf6865980c7 100644 --- a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts +++ b/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts @@ -8,7 +8,7 @@ import htmlTagObjectToString from '../htmlTags'; describe('htmlTagObjectToString', () => { - test('valid html tag', () => { + it('valid html tag', () => { expect( htmlTagObjectToString({ tagName: 'script', @@ -55,7 +55,7 @@ describe('htmlTagObjectToString', () => { ).toMatchInlineSnapshot(`"
    Test
    "`); }); - test('valid html void tag', () => { + it('valid html void tag', () => { expect( htmlTagObjectToString({ tagName: 'meta', @@ -83,7 +83,7 @@ describe('htmlTagObjectToString', () => { ); }); - test('invalid tag', () => { + it('invalid tag', () => { expect(() => htmlTagObjectToString({ tagName: 'endiliey', @@ -96,7 +96,7 @@ describe('htmlTagObjectToString', () => { ); }); - test('invalid tagName', () => { + it('invalid tagName', () => { expect(() => htmlTagObjectToString({ tagName: true, @@ -106,7 +106,7 @@ describe('htmlTagObjectToString', () => { ); }); - test('invalid html tag object', () => { + it('invalid html tag object', () => { expect(() => htmlTagObjectToString('fooofofoofo'), ).toThrowErrorMatchingInlineSnapshot( diff --git a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts index 751368320b94..7b204ab38af5 100644 --- a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts @@ -13,7 +13,7 @@ import pluginHeadTags from './__fixtures__/plugin-headTags'; import pluginPostBodyTags from './__fixtures__/plugin-postBodyTags'; describe('loadHtmlTags', () => { - test('empty plugin', () => { + it('empty plugin', () => { const htmlTags = loadHtmlTags([pluginEmpty()]); expect(htmlTags).toMatchInlineSnapshot(` Object { @@ -24,7 +24,7 @@ describe('loadHtmlTags', () => { `); }); - test('only inject headTags', () => { + it('only inject headTags', () => { const htmlTags = loadHtmlTags([pluginHeadTags()]); expect(htmlTags).toMatchInlineSnapshot(` Object { @@ -36,7 +36,7 @@ describe('loadHtmlTags', () => { `); }); - test('only inject preBodyTags', () => { + it('only inject preBodyTags', () => { const htmlTags = loadHtmlTags([pluginPreBodyTags()]); expect(htmlTags).toMatchInlineSnapshot(` Object { @@ -47,7 +47,7 @@ describe('loadHtmlTags', () => { `); }); - test('only inject postBodyTags', () => { + it('only inject postBodyTags', () => { const htmlTags = loadHtmlTags([pluginPostBodyTags()]); expect(htmlTags).toMatchInlineSnapshot(` Object { @@ -58,7 +58,7 @@ describe('loadHtmlTags', () => { `); }); - test('multiple plugins that inject different part of html tags', () => { + it('multiple plugins that inject different part of html tags', () => { const htmlTags = loadHtmlTags([ pluginHeadTags(), pluginPostBodyTags(), @@ -74,7 +74,7 @@ describe('loadHtmlTags', () => { `); }); - test('multiple plugins that might/might not inject html tags', () => { + it('multiple plugins that might/might not inject html tags', () => { const htmlTags = loadHtmlTags([ pluginEmpty(), pluginHeadTags(), diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap index 8f50acccbed8..22f56e0389c9 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap @@ -28,7 +28,7 @@ Example valid plugin config: " `; -exports[`sortConfig should sort route config correctly 1`] = ` +exports[`sortConfig sorts route config correctly 1`] = ` Array [ Object { "component": "", @@ -83,7 +83,7 @@ Array [ ] `; -exports[`sortConfig should sort route config given a baseURL 1`] = ` +exports[`sortConfig sorts route config given a baseURL 1`] = ` Array [ Object { "component": "", diff --git a/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts b/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts index 713e4a1a6c8e..de21791fc82f 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts @@ -27,7 +27,7 @@ function params( } describe('applyRouteTrailingSlash', () => { - test('apply to empty', () => { + it('apply to empty', () => { expect(applyRouteTrailingSlash(route(''), params(true))).toEqual( route('/'), ); @@ -39,7 +39,7 @@ describe('applyRouteTrailingSlash', () => { ); }); - test('apply to /', () => { + it('apply to /', () => { expect(applyRouteTrailingSlash(route('/'), params(true))).toEqual( route('/'), ); @@ -51,7 +51,7 @@ describe('applyRouteTrailingSlash', () => { ); }); - test('apply to /abc', () => { + it('apply to /abc', () => { expect(applyRouteTrailingSlash(route('/abc'), params(true))).toEqual( route('/abc/'), ); @@ -63,7 +63,7 @@ describe('applyRouteTrailingSlash', () => { ); }); - test('apply to /abc/', () => { + it('apply to /abc/', () => { expect(applyRouteTrailingSlash(route('/abc/'), params(true))).toEqual( route('/abc/'), ); @@ -75,7 +75,7 @@ describe('applyRouteTrailingSlash', () => { ); }); - test('apply to /abc?search#anchor', () => { + it('apply to /abc?search#anchor', () => { expect( applyRouteTrailingSlash(route('/abc?search#anchor'), params(true)), ).toEqual(route('/abc/?search#anchor')); @@ -87,7 +87,7 @@ describe('applyRouteTrailingSlash', () => { ).toEqual(route('/abc?search#anchor')); }); - test('apply to /abc/?search#anchor', () => { + it('apply to /abc/?search#anchor', () => { expect( applyRouteTrailingSlash(route('/abc/?search#anchor'), params(true)), ).toEqual(route('/abc/?search#anchor')); @@ -99,7 +99,7 @@ describe('applyRouteTrailingSlash', () => { ).toEqual(route('/abc/?search#anchor')); }); - test('not apply to /abc/?search#anchor when baseUrl=/abc/', () => { + it('not apply to /abc/?search#anchor when baseUrl=/abc/', () => { const baseUrl = '/abc/'; expect( applyRouteTrailingSlash( @@ -121,7 +121,7 @@ describe('applyRouteTrailingSlash', () => { ).toEqual(route('/abc/?search#anchor')); }); - test('apply to subroutes', () => { + it('apply to subroutes', () => { expect( applyRouteTrailingSlash( route('/abc', ['/abc/1', '/abc/2']), @@ -142,7 +142,7 @@ describe('applyRouteTrailingSlash', () => { ).toEqual(route('/abc', ['/abc/1', '/abc/2'])); }); - test('apply for complex case', () => { + it('apply for complex case', () => { expect( applyRouteTrailingSlash( route('/abc?search#anchor', ['/abc/1?search', '/abc/2#anchor']), @@ -153,7 +153,7 @@ describe('applyRouteTrailingSlash', () => { ); }); - test('apply for complex case with baseUrl', () => { + it('apply for complex case with baseUrl', () => { const baseUrl = '/abc/'; expect( applyRouteTrailingSlash( diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index 09ef8e82a0fa..d2b06abbda00 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -29,7 +29,7 @@ describe('initPlugins', () => { return {siteDir, context, plugins}; } - test('plugins gets parsed correctly and loads in correct order', async () => { + it('plugins gets parsed correctly and loads in correct order', async () => { const {context, plugins} = await loadSite(); expect(context.siteConfig.plugins?.length).toBe(4); expect(plugins.length).toBe(8); @@ -45,7 +45,7 @@ describe('initPlugins', () => { expect(context.siteConfig.themeConfig).toEqual({a: 1}); }); - test('plugins with bad values throw user-friendly error message', async () => { + it('plugins with bad values throw user-friendly error message', async () => { await expect(() => loadSite({ customConfigFilePath: 'badPlugins.docusaurus.config.js', @@ -55,7 +55,7 @@ describe('initPlugins', () => { }); describe('sortConfig', () => { - test('should sort route config correctly', () => { + it('sorts route config correctly', () => { const routes: RouteConfig[] = [ { path: '/', @@ -97,7 +97,7 @@ describe('sortConfig', () => { expect(routes).toMatchSnapshot(); }); - test('should sort route config given a baseURL', () => { + it('sorts route config given a baseURL', () => { const baseURL = '/latest'; const routes: RouteConfig[] = [ { diff --git a/packages/docusaurus/src/server/plugins/__tests__/pluginIds.test.ts b/packages/docusaurus/src/server/plugins/__tests__/pluginIds.test.ts index 8621ac521703..0c04a3fc03bd 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/pluginIds.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/pluginIds.test.ts @@ -17,7 +17,7 @@ function createTestPlugin(name: string, id?: string): InitializedPlugin { } describe('ensureUniquePluginInstanceIds', () => { - test('accept single instance plugins', async () => { + it('accept single instance plugins', async () => { ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs'), createTestPlugin('plugin-blog'), @@ -25,7 +25,7 @@ describe('ensureUniquePluginInstanceIds', () => { ]); }); - test('accept single instance plugins, all with sameId', async () => { + it('accept single instance plugins, all with sameId', async () => { ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs', 'sameId'), createTestPlugin('plugin-blog', 'sameId'), @@ -33,7 +33,7 @@ describe('ensureUniquePluginInstanceIds', () => { ]); }); - test('accept multi instance plugins without id', async () => { + it('accept multi instance plugins without id', async () => { ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs', 'ios'), createTestPlugin('plugin-docs', 'android'), @@ -41,7 +41,7 @@ describe('ensureUniquePluginInstanceIds', () => { ]); }); - test('reject multi instance plugins without id', async () => { + it('reject multi instance plugins without id', async () => { expect(() => ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs'), @@ -50,7 +50,7 @@ describe('ensureUniquePluginInstanceIds', () => { ).toThrowErrorMatchingSnapshot(); }); - test('reject multi instance plugins with same id', async () => { + it('reject multi instance plugins with same id', async () => { expect(() => ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs', 'sameId'), @@ -59,7 +59,7 @@ describe('ensureUniquePluginInstanceIds', () => { ).toThrowErrorMatchingSnapshot(); }); - test('reject multi instance plugins with some without id', async () => { + it('reject multi instance plugins with some without id', async () => { expect(() => ensureUniquePluginInstanceIds([ createTestPlugin('plugin-docs'), diff --git a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..34a36d41fc66 --- /dev/null +++ b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,164 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadPresets array form 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + undefined, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + ], + "themes": Array [], +} +`; + +exports[`loadPresets array form composite 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + Object { + "path": "../", + }, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + Array [ + "@docusaurus/plugin-content-pages", + Object { + "path": "../", + }, + ], + Array [ + "@docusaurus/plugin-sitemap", + undefined, + ], + ], + "themes": Array [], +} +`; + +exports[`loadPresets array form with options 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + Object { + "path": "../", + }, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + ], + "themes": Array [], +} +`; + +exports[`loadPresets mixed form 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + Object { + "path": "../", + }, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + Array [ + "@docusaurus/plugin-content-pages", + undefined, + ], + Array [ + "@docusaurus/plugin-sitemap", + undefined, + ], + ], + "themes": Array [], +} +`; + +exports[`loadPresets mixed form with themes 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + Object { + "path": "../", + }, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + Array [ + "@docusaurus/plugin-content-pages", + undefined, + ], + Array [ + "@docusaurus/plugin-sitemap", + undefined, + ], + Array [ + "@docusaurus/plugin-test", + undefined, + ], + ], + "themes": Array [ + Array [ + "@docusaurus/theme-classic", + undefined, + ], + ], +} +`; + +exports[`loadPresets string form 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + undefined, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + ], + "themes": Array [], +} +`; + +exports[`loadPresets string form composite 1`] = ` +Object { + "plugins": Array [ + Array [ + "@docusaurus/plugin-content-docs", + undefined, + ], + Array [ + "@docusaurus/plugin-content-blog", + undefined, + ], + Array [ + "@docusaurus/plugin-content-pages", + undefined, + ], + Array [ + "@docusaurus/plugin-sitemap", + undefined, + ], + ], + "themes": Array [], +} +`; diff --git a/packages/docusaurus/src/server/presets/__tests__/index.test.ts b/packages/docusaurus/src/server/presets/__tests__/index.test.ts index 5066901d1fb4..68261597533b 100644 --- a/packages/docusaurus/src/server/presets/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/presets/__tests__/index.test.ts @@ -11,7 +11,7 @@ import loadPresets from '../index'; import type {LoadContext} from '@docusaurus/types'; describe('loadPresets', () => { - test('no presets', async () => { + it('no presets', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -27,7 +27,7 @@ describe('loadPresets', () => { `); }); - test('string form', async () => { + it('string form', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -35,24 +35,10 @@ describe('loadPresets', () => { }, } as LoadContext; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - undefined, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('string form composite', async () => { + it('string form composite', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -63,32 +49,10 @@ describe('loadPresets', () => { }, } as LoadContext; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - undefined, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - Array [ - "@docusaurus/plugin-content-pages", - undefined, - ], - Array [ - "@docusaurus/plugin-sitemap", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('array form', async () => { + it('array form', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -96,24 +60,10 @@ describe('loadPresets', () => { }, } as Partial; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - undefined, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('array form with options', async () => { + it('array form with options', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -126,26 +76,10 @@ describe('loadPresets', () => { }, } as Partial; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - Object { - "path": "../", - }, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('array form composite', async () => { + it('array form composite', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -162,36 +96,10 @@ describe('loadPresets', () => { }, } as Partial; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - Object { - "path": "../", - }, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - Array [ - "@docusaurus/plugin-content-pages", - Object { - "path": "../", - }, - ], - Array [ - "@docusaurus/plugin-sitemap", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('mixed form', async () => { + it('mixed form', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -205,34 +113,10 @@ describe('loadPresets', () => { }, } as LoadContext; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - Object { - "path": "../", - }, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - Array [ - "@docusaurus/plugin-content-pages", - undefined, - ], - Array [ - "@docusaurus/plugin-sitemap", - undefined, - ], - ], - "themes": Array [], - } - `); + expect(presets).toMatchSnapshot(); }); - test('mixed form with themes', async () => { + it('mixed form with themes', async () => { const context = { siteConfigPath: __dirname, siteConfig: { @@ -247,39 +131,6 @@ describe('loadPresets', () => { }, } as LoadContext; const presets = await loadPresets(context); - expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [ - Array [ - "@docusaurus/plugin-content-docs", - Object { - "path": "../", - }, - ], - Array [ - "@docusaurus/plugin-content-blog", - undefined, - ], - Array [ - "@docusaurus/plugin-content-pages", - undefined, - ], - Array [ - "@docusaurus/plugin-sitemap", - undefined, - ], - Array [ - "@docusaurus/plugin-test", - undefined, - ], - ], - "themes": Array [ - Array [ - "@docusaurus/theme-classic", - undefined, - ], - ], - } - `); + expect(presets).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts index dd140c3ee141..cb2f7c149e47 100644 --- a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts +++ b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts @@ -10,7 +10,7 @@ import fs from 'fs-extra'; import themeAlias from '../alias'; describe('themeAlias', () => { - test('valid themePath 1 with components', async () => { + it('valid themePath 1 with components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-1'); const alias = await themeAlias(themePath, true); @@ -26,7 +26,7 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - test('valid themePath 1 with components without original', async () => { + it('valid themePath 1 with components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-1'); const alias = await themeAlias(themePath, false); @@ -40,7 +40,7 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - test('valid themePath 2 with components', async () => { + it('valid themePath 2 with components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-2'); const alias = await themeAlias(themePath, true); @@ -83,7 +83,7 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - test('valid themePath 2 with components without original', async () => { + it('valid themePath 2 with components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-2'); const alias = await themeAlias(themePath, false); @@ -107,7 +107,7 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - test('valid themePath with no components', async () => { + it('valid themePath with no components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'empty-theme'); await fs.ensureDir(themePath); @@ -115,7 +115,7 @@ describe('themeAlias', () => { expect(alias).toEqual({}); }); - test('valid themePath with no components without original', async () => { + it('valid themePath with no components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'empty-theme'); await fs.ensureDir(themePath); @@ -123,7 +123,7 @@ describe('themeAlias', () => { expect(alias).toEqual({}); }); - test('invalid themePath that does not exist', async () => { + it('invalid themePath that does not exist', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, '__noExist__'); const alias = await themeAlias(themePath, true); diff --git a/packages/docusaurus/src/server/themes/__tests__/index.test.ts b/packages/docusaurus/src/server/themes/__tests__/index.test.ts index 9c42f76074ef..aa70330d661f 100644 --- a/packages/docusaurus/src/server/themes/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/themes/__tests__/index.test.ts @@ -9,7 +9,7 @@ import path from 'path'; import {loadThemeAliases} from '../index'; describe('loadThemeAliases', () => { - test('next alias can override the previous alias', async () => { + it('next alias can override the previous alias', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const theme1Path = path.join(fixtures, 'theme-1'); const theme2Path = path.join(fixtures, 'theme-2'); diff --git a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts index 305c5a8aeb54..fd9c7818f655 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts @@ -52,7 +52,7 @@ async function createTmpTranslationFile( } describe('ensureTranslationFileContent', () => { - test('should pass valid translation file content', () => { + it('passes valid translation file content', () => { ensureTranslationFileContent({}); ensureTranslationFileContent({key1: {message: ''}}); ensureTranslationFileContent({key1: {message: 'abc'}}); @@ -63,7 +63,7 @@ describe('ensureTranslationFileContent', () => { }); }); - test('should fail for invalid translation file content', () => { + it('fails for invalid translation file content', () => { expect(() => ensureTranslationFileContent(null), ).toThrowErrorMatchingInlineSnapshot( @@ -101,7 +101,7 @@ describe('ensureTranslationFileContent', () => { }); describe('writeTranslationFileContent', () => { - test('should create new translation file', async () => { + it('creates new translation file', async () => { const {filePath, readFile} = await createTmpTranslationFile(null); await writeTranslationFileContent({ @@ -120,7 +120,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should create new translation file with prefix', async () => { + it('creates new translation file with prefix', async () => { const {filePath, readFile} = await createTmpTranslationFile(null); await writeTranslationFileContent({ @@ -142,7 +142,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should append missing translations', async () => { + it('appends missing translations', async () => { const {filePath, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, @@ -167,7 +167,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should append missing translations with prefix', async () => { + it('appends missing translations with prefix', async () => { const {filePath, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); @@ -189,7 +189,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should override missing translations', async () => { + it('overrides missing translations', async () => { const {filePath, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); @@ -211,7 +211,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should override missing translations with prefix', async () => { + it('overrides missing translations with prefix', async () => { const {filePath, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); @@ -234,7 +234,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should always override message description', async () => { + it('always overrides message description', async () => { const {filePath, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message', description: 'key1 desc'}, key2: {message: 'key2 message', description: 'key2 desc'}, @@ -257,7 +257,7 @@ describe('writeTranslationFileContent', () => { }); }); - test('should throw for invalid content', async () => { + it('throws for invalid content', async () => { const {filePath} = await createTmpTranslationFile( // @ts-expect-error: bad content on purpose {bad: 'content'}, @@ -277,7 +277,7 @@ describe('writeTranslationFileContent', () => { }); describe('writePluginTranslations', () => { - test('should write plugin translations', async () => { + it('writes plugin translations', async () => { const siteDir = await createTmpSiteDir(); const filePath = path.join( @@ -315,7 +315,7 @@ describe('writePluginTranslations', () => { }); }); - test('should write plugin translations consecutively with different options', async () => { + it('writes plugin translations consecutively with different options', async () => { const siteDir = await createTmpSiteDir(); const filePath = path.join( @@ -396,7 +396,7 @@ describe('writePluginTranslations', () => { }); describe('localizePluginTranslationFile', () => { - test('not localize if localized file does not exist', async () => { + it('does not localize if localized file does not exist', async () => { const siteDir = await createTmpSiteDir(); const translationFile: TranslationFile = { @@ -422,7 +422,7 @@ describe('localizePluginTranslationFile', () => { expect(localizedTranslationFile).toEqual(translationFile); }); - test('not localize if localized file does not exist 2', async () => { + it('does not localize if localized file does not exist 2', async () => { const siteDir = await createTmpSiteDir(); await writeTranslationFileContent({ @@ -481,21 +481,21 @@ describe('getPluginsDefaultCodeTranslationMessages', () => { return {getDefaultCodeTranslationMessages: fn} as InitializedPlugin; } - test('for empty plugins', async () => { + it('works for empty plugins', async () => { const plugins: InitializedPlugin[] = []; await expect( getPluginsDefaultCodeTranslationMessages(plugins), ).resolves.toEqual({}); }); - test('for 1 plugin without lifecycle', async () => { + it('works for 1 plugin without lifecycle', async () => { const plugins: InitializedPlugin[] = [createTestPlugin(undefined)]; await expect( getPluginsDefaultCodeTranslationMessages(plugins), ).resolves.toEqual({}); }); - test('for 1 plugin with lifecycle', async () => { + it('works for 1 plugin with lifecycle', async () => { const plugins: InitializedPlugin[] = [ createTestPlugin(async () => ({ a: '1', @@ -510,7 +510,7 @@ describe('getPluginsDefaultCodeTranslationMessages', () => { }); }); - test('for 2 plugins with lifecycles', async () => { + it('works for 2 plugins with lifecycles', async () => { const plugins: InitializedPlugin[] = [ createTestPlugin(async () => ({ a: '1', @@ -531,7 +531,7 @@ describe('getPluginsDefaultCodeTranslationMessages', () => { }); }); - test('for realistic use-case', async () => { + it('works for realistic use-case', async () => { const plugins: InitializedPlugin[] = [ createTestPlugin(undefined), createTestPlugin(async () => ({ @@ -566,7 +566,7 @@ describe('applyDefaultCodeTranslations', () => { consoleSpy.mockClear(); }); - test('for no code and message', () => { + it('works for no code and message', () => { expect( applyDefaultCodeTranslations({ extractedCodeTranslations: {}, @@ -576,7 +576,7 @@ describe('applyDefaultCodeTranslations', () => { expect(consoleSpy).toHaveBeenCalledTimes(0); }); - test('for code and message', () => { + it('works for code and message', () => { expect( applyDefaultCodeTranslations({ extractedCodeTranslations: { @@ -598,7 +598,7 @@ describe('applyDefaultCodeTranslations', () => { expect(consoleSpy).toHaveBeenCalledTimes(0); }); - test('for code and message mismatch', () => { + it('works for code and message mismatch', () => { expect( applyDefaultCodeTranslations({ extractedCodeTranslations: { @@ -621,7 +621,7 @@ describe('applyDefaultCodeTranslations', () => { expect(consoleSpy.mock.calls[0][0]).toMatch(/unknownId/); }); - test('for realistic scenario', () => { + it('works for realistic scenario', () => { expect( applyDefaultCodeTranslations({ extractedCodeTranslations: { diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index dd333ebde359..1f899ac34ab9 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -47,8 +47,8 @@ async function createTmpSourceCodeFile({ }; } -describe('extractSourceCodeTranslations', () => { - test('throw for bad source code', async () => { +describe('extractSourceCodeFileTranslations', () => { + it('throws for bad source code', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -58,7 +58,7 @@ const default => { `, }); - const errorMock = jest.spyOn(console, 'error').mockImplementation(); + const errorMock = jest.spyOn(console, 'error').mockImplementation(() => {}); await expect( extractSourceCodeFileTranslations(sourceCodeFilePath, TestBabelOptions), @@ -71,7 +71,7 @@ const default => { ); }); - test('extract nothing from untranslated source code', async () => { + it('extracts nothing from untranslated source code', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -91,7 +91,7 @@ const unrelated = 42; }); }); - test('extract from a translate() functions calls', async () => { + it('extracts from a translate() functions calls', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -124,7 +124,7 @@ export default function MyComponent() { }); }); - test('extract from a components', async () => { + it('extracts from a components', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -159,7 +159,7 @@ export default function MyComponent() { }); }); - test('extract statically evaluable content', async () => { + it('extracts statically evaluable content', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -220,7 +220,7 @@ export default function MyComponent() { }); }); - test('extract from TypeScript file', async () => { + it('extracts from TypeScript file', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'tsx', content: ` @@ -252,7 +252,7 @@ export default function MyComponent(props: ComponentProps) { }); }); - test('do not extract from functions that is not docusaurus provided', async () => { + it('does not extract from functions that is not docusaurus provided', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -277,7 +277,7 @@ export default function somethingElse() { }); }); - test('do not extract from functions that is internal', async () => { + it('does not extract from functions that is internal', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -304,7 +304,7 @@ export default function somethingElse() { }); }); - test('recognize aliased imports', async () => { + it('recognizes aliased imports', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -354,7 +354,7 @@ export default function () { }); }); - test('recognize aliased imports as string literal', async () => { + it('recognizes aliased imports as string literal', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -388,7 +388,7 @@ export default function () { }); }); - test('warn about id if no children', async () => { + it('warns about id if no children', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -419,7 +419,7 @@ Full code: `, }); }); - test('warn about dynamic id', async () => { + it('warns about dynamic id', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -455,7 +455,7 @@ Full code: foo`, }); }); - test('warn about dynamic children', async () => { + it('warns about dynamic children', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -485,7 +485,7 @@ Full code:
    hhh`, }); }); - test('warn about dynamic translate argument', async () => { + it('warns about dynamic translate argument', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -513,7 +513,7 @@ Full code: translate(foo)`, }); }); - test('warn about too many arguments', async () => { + it('warns about too many arguments', async () => { const {sourceCodeFilePath} = await createTmpSourceCodeFile({ extension: 'js', content: ` @@ -545,7 +545,7 @@ Full code: translate({ }); describe('extractSiteSourceCodeTranslations', () => { - test('should extract translation from all plugins source code', async () => { + it('extracts translation from all plugins source code', async () => { const siteDir = await createTmpDir(); const siteComponentFile1 = path.join( diff --git a/packages/docusaurus/src/server/versions/__tests__/index.test.ts b/packages/docusaurus/src/server/versions/__tests__/index.test.ts index e5542ffbfbaf..bf8e15db6c9f 100644 --- a/packages/docusaurus/src/server/versions/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/versions/__tests__/index.test.ts @@ -9,7 +9,7 @@ import {getPluginVersion} from '..'; import path from 'path'; describe('getPluginVersion', () => { - it('Can detect external packages plugins versions of correctly.', async () => { + it('detects external packages plugins versions', async () => { await expect( getPluginVersion( path.join(__dirname, '__fixtures__/dummy-plugin.js'), @@ -19,7 +19,7 @@ describe('getPluginVersion', () => { ).resolves.toEqual({type: 'package', version: 'random-version'}); }); - it('Can detect project plugins versions correctly.', async () => { + it('detects project plugins versions', async () => { await expect( getPluginVersion( path.join(__dirname, '__fixtures__/dummy-plugin.js'), @@ -29,7 +29,7 @@ describe('getPluginVersion', () => { ).resolves.toEqual({type: 'project'}); }); - it('Can detect local packages versions correctly.', async () => { + it('detect local packages versions', async () => { await expect(getPluginVersion('/', '/')).resolves.toEqual({type: 'local'}); }); }); diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index 303c36891dc3..c593268eeadd 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`base webpack config should create webpack aliases 1`] = ` +exports[`base webpack config creates webpack aliases 1`] = ` Object { "@docusaurus/BrowserOnly": "../../../../client/exports/BrowserOnly.tsx", "@docusaurus/ComponentCreator": "../../../../client/exports/ComponentCreator.tsx", @@ -47,7 +47,7 @@ Object { } `; -exports[`getDocusaurusAliases() return appropriate webpack aliases 1`] = ` +exports[`getDocusaurusAliases() returns appropriate webpack aliases 1`] = ` Object { "@docusaurus/BrowserOnly": "../../client/exports/BrowserOnly.tsx", "@docusaurus/ComponentCreator": "../../client/exports/ComponentCreator.tsx", diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts index 397781eb84d8..6c21fd1338d8 100644 --- a/packages/docusaurus/src/webpack/__tests__/base.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts @@ -20,7 +20,7 @@ import _ from 'lodash'; import type {Props, ThemeAliases} from '@docusaurus/types'; describe('babel transpilation exclude logic', () => { - test('always transpile client dir files', () => { + it('always transpiles client dir files', () => { const clientFiles = [ 'App.js', 'clientEntry.js', @@ -32,7 +32,7 @@ describe('babel transpilation exclude logic', () => { }); }); - test('always transpile non node_module files', () => { + it('always transpiles non node_module files', () => { const moduleFiles = [ '/pages/user/App.jsx', '/website/src/components/foo.js', @@ -43,7 +43,7 @@ describe('babel transpilation exclude logic', () => { }); }); - test('transpile docusaurus npm packages even in node_modules', () => { + it('transpiles docusaurus npm packages even in node_modules', () => { const moduleFiles = [ '/website/node_modules/docusaurus-theme-search/theme/Navbar/index.js', 'node_modules/@docusaurus/theme-classic/theme/Layout.js', @@ -54,7 +54,7 @@ describe('babel transpilation exclude logic', () => { }); }); - test('does not transpile node_modules', () => { + it('does not transpile node_modules', () => { const moduleFiles = [ 'node_modules/react-toggle.js', '/website/node_modules/react-trend/index.js', @@ -69,7 +69,7 @@ describe('babel transpilation exclude logic', () => { }); describe('getDocusaurusAliases()', () => { - test('return appropriate webpack aliases', async () => { + it('returns appropriate webpack aliases', async () => { // using relative paths makes tests work everywhere const relativeDocusaurusAliases = _.mapValues( await getDocusaurusAliases(), @@ -121,7 +121,7 @@ describe('base webpack config', () => { jest.restoreAllMocks(); }); - test('should create webpack aliases', async () => { + it('creates webpack aliases', async () => { // @ts-expect-error: Docusaurus webpack alias is always an object const aliases: ThemeAliases = (await createBaseConfig(props, true)).resolve?.alias ?? {}; @@ -132,7 +132,7 @@ describe('base webpack config', () => { expect(relativeAliases).toMatchSnapshot(); }); - test('should use svg rule', async () => { + it('uses svg rule', async () => { const fileLoaderUtils = utils.getFileLoaderUtils(); const mockSvg = jest.spyOn(fileLoaderUtils.rules, 'svg'); jest diff --git a/packages/docusaurus/src/webpack/__tests__/client.test.ts b/packages/docusaurus/src/webpack/__tests__/client.test.ts index e5e526a915d4..87c825eb9802 100644 --- a/packages/docusaurus/src/webpack/__tests__/client.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/client.test.ts @@ -5,23 +5,20 @@ * LICENSE file in the root directory of this source tree. */ -import {jest} from '@jest/globals'; import webpack from 'webpack'; import createClientConfig from '../client'; import loadSetup from '../../server/__tests__/testUtils'; describe('webpack dev config', () => { - test('simple', async () => { - console.log = jest.fn(); + it('simple', async () => { const props = await loadSetup('simple'); const config = await createClientConfig(props); const errors = webpack.validate(config); expect(errors).toBeUndefined(); }); - test('custom', async () => { - console.log = jest.fn(); + it('custom', async () => { const props = await loadSetup('custom'); const config = await createClientConfig(props); const errors = webpack.validate(config); diff --git a/packages/docusaurus/src/webpack/__tests__/server.test.ts b/packages/docusaurus/src/webpack/__tests__/server.test.ts index 6be134ac5faf..a7a9641799aa 100644 --- a/packages/docusaurus/src/webpack/__tests__/server.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/server.test.ts @@ -12,7 +12,7 @@ import createServerConfig from '../server'; import loadSetup from '../../server/__tests__/testUtils'; describe('webpack production config', () => { - test('simple', async () => { + it('simple', async () => { console.log = jest.fn(); const props = await loadSetup('simple'); const config = await createServerConfig({props}); @@ -20,7 +20,7 @@ describe('webpack production config', () => { expect(errors).toBeUndefined(); }); - test('custom', async () => { + it('custom', async () => { console.log = jest.fn(); const props = await loadSetup('custom'); const config = await createServerConfig({props}); diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index 1dc3fb7fb259..a19193934c47 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -19,7 +19,7 @@ import type { } from '@docusaurus/types'; describe('customize JS loader', () => { - test('getCustomizableJSLoader defaults to babel loader', () => { + it('getCustomizableJSLoader defaults to babel loader', () => { expect(getCustomizableJSLoader()({isServer: true}).loader).toBe( require.resolve('babel-loader'), ); @@ -28,7 +28,7 @@ describe('customize JS loader', () => { ); }); - test('getCustomizableJSLoader accepts loaders with preset', () => { + it('getCustomizableJSLoader accepts loaders with preset', () => { expect(getCustomizableJSLoader('babel')({isServer: true}).loader).toBe( require.resolve('babel-loader'), ); @@ -37,7 +37,7 @@ describe('customize JS loader', () => { ); }); - test('getCustomizableJSLoader allows customization', () => { + it('getCustomizableJSLoader allows customization', () => { const customJSLoader = (isServer: boolean): RuleSetRule => ({ loader: 'my-fast-js-loader', options: String(isServer), @@ -53,7 +53,7 @@ describe('customize JS loader', () => { }); describe('extending generated webpack config', () => { - test('direct mutation on generated webpack config object', async () => { + it('direct mutation on generated webpack config object', async () => { // fake generated webpack config let config: Configuration = { output: { @@ -90,7 +90,7 @@ describe('extending generated webpack config', () => { expect(errors).toBeUndefined(); }); - test('webpack-merge with user webpack config object', async () => { + it('webpack-merge with user webpack config object', async () => { let config: Configuration = { output: { path: __dirname, @@ -120,7 +120,7 @@ describe('extending generated webpack config', () => { expect(errors).toBeUndefined(); }); - test('webpack-merge with custom strategy', async () => { + it('webpack-merge with custom strategy', async () => { const config: Configuration = { module: { rules: [{use: 'xxx'}, {use: 'yyy'}], @@ -178,7 +178,7 @@ describe('extending generated webpack config', () => { }); describe('extending PostCSS', () => { - test('user plugin should be appended in PostCSS loader', () => { + it('user plugin should be appended in PostCSS loader', () => { let webpackConfig: Configuration = { output: { path: __dirname, diff --git a/packages/lqip-loader/src/__tests__/lqip.test.ts b/packages/lqip-loader/src/__tests__/lqip.test.ts index 180be8b0f046..01e6255e18c6 100644 --- a/packages/lqip-loader/src/__tests__/lqip.test.ts +++ b/packages/lqip-loader/src/__tests__/lqip.test.ts @@ -6,25 +6,27 @@ */ import path from 'path'; -import * as lqip from '../lqip'; +import {base64, palette} from '../lqip'; -describe('lqip library', () => { - const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg'); - const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg'); +const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg'); +const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg'); - it('should reject unknown or unsupported file format', async () => { - await expect(lqip.base64(invalidPath)).rejects.toThrow( +describe('base64', () => { + it('rejects unknown or unsupported file format', async () => { + await expect(base64(invalidPath)).rejects.toThrow( /Error: Input file is missing or uses unsupported image format, lqip v.*/, ); }); - it('should generate a valid base64', async () => { + it('generates a valid base64', async () => { const expectedBase64 = 'data:image/jpeg;base64,/9j/2wBDA'; - await expect(lqip.base64(imgPath)).resolves.toContain(expectedBase64); + await expect(base64(imgPath)).resolves.toContain(expectedBase64); }); +}); - it('should generate a valid color palette', async () => { - const imgPalette = await lqip.palette(imgPath); +describe('palette', () => { + it('generates a valid color palette', async () => { + const imgPalette = await palette(imgPath); expect(imgPalette).toHaveLength(6); expect(imgPalette).toContain('#578ca1'); }); diff --git a/packages/lqip-loader/src/__tests__/utils.test.ts b/packages/lqip-loader/src/__tests__/utils.test.ts index f0bd6d021f91..0f32e2d4b989 100644 --- a/packages/lqip-loader/src/__tests__/utils.test.ts +++ b/packages/lqip-loader/src/__tests__/utils.test.ts @@ -12,7 +12,7 @@ import type {Palette} from 'node-vibrant/lib/color'; import {toPalette, toBase64} from '../utils'; describe('toBase64', () => { - test('should return a properly formatted Base64 image string', () => { + it('returns a properly formatted Base64 image string', () => { const mockedMimeType = 'image/jpeg'; const mockedBase64Data = Buffer.from('hello world'); expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual( @@ -35,11 +35,11 @@ describe('toPalette', () => { }); }); - it('should return 6 hex colours sorted by popularity', () => { + it('returns 6 hex colours sorted by popularity', () => { expect(toPalette(correctTestSwatch)).toHaveLength(6); }); - it('should return 5 hex colours with no errors if a palette was incomplete', () => { + it('returns 5 hex colours with no errors if a palette was incomplete', () => { expect(toPalette(testSwatchWithNull)).toHaveLength(5); }); }); diff --git a/packages/stylelint-copyright/__tests__/index.test.js b/packages/stylelint-copyright/__tests__/index.test.js index 18c02f703906..e44dfbbeeb24 100644 --- a/packages/stylelint-copyright/__tests__/index.test.js +++ b/packages/stylelint-copyright/__tests__/index.test.js @@ -19,14 +19,14 @@ function getOutputCss(output) { } function testStylelintRule(config, tests) { - describe(tests.ruleName, () => { + describe(`${tests.ruleName}`, () => { const checkTestCaseContent = (testCase) => testCase.description || testCase.code || 'no description'; if (tests.accept && tests.accept.length) { describe('accept cases', () => { tests.accept.forEach((testCase) => { - test(checkTestCaseContent(testCase), async () => { + it(`${checkTestCaseContent(testCase)}`, async () => { const options = { code: testCase.code, config, @@ -49,7 +49,7 @@ function testStylelintRule(config, tests) { if (tests.reject && tests.reject.length) { describe('reject cases', () => { tests.reject.forEach((testCase) => { - test(checkTestCaseContent(testCase), async () => { + it(`${checkTestCaseContent(testCase)}`, async () => { const options = { code: testCase.code, config, diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index 183d9c37eeb6..8d9b4aa35a99 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -45,55 +45,53 @@ expect.extend({ }, }); -describe('users', () => { - sortedUsers.forEach((user) => { - test(user.title, async () => { - Joi.attempt( - user, - Joi.object({ - title: Joi.string().required(), - description: Joi.string().required(), - website: Joi.string() - .pattern(/^https?:\/\//) - .message('') - .required(), - // The preview should be jest/emptyModule - preview: Joi.object({}).unknown(false).required().messages({ - 'object.base': - 'The image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs. It must be imported with require().', - }), - tags: Joi.array() - .items(...TagList) - .required(), - source: Joi.string().allow(null).required().messages({ - 'any.required': - "The source attribute is required.\nIf your Docusaurus site is not open-source, please make it explicit with 'source: null'.", - }), - }).unknown(false), +describe('users data', () => { + it.each(sortedUsers)('$title', async (user) => { + Joi.attempt( + user, + Joi.object({ + title: Joi.string().required(), + description: Joi.string().required(), + website: Joi.string() + .pattern(/^https?:\/\//) + .message('') + .required(), + // The preview should be jest/emptyModule + preview: Joi.object({}).unknown(false).required().messages({ + 'object.base': + 'The image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs. It must be imported with require().', + }), + tags: Joi.array() + .items(...TagList) + .required(), + source: Joi.string().allow(null).required().messages({ + 'any.required': + "The source attribute is required.\nIf your Docusaurus site is not open-source, please make it explicit with 'source: null'.", + }), + }).unknown(false), + ); + if (user.tags.includes('opensource') && user.source === null) { + throw new Error( + "You can't add the 'opensource' tag to a site that does not have a link to source code. Please add your source code, or remove this tag.", ); - if (user.tags.includes('opensource') && user.source === null) { - throw new Error( - "You can't add the 'opensource' tag to a site that does not have a link to source code. Please add your source code, or remove this tag.", - ); - } else if (user.source !== null && !user.tags.includes('opensource')) { - throw new Error( - "For open-source sites, please add the 'opensource' tag.", - ); - } - }); + } else if (user.source !== null && !user.tags.includes('opensource')) { + throw new Error( + "For open-source sites, please add the 'opensource' tag.", + ); + } }); +}); +describe('preview images', () => { const imageDir = path.join(__dirname, '../showcase'); // eslint-disable-next-line no-restricted-properties const files = fs .readdirSync(imageDir) .filter((file) => ['.png', 'jpg', '.jpeg'].includes(path.extname(file))); - files.forEach((file) => { - test(file, () => { - const size = imageSize(path.join(imageDir, file)); + it.each(files)('%s', (file) => { + const size = imageSize(path.join(imageDir, file)); - expect(size).toHaveGoodDimensions(); - }); + expect(size).toHaveGoodDimensions(); }); }); From f6baaa6b753fa41a99d9ab957317bdb609d9a5c8 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 12 Mar 2022 13:17:21 +0800 Subject: [PATCH 004/405] test(theme-common): improve test coverage (#6902) * test(theme-common): improve test coverage * revert --- .eslintrc.js | 4 + package.json | 1 + ...ration.test.ts.snap => index.test.ts.snap} | 24 +-- .../src/__tests__/frontMatter.test.ts | 12 +- .../{migration.test.ts => index.test.ts} | 9 +- .../src/index.d.ts | 8 +- .../src/__tests__/writeRedirectFiles.test.ts | 16 +- .../src/__tests__/blogUtils.test.ts | 12 +- .../src/__tests__/index.test.ts | 4 +- .../src/__tests__/pluginOptionSchema.test.ts | 14 +- .../__snapshots__/index.test.ts.snap | 23 ++ .../src/__tests__/docs.test.ts | 36 ++-- .../src/__tests__/index.test.ts | 106 ++++----- .../src/__tests__/numberPrefix.test.ts | 62 +++--- .../src/__tests__/options.test.ts | 14 +- .../src/__tests__/slug.test.ts | 50 ++--- .../client/__tests__/docsClientUtils.test.ts | 28 +-- .../src/sidebars/__tests__/utils.test.ts | 18 +- packages/docusaurus-theme-common/package.json | 1 - .../__snapshots__/tocUtils.test.ts.snap | 40 ++++ .../utils/__tests__/codeBlockUtils.test.ts | 22 +- .../src/utils/__tests__/docsUtils.test.tsx | 203 ++++++++++++------ .../src/utils/__tests__/footerUtils.test.ts | 37 ++++ .../src/utils/__tests__/generalUtils.test.tsx | 33 +++ .../src/utils/__tests__/regexpUtils.test.ts | 16 +- .../src/utils/__tests__/routesUtils.test.ts | 6 +- .../src/utils/__tests__/searchUtils.test.ts | 2 +- .../src/utils/__tests__/tocUtils.test.ts | 79 +++---- .../__tests__/useAlternatePageUtils.test.tsx | 124 +++++++++++ .../utils/__tests__/useLocalPathname.test.tsx | 38 ++++ .../utils/__tests__/usePluralForm.test.tsx | 79 +++++++ .../src/utils/docsUtils.tsx | 2 +- .../src/utils/generalUtils.ts | 4 +- .../src/utils/routesUtils.ts | 5 +- .../src/utils/usePluralForm.ts | 22 +- packages/docusaurus-types/src/index.d.ts | 8 + .../src/__tests__/applyTrailingSlash.test.ts | 118 +++++----- .../src/__tests__/emitUtils.test.ts | 16 +- .../src/__tests__/globUtils.test.ts | 118 +++++----- .../src/__tests__/jsUtils.test.ts | 18 +- .../src/__tests__/markdownParser.test.ts | 20 +- .../src/__tests__/pathUtils.test.ts | 6 +- .../src/__tests__/slugger.test.ts | 16 +- .../src/__tests__/urlUtils.test.ts | 40 ++-- .../exports/__tests__/Translate.test.tsx | 6 +- .../exports/__tests__/useBaseUrl.test.ts | 140 ------------ .../exports/__tests__/useBaseUrl.test.tsx | 150 +++++++++++++ .../src/commands/__tests__/deploy.test.ts | 16 +- .../__tests__/writeHeadingIds.test.ts | 18 +- .../swizzle/__tests__/components.test.ts | 48 ++--- .../server/__tests__/configValidation.test.ts | 4 +- .../src/server/__tests__/i18n.test.ts | 10 +- .../__tests__/__snapshots__/init.test.ts.snap | 2 +- .../src/server/plugins/__tests__/init.test.ts | 6 +- .../__tests__/translations.test.ts | 4 +- .../src/webpack/__tests__/base.test.ts | 8 +- .../src/webpack/__tests__/server.test.ts | 4 +- .../src/webpack/__tests__/utils.test.ts | 4 +- .../lqip-loader/src/__tests__/utils.test.ts | 2 +- 59 files changed, 1182 insertions(+), 754 deletions(-) rename packages/docusaurus-migrate/src/__tests__/__snapshots__/{migration.test.ts.snap => index.test.ts.snap} (95%) rename packages/docusaurus-migrate/src/__tests__/{migration.test.ts => index.test.ts} (92%) create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/footerUtils.test.ts create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx delete mode 100644 packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts create mode 100644 packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 236f14d62359..d82bb95342cf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -211,8 +211,12 @@ module.exports = { WARNING, {maxSize: Infinity, inlineMaxSize: 10}, ], + 'jest/no-test-return-statement': ERROR, 'jest/prefer-expect-resolves': WARNING, 'jest/prefer-lowercase-title': [WARNING, {ignore: ['describe']}], + 'jest/prefer-spy-on': WARNING, + 'jest/prefer-to-be': WARNING, + 'jest/prefer-to-have-length': WARNING, 'jest/require-top-level-describe': ERROR, 'jest/valid-title': [ ERROR, diff --git a/package.json b/package.json index f442643e5d05..50530105b82e 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@babel/core": "^7.17.5", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", + "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", "@types/lodash": "^4.14.179", diff --git a/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap similarity index 95% rename from packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap rename to packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap index b5be0f1ead24..750f8e7e9537 100644 --- a/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap +++ b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`migration test complex website: copy 1`] = ` +exports[`migration CLI migrates complex website: copy 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/blog", @@ -17,7 +17,7 @@ Array [ ] `; -exports[`migration test complex website: mkdirp 1`] = ` +exports[`migration CLI migrates complex website: mkdirp 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages", @@ -25,9 +25,9 @@ Array [ ] `; -exports[`migration test complex website: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates complex website: mkdirs 1`] = `Array []`; -exports[`migration test complex website: write 1`] = ` +exports[`migration CLI migrates complex website: write 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/docusaurus.config.js", @@ -183,7 +183,7 @@ Array [ ] `; -exports[`migration test missing versions: copy 1`] = ` +exports[`migration CLI migrates missing versions: copy 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/blog", @@ -200,7 +200,7 @@ Array [ ] `; -exports[`migration test missing versions: mkdirp 1`] = ` +exports[`migration CLI migrates missing versions: mkdirp 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages", @@ -208,9 +208,9 @@ Array [ ] `; -exports[`migration test missing versions: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates missing versions: mkdirs 1`] = `Array []`; -exports[`migration test missing versions: write 1`] = ` +exports[`migration CLI migrates missing versions: write 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/docusaurus.config.js", @@ -366,7 +366,7 @@ Array [ ] `; -exports[`migration test simple website: copy 1`] = ` +exports[`migration CLI migrates simple website: copy 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/website/pages/en", @@ -379,7 +379,7 @@ Array [ ] `; -exports[`migration test simple website: mkdirp 1`] = ` +exports[`migration CLI migrates simple website: mkdirp 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages", @@ -387,9 +387,9 @@ Array [ ] `; -exports[`migration test simple website: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates simple website: mkdirs 1`] = `Array []`; -exports[`migration test simple website: write 1`] = ` +exports[`migration CLI migrates simple website: write 1`] = ` Array [ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/docusaurus.config.js", diff --git a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts index 3f480415b43e..35de9e01cbf5 100644 --- a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts @@ -9,19 +9,19 @@ import {shouldQuotifyFrontMatter} from '../frontMatter'; describe('shouldQuotifyFrontMatter', () => { it('works', () => { - expect(shouldQuotifyFrontMatter(['id', 'value'])).toEqual(false); + expect(shouldQuotifyFrontMatter(['id', 'value'])).toBe(false); expect( shouldQuotifyFrontMatter([ 'title', "Some title front matter with allowed special chars like sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+-_?'`&#()[]§%€$", ]), - ).toEqual(false); + ).toBe(false); - expect(shouldQuotifyFrontMatter(['title', 'Special char :'])).toEqual(true); + expect(shouldQuotifyFrontMatter(['title', 'Special char :'])).toBe(true); - expect(shouldQuotifyFrontMatter(['title', 'value!'])).toEqual(false); - expect(shouldQuotifyFrontMatter(['title', '!value'])).toEqual(true); + expect(shouldQuotifyFrontMatter(['title', 'value!'])).toBe(false); + expect(shouldQuotifyFrontMatter(['title', '!value'])).toBe(true); - expect(shouldQuotifyFrontMatter(['tags', '[tag1, tag2]'])).toEqual(false); + expect(shouldQuotifyFrontMatter(['tags', '[tag1, tag2]'])).toBe(false); }); }); diff --git a/packages/docusaurus-migrate/src/__tests__/migration.test.ts b/packages/docusaurus-migrate/src/__tests__/index.test.ts similarity index 92% rename from packages/docusaurus-migrate/src/__tests__/migration.test.ts rename to packages/docusaurus-migrate/src/__tests__/index.test.ts index be9c4ae9ae31..f4516276d2d9 100644 --- a/packages/docusaurus-migrate/src/__tests__/migration.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/index.test.ts @@ -43,20 +43,21 @@ async function testMigration(siteDir: string, newDir: string) { copyMock.mockRestore(); } -describe('migration test', () => { +describe('migration CLI', () => { const fixtureDir = path.join(__dirname, '__fixtures__'); - it('simple website', async () => { + it('migrates simple website', async () => { const siteDir = path.join(fixtureDir, 'simple_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_simple_site'); await testMigration(siteDir, newDir); }); - it('complex website', async () => { + + it('migrates complex website', async () => { const siteDir = path.join(fixtureDir, 'complex_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_complex_site'); await testMigration(siteDir, newDir); }); - it('missing versions', async () => { + it('migrates missing versions', async () => { const siteDir = path.join(fixtureDir, 'missing_version_website', 'website'); const newDir = path.join(fixtureDir, 'migrated_missing_version_site'); await testMigration(siteDir, newDir); diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 80291f92f409..86c722759c05 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -35,14 +35,8 @@ declare module '@generated/registry' { } declare module '@generated/routes' { - import type {RouteConfig} from 'react-router-config'; + import type {Route} from '@docusaurus/types'; - export type Route = { - readonly path: string; - readonly component: RouteConfig['component']; - readonly exact?: boolean; - readonly routes?: Route[]; - }; const routes: Route[]; export default routes; } diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts index 8cb651fab8a4..215d968b7399 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts @@ -18,25 +18,25 @@ import writeRedirectFiles, { // - https://github.com/facebook/docusaurus/issues/3925 describe('createToUrl', () => { it('creates appropriate redirect urls', async () => { - expect(createToUrl('/', '/docs/something/else')).toEqual( + expect(createToUrl('/', '/docs/something/else')).toBe( '/docs/something/else', ); - expect(createToUrl('/', '/docs/something/else/')).toEqual( + expect(createToUrl('/', '/docs/something/else/')).toBe( '/docs/something/else/', ); - expect(createToUrl('/', 'docs/something/else')).toEqual( + expect(createToUrl('/', 'docs/something/else')).toBe( '/docs/something/else', ); }); it('creates appropriate redirect urls with baseUrl', async () => { - expect(createToUrl('/baseUrl/', '/docs/something/else')).toEqual( + expect(createToUrl('/baseUrl/', '/docs/something/else')).toBe( '/baseUrl/docs/something/else', ); - expect(createToUrl('/baseUrl/', '/docs/something/else/')).toEqual( + expect(createToUrl('/baseUrl/', '/docs/something/else/')).toBe( '/baseUrl/docs/something/else/', ); - expect(createToUrl('/baseUrl/', 'docs/something/else')).toEqual( + expect(createToUrl('/baseUrl/', 'docs/something/else')).toBe( '/baseUrl/docs/something/else', ); }); @@ -177,11 +177,11 @@ describe('writeRedirectFiles', () => { await expect( fs.readFile(filesMetadata[0].fileAbsolutePath, 'utf8'), - ).resolves.toEqual('content 1'); + ).resolves.toBe('content 1'); await expect( fs.readFile(filesMetadata[1].fileAbsolutePath, 'utf8'), - ).resolves.toEqual('content 2'); + ).resolves.toBe('content 2'); }); it('avoid overwriting existing files', async () => { diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts index db3ad1852a53..027979ba52b5 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts @@ -75,17 +75,17 @@ describe('truncate', () => { it('truncates texts', () => { expect( truncate('aaa\n\nbbb\nccc', //), - ).toEqual('aaa\n'); - expect( - truncate('\n\nbbb\nccc', //), - ).toEqual('\n'); + ).toBe('aaa\n'); + expect(truncate('\n\nbbb\nccc', //)).toBe( + '\n', + ); }); it('leaves texts without markers', () => { - expect(truncate('aaa\nbbb\nccc', //)).toEqual( + expect(truncate('aaa\nbbb\nccc', //)).toBe( 'aaa\nbbb\nccc', ); - expect(truncate('', //)).toEqual(''); + expect(truncate('', //)).toBe(''); }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 345847a56cd7..0dca4dfbb4f5 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -341,7 +341,7 @@ describe('blog plugin', () => { (v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)', )!; - expect(localizedBlogPost.metadata.editUrl).toEqual( + expect(localizedBlogPost.metadata.editUrl).toBe( `${BaseEditUrl}/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md`, ); }); @@ -478,7 +478,7 @@ describe('blog plugin', () => { postsPerPage: 2, }); - expect(Object.keys(blogTags).length).toEqual(2); + expect(Object.keys(blogTags)).toHaveLength(2); expect(blogTags).toMatchSnapshot(); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts index 28bbe06b8142..49fa16a21f78 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts @@ -15,7 +15,7 @@ describe('blog plugin options schema', () => { it('normalizes options', () => { const {value, error} = PluginOptionSchema.validate({}); expect(value).toEqual(DEFAULT_OPTIONS); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts correctly defined user options', () => { @@ -32,7 +32,7 @@ describe('blog plugin options schema', () => { ...userOptions, feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, }); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts valid user options', async () => { @@ -49,7 +49,7 @@ describe('blog plugin options schema', () => { }; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual(userOptions); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('throws Error in case of invalid options', () => { @@ -91,7 +91,7 @@ describe('blog plugin options schema', () => { ...DEFAULT_OPTIONS, feedOptions: {type: null}, }); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('contains array with rss + atom for missing feed type', () => { @@ -117,14 +117,14 @@ describe('blog sidebar', () => { const userOptions = {blogSidebarCount: 0}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts "ALL" sidebar count', () => { const userOptions = {blogSidebarCount: 'ALL'}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('rejects "abcdef" sidebar count', () => { @@ -139,7 +139,7 @@ describe('blog sidebar', () => { const userOptions = {blogSidebarTitle: 'all posts'}; const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('rejects 42 sidebar title', () => { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 750029643375..7e1365f46d8a 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -16,6 +16,29 @@ Object { } `; +exports[`sidebar site with wrong sidebar content 1`] = ` +"Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". +These sidebar document ids do not exist: +- goku + +Available document ids are: +- doc with space +- foo/bar +- foo/baz +- headingAsTitle +- hello +- ipsum +- lorem +- rootAbsoluteSlug +- rootRelativeSlug +- rootResolvedSlug +- rootTryToEscapeSlug +- slugs/absoluteSlug +- slugs/relativeSlug +- slugs/resolvedSlug +- slugs/tryToEscapeSlug" +`; + exports[`simple website content 1`] = ` Object { "description": "Images", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 5e4b292fcc54..1fcffb05e720 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -176,7 +176,7 @@ describe('simple site', () => { context, options, }); - expect(versionsMetadata.length).toEqual(1); + expect(versionsMetadata).toHaveLength(1); const [currentVersion] = versionsMetadata; const defaultTestUtils = createTestUtils({ @@ -533,7 +533,7 @@ describe('versioned site', () => { context, options, }); - expect(versionsMetadata.length).toEqual(4); + expect(versionsMetadata).toHaveLength(4); const [currentVersion, version101, version100, versionWithSlugs] = versionsMetadata; @@ -947,28 +947,28 @@ describe('isConventionalDocIndex', () => { directories: ['doesNotMatter'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'readme', directories: ['doesNotMatter'], extension: '.mdx', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'README', directories: ['doesNotMatter'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'ReAdMe', directories: ['doesNotMatter'], extension: '', }), - ).toEqual(true); + ).toBe(true); }); it('supports index', () => { @@ -978,28 +978,28 @@ describe('isConventionalDocIndex', () => { directories: ['doesNotMatter'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'index', directories: ['doesNotMatter'], extension: '.mdx', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'INDEX', directories: ['doesNotMatter'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'InDeX', directories: ['doesNotMatter'], extension: '', }), - ).toEqual(true); + ).toBe(true); }); it('supports /.md', () => { @@ -1009,35 +1009,35 @@ describe('isConventionalDocIndex', () => { directories: ['someCategory', 'doesNotMatter'], extension: '', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'someCategory', directories: ['someCategory'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'someCategory', directories: ['someCategory'], extension: '.mdx', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'SOME_CATEGORY', directories: ['some_category'], extension: '.md', }), - ).toEqual(true); + ).toBe(true); expect( isCategoryIndex({ fileName: 'some_category', directories: ['some_category'], extension: '', }), - ).toEqual(true); + ).toBe(true); }); it('reject other cases', () => { @@ -1047,20 +1047,20 @@ describe('isConventionalDocIndex', () => { directories: ['someCategory'], extension: '', }), - ).toEqual(false); + ).toBe(false); expect( isCategoryIndex({ fileName: 'read_me', directories: ['doesNotMatter'], extension: '', }), - ).toEqual(false); + ).toBe(false); expect( isCategoryIndex({ fileName: 'the index', directories: ['doesNotMatter'], extension: '', }), - ).toEqual(false); + ).toBe(false); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index f6751119230f..b2e1ed440e07 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -123,29 +123,7 @@ describe('sidebar', () => { sidebarPath, }), ); - await expect(plugin.loadContent!()).rejects - .toThrowErrorMatchingInlineSnapshot(` - "Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". - These sidebar document ids do not exist: - - goku - - Available document ids are: - - doc with space - - foo/bar - - foo/baz - - headingAsTitle - - hello - - ipsum - - lorem - - rootAbsoluteSlug - - rootRelativeSlug - - rootResolvedSlug - - rootTryToEscapeSlug - - slugs/absoluteSlug - - slugs/relativeSlug - - slugs/resolvedSlug - - slugs/tryToEscapeSlug" - `); + await expect(plugin.loadContent!()).rejects.toThrowErrorMatchingSnapshot(); }); it('site with wrong sidebar file path', async () => { @@ -281,17 +259,17 @@ describe('simple website', () => { posixPath(path.relative(siteDir, filepath)), ); expect(matchPattern).toMatchSnapshot(); - expect(isMatch('docs/hello.md', matchPattern)).toEqual(true); - expect(isMatch('docs/hello.mdx', matchPattern)).toEqual(true); - expect(isMatch('docs/foo/bar.md', matchPattern)).toEqual(true); - expect(isMatch('docs/hello.js', matchPattern)).toEqual(false); - expect(isMatch('docs/super.mdl', matchPattern)).toEqual(false); - expect(isMatch('docs/mdx', matchPattern)).toEqual(false); - expect(isMatch('docs/headingAsTitle.md', matchPattern)).toEqual(true); - expect(isMatch('sidebars.json', matchPattern)).toEqual(true); - expect(isMatch('versioned_docs/hello.md', matchPattern)).toEqual(false); - expect(isMatch('hello.md', matchPattern)).toEqual(false); - expect(isMatch('super/docs/hello.md', matchPattern)).toEqual(false); + expect(isMatch('docs/hello.md', matchPattern)).toBe(true); + expect(isMatch('docs/hello.mdx', matchPattern)).toBe(true); + expect(isMatch('docs/foo/bar.md', matchPattern)).toBe(true); + expect(isMatch('docs/hello.js', matchPattern)).toBe(false); + expect(isMatch('docs/super.mdl', matchPattern)).toBe(false); + expect(isMatch('docs/mdx', matchPattern)).toBe(false); + expect(isMatch('docs/headingAsTitle.md', matchPattern)).toBe(true); + expect(isMatch('sidebars.json', matchPattern)).toBe(true); + expect(isMatch('versioned_docs/hello.md', matchPattern)).toBe(false); + expect(isMatch('hello.md', matchPattern)).toBe(false); + expect(isMatch('super/docs/hello.md', matchPattern)).toBe(false); }); it('configureWebpack', async () => { @@ -319,7 +297,7 @@ describe('simple website', () => { it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); - expect(content.loadedVersions.length).toEqual(1); + expect(content.loadedVersions).toHaveLength(1); const [currentVersion] = content.loadedVersions; expect(findDocById(currentVersion, 'foo/baz')).toMatchSnapshot(); @@ -398,42 +376,42 @@ describe('versioned website', () => { ); expect(matchPattern).not.toEqual([]); expect(matchPattern).toMatchSnapshot(); - expect(isMatch('docs/hello.md', matchPattern)).toEqual(true); - expect(isMatch('docs/hello.mdx', matchPattern)).toEqual(true); - expect(isMatch('docs/foo/bar.md', matchPattern)).toEqual(true); - expect(isMatch('sidebars.json', matchPattern)).toEqual(true); - expect( - isMatch('versioned_docs/version-1.0.0/hello.md', matchPattern), - ).toEqual(true); + expect(isMatch('docs/hello.md', matchPattern)).toBe(true); + expect(isMatch('docs/hello.mdx', matchPattern)).toBe(true); + expect(isMatch('docs/foo/bar.md', matchPattern)).toBe(true); + expect(isMatch('sidebars.json', matchPattern)).toBe(true); + expect(isMatch('versioned_docs/version-1.0.0/hello.md', matchPattern)).toBe( + true, + ); expect( isMatch('versioned_docs/version-1.0.0/foo/bar.md', matchPattern), - ).toEqual(true); + ).toBe(true); expect( isMatch('versioned_sidebars/version-1.0.0-sidebars.json', matchPattern), - ).toEqual(true); + ).toBe(true); // Non existing version expect( isMatch('versioned_docs/version-2.0.0/foo/bar.md', matchPattern), - ).toEqual(false); - expect( - isMatch('versioned_docs/version-2.0.0/hello.md', matchPattern), - ).toEqual(false); + ).toBe(false); + expect(isMatch('versioned_docs/version-2.0.0/hello.md', matchPattern)).toBe( + false, + ); expect( isMatch('versioned_sidebars/version-2.0.0-sidebars.json', matchPattern), - ).toEqual(false); + ).toBe(false); - expect(isMatch('docs/hello.js', matchPattern)).toEqual(false); - expect(isMatch('docs/super.mdl', matchPattern)).toEqual(false); - expect(isMatch('docs/mdx', matchPattern)).toEqual(false); - expect(isMatch('hello.md', matchPattern)).toEqual(false); - expect(isMatch('super/docs/hello.md', matchPattern)).toEqual(false); + expect(isMatch('docs/hello.js', matchPattern)).toBe(false); + expect(isMatch('docs/super.mdl', matchPattern)).toBe(false); + expect(isMatch('docs/mdx', matchPattern)).toBe(false); + expect(isMatch('hello.md', matchPattern)).toBe(false); + expect(isMatch('super/docs/hello.md', matchPattern)).toBe(false); }); it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); - expect(content.loadedVersions.length).toEqual(4); + expect(content.loadedVersions).toHaveLength(4); const [currentVersion, version101, version100, versionWithSlugs] = content.loadedVersions; @@ -529,32 +507,32 @@ describe('versioned website (community)', () => { ); expect(matchPattern).not.toEqual([]); expect(matchPattern).toMatchSnapshot(); - expect(isMatch('community/team.md', matchPattern)).toEqual(true); + expect(isMatch('community/team.md', matchPattern)).toBe(true); expect( isMatch('community_versioned_docs/version-1.0.0/team.md', matchPattern), - ).toEqual(true); + ).toBe(true); // Non existing version expect( isMatch('community_versioned_docs/version-2.0.0/team.md', matchPattern), - ).toEqual(false); + ).toBe(false); expect( isMatch( 'community_versioned_sidebars/version-2.0.0-sidebars.json', matchPattern, ), - ).toEqual(false); + ).toBe(false); - expect(isMatch('community/team.js', matchPattern)).toEqual(false); + expect(isMatch('community/team.js', matchPattern)).toBe(false); expect( isMatch('community_versioned_docs/version-1.0.0/team.js', matchPattern), - ).toEqual(false); + ).toBe(false); }); it('content', async () => { const {plugin, pluginContentDir} = await loadSite(); const content = await plugin.loadContent!(); - expect(content.loadedVersions.length).toEqual(2); + expect(content.loadedVersions).toHaveLength(2); const [currentVersion, version100] = content.loadedVersions; expect(getDocById(currentVersion, 'team')).toMatchSnapshot(); @@ -600,7 +578,7 @@ describe('site with doc label', () => { const loadedVersion = content.loadedVersions[0]; const sidebarProps = toSidebarsProp(loadedVersion); - expect(sidebarProps.docs[0].label).toEqual('Hello One'); + expect(sidebarProps.docs[0].label).toBe('Hello One'); }); it('sidebar_label in doc has higher precedence over label in sidebar.json', async () => { @@ -608,7 +586,7 @@ describe('site with doc label', () => { const loadedVersion = content.loadedVersions[0]; const sidebarProps = toSidebarsProp(loadedVersion); - expect(sidebarProps.docs[1].label).toEqual('Hello 2 From Doc'); + expect(sidebarProps.docs[1].label).toBe('Hello 2 From Doc'); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts index 933d2d7297ca..e1b7afd4c8a5 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/numberPrefix.test.ts @@ -70,45 +70,37 @@ describe('stripNumberPrefix', () => { } it('strips number prefix if present', () => { - expect(stripNumberPrefixDefault('1-My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('01-My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001-My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 - My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 - My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('999 - My Doc')).toEqual( - 'My Doc', - ); + expect(stripNumberPrefixDefault('1-My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('01-My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001-My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 - My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 - My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('999 - My Doc')).toBe('My Doc'); // - expect(stripNumberPrefixDefault('1---My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('01---My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001---My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 --- My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 --- My Doc')).toEqual( - 'My Doc', - ); - expect(stripNumberPrefixDefault('999 --- My Doc')).toEqual( + expect(stripNumberPrefixDefault('1---My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('01---My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001---My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 --- My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 --- My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('999 --- My Doc')).toBe( 'My Doc', ); // - expect(stripNumberPrefixDefault('1___My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('01___My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001___My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 ___ My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 ___ My Doc')).toEqual( - 'My Doc', - ); - expect(stripNumberPrefixDefault('999 ___ My Doc')).toEqual( + expect(stripNumberPrefixDefault('1___My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('01___My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001___My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 ___ My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 ___ My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('999 ___ My Doc')).toBe( 'My Doc', ); // - expect(stripNumberPrefixDefault('1.My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('01.My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001.My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 . My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('001 . My Doc')).toEqual('My Doc'); - expect(stripNumberPrefixDefault('999 . My Doc')).toEqual( - 'My Doc', - ); + expect(stripNumberPrefixDefault('1.My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('01.My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001.My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 . My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('001 . My Doc')).toBe('My Doc'); + expect(stripNumberPrefixDefault('999 . My Doc')).toBe('My Doc'); }); it('does not strip number prefix if pattern does not match', () => { @@ -125,7 +117,7 @@ describe('stripPathNumberPrefix', () => { '0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3', DefaultNumberPrefixParser, ), - ).toEqual('MyRootFolder0/MySubFolder1/MyDeepFolder2/MyDoc3'); + ).toBe('MyRootFolder0/MySubFolder1/MyDeepFolder2/MyDoc3'); }); it('strips number prefixes in paths with custom parser', () => { @@ -138,7 +130,7 @@ describe('stripPathNumberPrefix', () => { expect( stripPathNumberPrefixes('aaaa/bbbb/cccc', stripPathNumberPrefixCustom), - ).toEqual('aaa/bbb/ccc'); + ).toBe('aaa/bbb/ccc'); }); it('does not strip number prefixes in paths with disabled parser', () => { @@ -147,7 +139,7 @@ describe('stripPathNumberPrefix', () => { '0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3', DisabledNumberPrefixParser, ), - ).toEqual('0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3'); + ).toBe('0-MyRootFolder0/1 - MySubFolder1/2. MyDeepFolder2/3 _MyDoc3'); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 3c39f1b6de23..a4833aa6d7b3 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -33,7 +33,7 @@ describe('normalizeDocsPluginOptions', () => { it('returns default options for undefined user options', async () => { const {value, error} = await OptionsSchema.validate({}); expect(value).toEqual(DEFAULT_OPTIONS); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts correctly defined user options', async () => { @@ -79,7 +79,7 @@ describe('normalizeDocsPluginOptions', () => { }; const {value, error} = await OptionsSchema.validate(userOptions); expect(value).toEqual(userOptions); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts correctly defined remark and rehype plugin options', async () => { @@ -95,7 +95,7 @@ describe('normalizeDocsPluginOptions', () => { }; const {value, error} = await OptionsSchema.validate(userOptions); expect(value).toEqual(userOptions); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts admonitions false', async () => { @@ -105,7 +105,7 @@ describe('normalizeDocsPluginOptions', () => { }; const {value, error} = OptionsSchema.validate(admonitionsFalse); expect(value).toEqual(admonitionsFalse); - expect(error).toBe(undefined); + expect(error).toBeUndefined(); }); it('accepts numberPrefixParser function', () => { @@ -256,7 +256,7 @@ describe('normalizeDocsPluginOptions', () => { sidebarCollapsible: true, sidebarCollapsed: undefined, }).sidebarCollapsed, - ).toEqual(true); + ).toBe(true); expect( testValidateOptions({ @@ -264,7 +264,7 @@ describe('normalizeDocsPluginOptions', () => { sidebarCollapsible: false, sidebarCollapsed: undefined, }).sidebarCollapsed, - ).toEqual(false); + ).toBe(false); expect( testValidateOptions({ @@ -272,6 +272,6 @@ describe('normalizeDocsPluginOptions', () => { sidebarCollapsible: false, sidebarCollapsed: true, }).sidebarCollapsed, - ).toEqual(false); + ).toBe(false); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts index e015d7260c8a..eed2abde2c3f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts @@ -15,14 +15,14 @@ describe('getSlug', () => { source: '@site/docs/dir/doc.md', sourceDirName: '/dir', }), - ).toEqual('/dir/doc'); + ).toBe('/dir/doc'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/doc.md', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/doc'); + ).toBe('/dir/subdir/doc'); }); it('handles conventional doc indexes', () => { @@ -32,42 +32,42 @@ describe('getSlug', () => { source: '@site/docs/dir/subdir/index.md', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/inDEx.mdx', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/readme.md', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/reADMe.mdx', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/subdir.md', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); expect( getSlug({ baseID: 'doc', source: '@site/docs/dir/subdir/suBDir.mdx', sourceDirName: '/dir/subdir', }), - ).toEqual('/dir/subdir/'); + ).toBe('/dir/subdir/'); }); it('ignores conventional doc index when explicit slug front matter is provided', () => { @@ -78,7 +78,7 @@ describe('getSlug', () => { sourceDirName: '/dir/subdir', frontMatterSlug: '/my/frontMatterSlug', }), - ).toEqual('/my/frontMatterSlug'); + ).toBe('/my/frontMatterSlug'); }); it('can strip dir number prefixes', () => { @@ -89,7 +89,7 @@ describe('getSlug', () => { sourceDirName: '/001-dir1/002-dir2', stripDirNumberPrefixes: true, }), - ).toEqual('/dir1/dir2/doc'); + ).toBe('/dir1/dir2/doc'); expect( getSlug({ baseID: 'doc', @@ -97,7 +97,7 @@ describe('getSlug', () => { sourceDirName: '/001-dir1/002-dir2', stripDirNumberPrefixes: false, }), - ).toEqual('/001-dir1/002-dir2/doc'); + ).toBe('/001-dir1/002-dir2/doc'); }); // See https://github.com/facebook/docusaurus/issues/3223 @@ -108,16 +108,16 @@ describe('getSlug', () => { source: '@site/docs/dir with spâce/hey $hello/doc.md', sourceDirName: '/dir with spâce/hey $hello', }), - ).toEqual('/dir with spâce/hey $hello/my dôc'); + ).toBe('/dir with spâce/hey $hello/my dôc'); }); it('handles current dir', () => { expect( getSlug({baseID: 'doc', source: '@site/docs/doc.md', sourceDirName: '.'}), - ).toEqual('/doc'); + ).toBe('/doc'); expect( getSlug({baseID: 'doc', source: '@site/docs/doc.md', sourceDirName: '/'}), - ).toEqual('/doc'); + ).toBe('/doc'); }); it('resolves absolute slug front matter', () => { @@ -128,7 +128,7 @@ describe('getSlug', () => { sourceDirName: '.', frontMatterSlug: '/abc/def', }), - ).toEqual('/abc/def'); + ).toBe('/abc/def'); expect( getSlug({ baseID: 'any', @@ -136,7 +136,7 @@ describe('getSlug', () => { sourceDirName: './any', frontMatterSlug: '/abc/def', }), - ).toEqual('/abc/def'); + ).toBe('/abc/def'); expect( getSlug({ baseID: 'any', @@ -144,7 +144,7 @@ describe('getSlug', () => { sourceDirName: './any/any', frontMatterSlug: '/abc/def', }), - ).toEqual('/abc/def'); + ).toBe('/abc/def'); }); it('resolves relative slug front matter', () => { @@ -155,7 +155,7 @@ describe('getSlug', () => { sourceDirName: '.', frontMatterSlug: 'abc/def', }), - ).toEqual('/abc/def'); + ).toBe('/abc/def'); expect( getSlug({ baseID: 'any', @@ -163,7 +163,7 @@ describe('getSlug', () => { sourceDirName: '/dir', frontMatterSlug: 'abc/def', }), - ).toEqual('/dir/abc/def'); + ).toBe('/dir/abc/def'); expect( getSlug({ baseID: 'any', @@ -171,7 +171,7 @@ describe('getSlug', () => { sourceDirName: 'unslashedDir', frontMatterSlug: 'abc/def', }), - ).toEqual('/unslashedDir/abc/def'); + ).toBe('/unslashedDir/abc/def'); expect( getSlug({ baseID: 'any', @@ -179,7 +179,7 @@ describe('getSlug', () => { sourceDirName: 'dir/subdir', frontMatterSlug: 'abc/def', }), - ).toEqual('/dir/subdir/abc/def'); + ).toBe('/dir/subdir/abc/def'); expect( getSlug({ baseID: 'any', @@ -187,7 +187,7 @@ describe('getSlug', () => { sourceDirName: '/dir', frontMatterSlug: './abc/def', }), - ).toEqual('/dir/abc/def'); + ).toBe('/dir/abc/def'); expect( getSlug({ baseID: 'any', @@ -195,7 +195,7 @@ describe('getSlug', () => { sourceDirName: '/dir', frontMatterSlug: './abc/../def', }), - ).toEqual('/dir/def'); + ).toBe('/dir/def'); expect( getSlug({ baseID: 'any', @@ -203,7 +203,7 @@ describe('getSlug', () => { sourceDirName: '/dir/subdir', frontMatterSlug: '../abc/def', }), - ).toEqual('/dir/abc/def'); + ).toBe('/dir/abc/def'); expect( getSlug({ baseID: 'any', @@ -211,6 +211,6 @@ describe('getSlug', () => { sourceDirName: '/dir/subdir', frontMatterSlug: '../../../../../abc/../def', }), - ).toEqual('/def'); + ).toBe('/def'); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts index 45323322fbd4..5576af633260 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts @@ -32,8 +32,8 @@ describe('docsClientUtils', () => { }, }; - expect(getActivePlugin(data, '/')).toEqual(undefined); - expect(getActivePlugin(data, '/xyz')).toEqual(undefined); + expect(getActivePlugin(data, '/')).toBeUndefined(); + expect(getActivePlugin(data, '/xyz')).toBeUndefined(); expect(() => getActivePlugin(data, '/', {failfast: true}), @@ -73,7 +73,7 @@ describe('docsClientUtils', () => { versions: [], }, }; - expect(getActivePlugin(onePluginAtRoot, '/android/foo').pluginId).toEqual( + expect(getActivePlugin(onePluginAtRoot, '/android/foo').pluginId).toBe( 'pluginAndroidId', ); const onePluginAtRootReversed = { @@ -88,7 +88,7 @@ describe('docsClientUtils', () => { }; expect( getActivePlugin(onePluginAtRootReversed, '/android/foo').pluginId, - ).toEqual('pluginAndroidId'); + ).toBe('pluginAndroidId'); }); it('getLatestVersion', () => { @@ -158,19 +158,19 @@ describe('docsClientUtils', () => { ], }; - expect(getActiveVersion(data, '/someUnknownPath')).toEqual(undefined); + expect(getActiveVersion(data, '/someUnknownPath')).toBeUndefined(); - expect(getActiveVersion(data, '/docs/next')?.name).toEqual('next'); - expect(getActiveVersion(data, '/docs/next/')?.name).toEqual('next'); - expect(getActiveVersion(data, '/docs/next/someDoc')?.name).toEqual('next'); + expect(getActiveVersion(data, '/docs/next')?.name).toBe('next'); + expect(getActiveVersion(data, '/docs/next/')?.name).toBe('next'); + expect(getActiveVersion(data, '/docs/next/someDoc')?.name).toBe('next'); - expect(getActiveVersion(data, '/docs')?.name).toEqual('version2'); - expect(getActiveVersion(data, '/docs/')?.name).toEqual('version2'); - expect(getActiveVersion(data, '/docs/someDoc')?.name).toEqual('version2'); + expect(getActiveVersion(data, '/docs')?.name).toBe('version2'); + expect(getActiveVersion(data, '/docs/')?.name).toBe('version2'); + expect(getActiveVersion(data, '/docs/someDoc')?.name).toBe('version2'); - expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1'); - expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1'); - expect(getActiveVersion(data, '/docs/version1/someDoc')?.name).toEqual( + expect(getActiveVersion(data, '/docs/version1')?.name).toBe('version1'); + expect(getActiveVersion(data, '/docs/version1')?.name).toBe('version1'); + expect(getActiveVersion(data, '/docs/version1/someDoc')?.name).toBe( 'version1', ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index c268103b25b7..c6a740fb84e3 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -132,18 +132,18 @@ describe('createSidebarsUtils', () => { } = createSidebarsUtils(sidebars); it('getFirstDocIdOfFirstSidebar', async () => { - expect(getFirstDocIdOfFirstSidebar()).toEqual('doc1'); + expect(getFirstDocIdOfFirstSidebar()).toBe('doc1'); }); it('getSidebarNameByDocId', async () => { - expect(getSidebarNameByDocId('doc1')).toEqual('sidebar1'); - expect(getSidebarNameByDocId('doc2')).toEqual('sidebar1'); - expect(getSidebarNameByDocId('doc3')).toEqual('sidebar2'); - expect(getSidebarNameByDocId('doc4')).toEqual('sidebar2'); - expect(getSidebarNameByDocId('doc5')).toEqual('sidebar3'); - expect(getSidebarNameByDocId('doc6')).toEqual('sidebar3'); - expect(getSidebarNameByDocId('doc7')).toEqual('sidebar3'); - expect(getSidebarNameByDocId('unknown_id')).toEqual(undefined); + expect(getSidebarNameByDocId('doc1')).toBe('sidebar1'); + expect(getSidebarNameByDocId('doc2')).toBe('sidebar1'); + expect(getSidebarNameByDocId('doc3')).toBe('sidebar2'); + expect(getSidebarNameByDocId('doc4')).toBe('sidebar2'); + expect(getSidebarNameByDocId('doc5')).toBe('sidebar3'); + expect(getSidebarNameByDocId('doc6')).toBe('sidebar3'); + expect(getSidebarNameByDocId('doc7')).toBe('sidebar3'); + expect(getSidebarNameByDocId('unknown_id')).toBeUndefined(); }); it('getDocNavigation', async () => { diff --git a/packages/docusaurus-theme-common/package.json b/packages/docusaurus-theme-common/package.json index aaf4835bee8c..ab293316f44c 100644 --- a/packages/docusaurus-theme-common/package.json +++ b/packages/docusaurus-theme-common/package.json @@ -31,7 +31,6 @@ "devDependencies": { "@docusaurus/core": "2.0.0-beta.17", "@docusaurus/types": "2.0.0-beta.17", - "@testing-library/react-hooks": "^7.0.2", "fs-extra": "^10.0.1", "lodash": "^4.17.21" }, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap new file mode 100644 index 000000000000..45df110aa812 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`useTreeifiedTOC treeifies TOC without filtering 1`] = ` +Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [], + "id": "foxtrot", + "level": 6, + "value": "Foxtrot", + }, + ], + "id": "echo", + "level": 5, + "value": "Echo", + }, + ], + "id": "delta", + "level": 4, + "value": "Delta", + }, + ], + "id": "charlie", + "level": 3, + "value": "Charlie", + }, + ], + "id": "bravo", + "level": 2, + "value": "Bravo", + }, +] +`; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts index 509a92f1ccf0..efc84c6de68e 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts @@ -13,45 +13,45 @@ import { describe('parseCodeBlockTitle', () => { it('parses double quote delimited title', () => { - expect(parseCodeBlockTitle(`title="index.js"`)).toEqual(`index.js`); + expect(parseCodeBlockTitle(`title="index.js"`)).toBe(`index.js`); }); it('parses single quote delimited title', () => { - expect(parseCodeBlockTitle(`title='index.js'`)).toEqual(`index.js`); + expect(parseCodeBlockTitle(`title='index.js'`)).toBe(`index.js`); }); it('does not parse mismatched quote delimiters', () => { - expect(parseCodeBlockTitle(`title="index.js'`)).toEqual(``); + expect(parseCodeBlockTitle(`title="index.js'`)).toBe(``); }); it('parses undefined metastring', () => { - expect(parseCodeBlockTitle(undefined)).toEqual(``); + expect(parseCodeBlockTitle(undefined)).toBe(``); }); it('parses metastring with no title specified', () => { - expect(parseCodeBlockTitle(`{1,2-3}`)).toEqual(``); + expect(parseCodeBlockTitle(`{1,2-3}`)).toBe(``); }); it('parses with multiple metadata title first', () => { - expect(parseCodeBlockTitle(`title="index.js" label="JavaScript"`)).toEqual( + expect(parseCodeBlockTitle(`title="index.js" label="JavaScript"`)).toBe( `index.js`, ); }); it('parses with multiple metadata title last', () => { - expect(parseCodeBlockTitle(`label="JavaScript" title="index.js"`)).toEqual( + expect(parseCodeBlockTitle(`label="JavaScript" title="index.js"`)).toBe( `index.js`, ); }); it('parses double quotes when delimited by single quotes', () => { - expect(parseCodeBlockTitle(`title='console.log("Hello, World!")'`)).toEqual( + expect(parseCodeBlockTitle(`title='console.log("Hello, World!")'`)).toBe( `console.log("Hello, World!")`, ); }); it('parses single quotes when delimited by double quotes', () => { - expect(parseCodeBlockTitle(`title="console.log('Hello, World!')"`)).toEqual( + expect(parseCodeBlockTitle(`title="console.log('Hello, World!')"`)).toBe( `console.log('Hello, World!')`, ); }); @@ -59,8 +59,8 @@ describe('parseCodeBlockTitle', () => { describe('parseLanguage', () => { it('works', () => { - expect(parseLanguage('language-foo xxx yyy')).toEqual('foo'); - expect(parseLanguage('xxxxx language-foo yyy')).toEqual('foo'); + expect(parseLanguage('language-foo xxx yyy')).toBe('foo'); + expect(parseLanguage('xxxxx language-foo yyy')).toBe('foo'); expect(parseLanguage('xx-language-foo yyyy')).toBeUndefined(); expect(parseLanguage('xxx yyy zzz')).toBeUndefined(); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index d5d4c2542703..04929a76f42b 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -16,8 +16,11 @@ import { useDocsSidebar, DocsSidebarProvider, findSidebarCategory, - getBreadcrumbs, + useCurrentSidebarCategory, + useSidebarBreadcrumbs, } from '../docsUtils'; +import {StaticRouter} from 'react-router-dom'; +import {Context} from '@docusaurus/docusaurusContext'; import type { PropSidebar, PropSidebarItem, @@ -123,7 +126,7 @@ describe('useDocById', () => { }, }); - function callHook(docId: string | undefined) { + function mockUseDocById(docId: string | undefined) { const {result} = renderHook(() => useDocById(docId), { wrapper: ({children}) => ( {children} @@ -133,25 +136,25 @@ describe('useDocById', () => { } it('accepts undefined', () => { - expect(callHook(undefined)).toBeUndefined(); + expect(mockUseDocById(undefined)).toBeUndefined(); }); it('finds doc1', () => { - expect(callHook('doc1')).toMatchObject({id: 'doc1'}); + expect(mockUseDocById('doc1')).toMatchObject({id: 'doc1'}); }); it('finds doc2', () => { - expect(callHook('doc2')).toMatchObject({id: 'doc2'}); + expect(mockUseDocById('doc2')).toMatchObject({id: 'doc2'}); }); it('throws for doc3', () => { - expect(() => callHook('doc3')).toThrowErrorMatchingInlineSnapshot( + expect(() => mockUseDocById('doc3')).toThrowErrorMatchingInlineSnapshot( `"no version doc found by id=doc3"`, ); }); }); describe('findSidebarCategory', () => { - it('os able to return undefined', () => { + it('is able to return undefined', () => { expect(findSidebarCategory([], () => false)).toBeUndefined(); expect( findSidebarCategory([testCategory(), testCategory()], () => false), @@ -207,7 +210,7 @@ describe('findFirstCategoryLink', () => { href: undefined, }), ), - ).toEqual(undefined); + ).toBeUndefined(); }); it('works with category with link', () => { @@ -217,7 +220,7 @@ describe('findFirstCategoryLink', () => { href: '/itemPath', }), ), - ).toEqual('/itemPath'); + ).toBe('/itemPath'); }); it('works with category with deeply nested category link', () => { @@ -239,7 +242,7 @@ describe('findFirstCategoryLink', () => { ], }), ), - ).toEqual('/itemPath'); + ).toBe('/itemPath'); }); it('works with category with deeply nested link', () => { @@ -255,7 +258,7 @@ describe('findFirstCategoryLink', () => { ], }), ), - ).toEqual('/itemPath'); + ).toBe('/itemPath'); }); }); @@ -267,15 +270,15 @@ describe('isActiveSidebarItem', () => { label: 'Label', }; - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); - expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); + expect(isActiveSidebarItem(item, '/itemPath')).toBe(true); // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); + expect(isActiveSidebarItem(item, '/itemPath/')).toBe(true); expect( isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), - ).toEqual(true); + ).toBe(true); }); it('works with category href', () => { @@ -283,15 +286,15 @@ describe('isActiveSidebarItem', () => { href: '/itemPath', }); - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); - expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true); + expect(isActiveSidebarItem(item, '/itemPath')).toBe(true); // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true); + expect(isActiveSidebarItem(item, '/itemPath/')).toBe(true); expect( isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'), - ).toEqual(true); + ).toBe(true); }); it('works with category nested items', () => { @@ -316,63 +319,70 @@ describe('isActiveSidebarItem', () => { ], }); - expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false); + expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); - expect(isActiveSidebarItem(item, '/category-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-link-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-category-path')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-sub-link-path')).toEqual(true); + expect(isActiveSidebarItem(item, '/category-path')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-link-path')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-category-path')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-sub-link-path')).toBe(true); // Ensure it's not trailing slash sensitive: - expect(isActiveSidebarItem(item, '/category-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-link-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-category-path/')).toEqual(true); - expect(isActiveSidebarItem(item, '/sub-sub-link-path/')).toEqual(true); + expect(isActiveSidebarItem(item, '/category-path/')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-link-path/')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-category-path/')).toBe(true); + expect(isActiveSidebarItem(item, '/sub-sub-link-path/')).toBe(true); }); }); -describe('getBreadcrumbs', () => { +describe('useSidebarBreadcrumbs', () => { + const createUseSidebarBreadcrumbsMock = + (sidebar: PropSidebar, breadcrumbsOption?: boolean) => (location: string) => + renderHook(() => useSidebarBreadcrumbs(), { + wrapper: ({children}) => ( + + + + {children} + + + + ), + }).result.current; it('returns empty for empty sidebar', () => { - expect( - getBreadcrumbs({ - sidebar: [], - pathname: '/doesNotExist', - }), - ).toEqual([]); + expect(createUseSidebarBreadcrumbsMock([])('/doesNotExist')).toEqual([]); }); it('returns empty for sidebar but unknown pathname', () => { const sidebar = [testCategory(), testLink()]; - expect( - getBreadcrumbs({ - sidebar, - pathname: '/doesNotExist', - }), - ).toEqual([]); + expect(createUseSidebarBreadcrumbsMock(sidebar)('/doesNotExist')).toEqual( + [], + ); }); it('returns first level category', () => { const pathname = '/somePathName'; const sidebar = [testCategory({href: pathname}), testLink()]; - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([sidebar[0]]); + expect(createUseSidebarBreadcrumbsMock(sidebar)(pathname)).toEqual([ + sidebar[0], + ]); }); it('returns first level link', () => { const pathname = '/somePathName'; const sidebar = [testCategory(), testLink({href: pathname})]; - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([sidebar[1]]); + expect(createUseSidebarBreadcrumbsMock(sidebar)(pathname)).toEqual([ + sidebar[1], + ]); }); it('returns nested category', () => { @@ -403,12 +413,11 @@ describe('getBreadcrumbs', () => { testCategory(), ]; - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([categoryLevel1, categoryLevel2, categoryLevel3]); + expect(createUseSidebarBreadcrumbsMock(sidebar)(pathname)).toEqual([ + categoryLevel1, + categoryLevel2, + categoryLevel3, + ]); }); it('returns nested link', () => { @@ -441,11 +450,75 @@ describe('getBreadcrumbs', () => { testCategory(), ]; - expect( - getBreadcrumbs({ - sidebar, - pathname, - }), - ).toEqual([categoryLevel1, categoryLevel2, categoryLevel3, link]); + expect(createUseSidebarBreadcrumbsMock(sidebar)(pathname)).toEqual([ + categoryLevel1, + categoryLevel2, + categoryLevel3, + link, + ]); + }); + + it('returns null when breadcrumbs disabled', () => { + expect(createUseSidebarBreadcrumbsMock([], false)('/foo')).toBeNull(); + }); + + it('returns null when there is no sidebar', () => { + expect(createUseSidebarBreadcrumbsMock(null, false)('/foo')).toBeNull(); + }); +}); + +describe('useCurrentSidebarCategory', () => { + const createUseCurrentSidebarCategoryMock = + (sidebar?: PropSidebar) => (location: string) => + renderHook(() => useCurrentSidebarCategory(), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current; + it('works', () => { + const category = { + type: 'category', + href: '/cat', + items: [ + {type: 'link', href: '/cat/foo', label: 'Foo'}, + {type: 'link', href: '/cat/bar', label: 'Bar'}, + {type: 'link', href: '/baz', label: 'Baz'}, + ], + }; + const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock([ + {type: 'link', href: '/cat/fake', label: 'Fake'}, + category, + ]); + expect(mockUseCurrentSidebarCategory('/cat')).toEqual(category); + }); + + it('throws for non-category index page', () => { + const category = { + type: 'category', + items: [ + {type: 'link', href: '/cat/foo', label: 'Foo'}, + {type: 'link', href: '/cat/bar', label: 'Bar'}, + {type: 'link', href: '/baz', label: 'Baz'}, + ], + }; + const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock([ + category, + ]); + expect(() => mockUseCurrentSidebarCategory('/cat')) + .toThrowErrorMatchingInlineSnapshot(` + "Unexpected: sidebar category could not be found for pathname='/cat'. + Hook useCurrentSidebarCategory() should only be used on Category pages" + `); + }); + + it('throws when sidebar is missing', () => { + const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock(); + expect(() => + mockUseCurrentSidebarCategory('/cat'), + ).toThrowErrorMatchingInlineSnapshot( + `"Unexpected: cant find current sidebar in context"`, + ); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/footerUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/footerUtils.test.ts new file mode 100644 index 000000000000..3c73e3dfa984 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/footerUtils.test.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {isMultiColumnFooterLinks} from '../footerUtils'; + +describe('isMultiColumnFooterLinks', () => { + it('works', () => { + expect( + isMultiColumnFooterLinks([ + { + title: 'section', + items: [ + {href: '/foo', label: 'Foo'}, + {href: '/bar', label: 'Bar'}, + ], + }, + { + title: 'section2', + items: [ + {href: '/foo', label: 'Foo2'}, + {href: '/bar', label: 'Bar2'}, + ], + }, + ]), + ).toBe(true); + expect( + isMultiColumnFooterLinks([ + {href: '/foo', label: 'Foo'}, + {href: '/bar', label: 'Bar'}, + ]), + ).toBe(false); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx new file mode 100644 index 000000000000..661069efe4cc --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {useTitleFormatter} from '../generalUtils'; +import {renderHook} from '@testing-library/react-hooks'; +import {Context} from '@docusaurus/docusaurusContext'; +import type {DocusaurusContext} from '@docusaurus/types'; + +describe('useTitleFormatter', () => { + const createUseTitleFormatterMock = + (context: DocusaurusContext) => (title?: string) => + renderHook(() => useTitleFormatter(title), { + wrapper: ({children}) => ( + {children} + ), + }).result.current; + it('works', () => { + const mockUseTitleFormatter = createUseTitleFormatterMock({ + siteConfig: { + title: 'my site', + titleDelimiter: '·', + }, + }); + expect(mockUseTitleFormatter('a page')).toBe('a page · my site'); + expect(mockUseTitleFormatter(undefined)).toBe('my site'); + expect(mockUseTitleFormatter(' ')).toBe('my site'); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts index 692f5aad7466..2101c647e92d 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts @@ -9,13 +9,13 @@ import {isRegexpStringMatch} from '../regexpUtils'; describe('isRegexpStringMatch', () => { it('works', () => { - expect(isRegexpStringMatch(undefined, 'foo')).toEqual(false); - expect(isRegexpStringMatch('bar', undefined)).toEqual(false); - expect(isRegexpStringMatch('foo', 'bar')).toEqual(false); - expect(isRegexpStringMatch('foo', 'foo')).toEqual(true); - expect(isRegexpStringMatch('fooooooooooo', 'foo')).toEqual(false); - expect(isRegexpStringMatch('foo', 'fooooooo')).toEqual(true); - expect(isRegexpStringMatch('f.*o', 'fggo')).toEqual(true); - expect(isRegexpStringMatch('FOO', 'foo')).toEqual(true); + expect(isRegexpStringMatch(undefined, 'foo')).toBe(false); + expect(isRegexpStringMatch('bar', undefined)).toBe(false); + expect(isRegexpStringMatch('foo', 'bar')).toBe(false); + expect(isRegexpStringMatch('foo', 'foo')).toBe(true); + expect(isRegexpStringMatch('fooooooooooo', 'foo')).toBe(false); + expect(isRegexpStringMatch('foo', 'fooooooo')).toBe(true); + expect(isRegexpStringMatch('f.*o', 'fggo')).toBe(true); + expect(isRegexpStringMatch('FOO', 'foo')).toBe(true); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts index 36837e3ce977..305164f36e64 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {type Route} from '@generated/routes'; +import type {Route} from '@docusaurus/types'; import {findHomePageRoute} from '../routesUtils'; describe('findHomePageRoute', () => { @@ -15,7 +15,7 @@ describe('findHomePageRoute', () => { }; it('returns undefined for no routes', () => { - expect(findHomePageRoute({baseUrl: '/', routes: []})).toEqual(undefined); + expect(findHomePageRoute({baseUrl: '/', routes: []})).toBeUndefined(); }); it('returns undefined for no homepage', () => { @@ -37,7 +37,7 @@ describe('findHomePageRoute', () => { }, ], }), - ).toEqual(undefined); + ).toBeUndefined(); }); it('finds top-level homepage', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts index a3ca5378268f..bb6ab8245e2c 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/searchUtils.test.ts @@ -9,6 +9,6 @@ import {docVersionSearchTag} from '../searchUtils'; describe('docVersionSearchTag', () => { it('works', () => { - expect(docVersionSearchTag('foo', 'bar')).toEqual('docs-foo-bar'); + expect(docVersionSearchTag('foo', 'bar')).toBe('docs-foo-bar'); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts index 2ac8a63fd434..0ae93d7024b6 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/tocUtils.test.ts @@ -7,47 +7,50 @@ import type {TOCItem} from '@docusaurus/types'; import {renderHook} from '@testing-library/react-hooks'; -import {useFilteredAndTreeifiedTOC} from '../tocUtils'; +import {useFilteredAndTreeifiedTOC, useTreeifiedTOC} from '../tocUtils'; + +const mockTOC: TOCItem[] = [ + { + id: 'bravo', + level: 2, + value: 'Bravo', + }, + { + id: 'charlie', + level: 3, + value: 'Charlie', + }, + { + id: 'delta', + level: 4, + value: 'Delta', + }, + { + id: 'echo', + level: 5, + value: 'Echo', + }, + { + id: 'foxtrot', + level: 6, + value: 'Foxtrot', + }, +]; + +describe('useTreeifiedTOC', () => { + it('treeifies TOC without filtering', () => { + expect( + renderHook(() => useTreeifiedTOC(mockTOC)).result.current, + ).toMatchSnapshot(); + }); +}); describe('useFilteredAndTreeifiedTOC', () => { it('filters a toc with all heading levels', () => { - const toc: TOCItem[] = [ - { - id: 'alpha', - level: 1, - value: 'alpha', - }, - { - id: 'bravo', - level: 2, - value: 'Bravo', - }, - { - id: 'charlie', - level: 3, - value: 'Charlie', - }, - { - id: 'delta', - level: 4, - value: 'Delta', - }, - { - id: 'echo', - level: 5, - value: 'Echo', - }, - { - id: 'foxtrot', - level: 6, - value: 'Foxtrot', - }, - ]; - expect( renderHook(() => useFilteredAndTreeifiedTOC({ - toc, + toc: mockTOC, minHeadingLevel: 2, maxHeadingLevel: 2, }), @@ -64,7 +67,7 @@ describe('useFilteredAndTreeifiedTOC', () => { expect( renderHook(() => useFilteredAndTreeifiedTOC({ - toc, + toc: mockTOC, minHeadingLevel: 3, maxHeadingLevel: 3, }), @@ -81,7 +84,7 @@ describe('useFilteredAndTreeifiedTOC', () => { expect( renderHook(() => useFilteredAndTreeifiedTOC({ - toc, + toc: mockTOC, minHeadingLevel: 2, maxHeadingLevel: 3, }), @@ -105,7 +108,7 @@ describe('useFilteredAndTreeifiedTOC', () => { expect( renderHook(() => useFilteredAndTreeifiedTOC({ - toc, + toc: mockTOC, minHeadingLevel: 2, maxHeadingLevel: 4, }), diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx new file mode 100644 index 000000000000..24f35e70b5ff --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx @@ -0,0 +1,124 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {useAlternatePageUtils} from '../useAlternatePageUtils'; +import {renderHook} from '@testing-library/react-hooks'; +import {StaticRouter} from 'react-router-dom'; +import {Context} from '@docusaurus/docusaurusContext'; +import type {DocusaurusContext} from '@docusaurus/types'; + +describe('useAlternatePageUtils', () => { + const createUseAlternatePageUtilsMock = + (context: DocusaurusContext) => (location: string) => + renderHook(() => useAlternatePageUtils(), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current; + it('works for baseUrl: / and currentLocale = defaultLocale', () => { + const mockUseAlternatePageUtils = createUseAlternatePageUtilsMock({ + siteConfig: {baseUrl: '/', url: 'https://example.com'}, + i18n: {defaultLocale: 'en', currentLocale: 'en'}, + }); + expect( + mockUseAlternatePageUtils('/').createUrl({ + locale: 'zh-Hans', + fullyQualified: false, + }), + ).toBe('/zh-Hans/'); + expect( + mockUseAlternatePageUtils('/foo').createUrl({ + locale: 'zh-Hans', + fullyQualified: false, + }), + ).toBe('/zh-Hans/foo'); + expect( + mockUseAlternatePageUtils('/foo').createUrl({ + locale: 'zh-Hans', + fullyQualified: true, + }), + ).toBe('https://example.com/zh-Hans/foo'); + }); + + it('works for baseUrl: / and currentLocale /= defaultLocale', () => { + const mockUseAlternatePageUtils = createUseAlternatePageUtilsMock({ + siteConfig: {baseUrl: '/zh-Hans/', url: 'https://example.com'}, + i18n: {defaultLocale: 'en', currentLocale: 'zh-Hans'}, + }); + expect( + mockUseAlternatePageUtils('/zh-Hans/').createUrl({ + locale: 'en', + fullyQualified: false, + }), + ).toBe('/'); + expect( + mockUseAlternatePageUtils('/zh-Hans/foo').createUrl({ + locale: 'en', + fullyQualified: false, + }), + ).toBe('/foo'); + expect( + mockUseAlternatePageUtils('/zh-Hans/foo').createUrl({ + locale: 'en', + fullyQualified: true, + }), + ).toBe('https://example.com/foo'); + }); + + it('works for non-root base URL and currentLocale = defaultLocale', () => { + const mockUseAlternatePageUtils = createUseAlternatePageUtilsMock({ + siteConfig: {baseUrl: '/base/', url: 'https://example.com'}, + i18n: {defaultLocale: 'en', currentLocale: 'en'}, + }); + expect( + mockUseAlternatePageUtils('/base/').createUrl({ + locale: 'zh-Hans', + fullyQualified: false, + }), + ).toBe('/base/zh-Hans/'); + expect( + mockUseAlternatePageUtils('/base/foo').createUrl({ + locale: 'zh-Hans', + fullyQualified: false, + }), + ).toBe('/base/zh-Hans/foo'); + expect( + mockUseAlternatePageUtils('/base/foo').createUrl({ + locale: 'zh-Hans', + fullyQualified: true, + }), + ).toBe('https://example.com/base/zh-Hans/foo'); + }); + + it('works for non-root base URL and currentLocale /= defaultLocale', () => { + const mockUseAlternatePageUtils = createUseAlternatePageUtilsMock({ + siteConfig: {baseUrl: '/base/zh-Hans/', url: 'https://example.com'}, + i18n: {defaultLocale: 'en', currentLocale: 'zh-Hans'}, + }); + expect( + mockUseAlternatePageUtils('/base/zh-Hans/').createUrl({ + locale: 'en', + fullyQualified: false, + }), + ).toBe('/base/'); + expect( + mockUseAlternatePageUtils('/base/zh-Hans/foo').createUrl({ + locale: 'en', + fullyQualified: false, + }), + ).toBe('/base/foo'); + expect( + mockUseAlternatePageUtils('/base/zh-Hans/foo').createUrl({ + locale: 'en', + fullyQualified: true, + }), + ).toBe('https://example.com/base/foo'); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx new file mode 100644 index 000000000000..c8298c5c640d --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {useLocalPathname} from '../useLocalPathname'; +import {renderHook} from '@testing-library/react-hooks'; +import {StaticRouter} from 'react-router-dom'; +import {Context} from '@docusaurus/docusaurusContext'; +import type {DocusaurusContext} from '@docusaurus/types'; + +describe('useLocalPathname', () => { + const createUseLocalPathnameMock = + (context: DocusaurusContext) => (location: string) => + renderHook(() => useLocalPathname(), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current; + it('works for baseUrl: /', () => { + const mockUseLocalPathname = createUseLocalPathnameMock({ + siteConfig: {baseUrl: '/'}, + }); + expect(mockUseLocalPathname('/foo')).toBe('/foo'); + }); + + it('works for non-root baseUrl', () => { + const mockUseLocalPathname = createUseLocalPathnameMock({ + siteConfig: {baseUrl: '/base/'}, + }); + expect(mockUseLocalPathname('/base/foo')).toBe('/foo'); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx new file mode 100644 index 000000000000..d7ab24b9ebcb --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx @@ -0,0 +1,79 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {jest} from '@jest/globals'; +import React from 'react'; +import {usePluralForm} from '../usePluralForm'; +import {renderHook} from '@testing-library/react-hooks'; +import {Context} from '@docusaurus/docusaurusContext'; +import type {DocusaurusContext} from '@docusaurus/types'; + +describe('usePluralForm', () => { + const createUsePluralFormMock = (context: DocusaurusContext) => () => + renderHook(() => usePluralForm(), { + wrapper: ({children}) => ( + {children} + ), + }).result.current; + it('returns the right plural', () => { + const mockUsePluralForm = createUsePluralFormMock({ + i18n: { + currentLocale: 'en', + }, + }); + expect(mockUsePluralForm().selectMessage(1, 'one|many')).toBe('one'); + expect(mockUsePluralForm().selectMessage(10, 'one|many')).toBe('many'); + }); + + it('warns against too many plurals', () => { + const mockUsePluralForm = createUsePluralFormMock({ + i18n: { + currentLocale: 'zh-Hans', + }, + }); + const consoleMock = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + expect(mockUsePluralForm().selectMessage(1, 'one|many')).toBe('one'); + expect(mockUsePluralForm().selectMessage(10, 'one|many')).toBe('one'); + expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot( + `"For locale=zh-Hans, a maximum of 1 plural forms are expected (other), but the message contains 2: one|many"`, + ); + }); + + it('uses the last with not enough plurals', () => { + const mockUsePluralForm = createUsePluralFormMock({ + i18n: { + currentLocale: 'en', + }, + }); + expect(mockUsePluralForm().selectMessage(10, 'many')).toBe('many'); + }); + + it('falls back when Intl.PluralForms is not available', () => { + const mockUsePluralForm = createUsePluralFormMock({ + i18n: { + currentLocale: 'zh-Hans', + }, + }); + const consoleMock = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + const pluralMock = jest + .spyOn(Intl, 'PluralRules') + .mockImplementation(() => undefined); + expect(mockUsePluralForm().selectMessage(1, 'one|many')).toBe('one'); + expect(mockUsePluralForm().selectMessage(10, 'one|many')).toBe('many'); + expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(` + "Failed to use Intl.PluralRules for locale \\"zh-Hans\\". + Docusaurus will fallback to the default (English) implementation. + Error: pluralRules.resolvedOptions is not a function + " + `); + pluralMock.mockRestore(); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index f6863ce2ded5..e935af70acd9 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -187,7 +187,7 @@ export function isActiveSidebarItem( return false; } -export function getBreadcrumbs({ +function getBreadcrumbs({ sidebar, pathname, }: { diff --git a/packages/docusaurus-theme-common/src/utils/generalUtils.ts b/packages/docusaurus-theme-common/src/utils/generalUtils.ts index 055c81517086..a6cc51026770 100644 --- a/packages/docusaurus-theme-common/src/utils/generalUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/generalUtils.ts @@ -7,10 +7,10 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -export const useTitleFormatter = (title?: string | undefined): string => { +export function useTitleFormatter(title?: string | undefined): string { const {siteConfig} = useDocusaurusContext(); const {title: siteTitle, titleDelimiter} = siteConfig; return title && title.trim().length ? `${title.trim()} ${titleDelimiter} ${siteTitle}` : siteTitle; -}; +} diff --git a/packages/docusaurus-theme-common/src/utils/routesUtils.ts b/packages/docusaurus-theme-common/src/utils/routesUtils.ts index 278b85d518bb..ceb76dd2b294 100644 --- a/packages/docusaurus-theme-common/src/utils/routesUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/routesUtils.ts @@ -5,9 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import GeneratedRoutes, {type Route} from '@generated/routes'; +import generatedRoutes from '@generated/routes'; import {useMemo} from 'react'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import type {Route} from '@docusaurus/types'; // Note that all sites don't always have a homepage in practice // See https://github.com/facebook/docusaurus/pull/6517#issuecomment-1048709116 @@ -48,7 +49,7 @@ export function useHomePageRoute(): Route | undefined { return useMemo( () => findHomePageRoute({ - routes: GeneratedRoutes, + routes: generatedRoutes, baseUrl, }), [baseUrl], diff --git a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts index 7397235a3fe9..029dd1bca899 100644 --- a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts +++ b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts @@ -70,21 +70,13 @@ function useLocalePluralForms(): LocalePluralForms { i18n: {currentLocale}, } = useDocusaurusContext(); return useMemo(() => { - // @ts-expect-error checking Intl.PluralRules in case browser doesn't - // have it (e.g Safari 12-) - if (Intl.PluralRules) { - try { - return createLocalePluralForms(currentLocale); - } catch { - console.error(`Failed to use Intl.PluralRules for locale "${currentLocale}". -Docusaurus will fallback to a default/fallback (English) Intl.PluralRules implementation. + try { + return createLocalePluralForms(currentLocale); + } catch (err) { + console.error(`Failed to use Intl.PluralRules for locale "${currentLocale}". +Docusaurus will fallback to the default (English) implementation. +Error: ${(err as Error).message} `); - return EnglishPluralForms; - } - } else { - console.error(`Intl.PluralRules not available! -Docusaurus will fallback to a default/fallback (English) Intl.PluralRules implementation. - `); return EnglishPluralForms; } }, [currentLocale]); @@ -103,7 +95,7 @@ function selectPluralMessage( } if (parts.length > localePluralForms.pluralForms.length) { console.error( - `For locale=${localePluralForms.locale}, a maximum of ${localePluralForms.pluralForms.length} plural forms are expected (${localePluralForms.pluralForms}), but the message contains ${parts.length} plural forms: ${pluralMessages} `, + `For locale=${localePluralForms.locale}, a maximum of ${localePluralForms.pluralForms.length} plural forms are expected (${localePluralForms.pluralForms}), but the message contains ${parts.length}: ${pluralMessages}`, ); } const pluralForm = localePluralForms.select(count); diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 588c90706d50..0378d5e4f8b1 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -372,6 +372,14 @@ export interface RouteConfig { [propName: string]: unknown; } +export type Route = { + readonly path: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readonly component: any; + readonly exact?: boolean; + readonly routes?: Route[]; +}; + // Aliases used for Webpack resolution (when using docusaurus swizzle) export interface ThemeAliases { [alias: string]: string; diff --git a/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts b/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts index 18afd34afc7c..4096b8273fca 100644 --- a/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts +++ b/packages/docusaurus-utils-common/src/__tests__/applyTrailingSlash.test.ts @@ -18,161 +18,161 @@ function params( describe('applyTrailingSlash', () => { it('applies to empty', () => { - expect(applyTrailingSlash('', params(true))).toEqual('/'); - expect(applyTrailingSlash('', params(false))).toEqual(''); - expect(applyTrailingSlash('', params(undefined))).toEqual(''); + expect(applyTrailingSlash('', params(true))).toBe('/'); + expect(applyTrailingSlash('', params(false))).toBe(''); + expect(applyTrailingSlash('', params(undefined))).toBe(''); }); it('does not apply to /', () => { - expect(applyTrailingSlash('/', params(true))).toEqual('/'); - expect(applyTrailingSlash('/', params(false))).toEqual('/'); - expect(applyTrailingSlash('/', params(undefined))).toEqual('/'); + expect(applyTrailingSlash('/', params(true))).toBe('/'); + expect(applyTrailingSlash('/', params(false))).toBe('/'); + expect(applyTrailingSlash('/', params(undefined))).toBe('/'); - expect(applyTrailingSlash('/?query#anchor', params(true))).toEqual( + expect(applyTrailingSlash('/?query#anchor', params(true))).toBe( '/?query#anchor', ); - expect(applyTrailingSlash('/?query#anchor', params(false))).toEqual( + expect(applyTrailingSlash('/?query#anchor', params(false))).toBe( '/?query#anchor', ); - expect(applyTrailingSlash('/?query#anchor', params(undefined))).toEqual( + expect(applyTrailingSlash('/?query#anchor', params(undefined))).toBe( '/?query#anchor', ); }); it('does not apply to /baseUrl/', () => { const baseUrl = '/baseUrl/'; - expect(applyTrailingSlash('/baseUrl/', params(true, baseUrl))).toEqual( + expect(applyTrailingSlash('/baseUrl/', params(true, baseUrl))).toBe( '/baseUrl/', ); - expect(applyTrailingSlash('/baseUrl/', params(false, baseUrl))).toEqual( + expect(applyTrailingSlash('/baseUrl/', params(false, baseUrl))).toBe( '/baseUrl/', ); - expect(applyTrailingSlash('/baseUrl/', params(undefined, baseUrl))).toEqual( + expect(applyTrailingSlash('/baseUrl/', params(undefined, baseUrl))).toBe( '/baseUrl/', ); expect( applyTrailingSlash('/baseUrl/?query#anchor', params(true, baseUrl)), - ).toEqual('/baseUrl/?query#anchor'); + ).toBe('/baseUrl/?query#anchor'); expect( applyTrailingSlash('/baseUrl/?query#anchor', params(false, baseUrl)), - ).toEqual('/baseUrl/?query#anchor'); + ).toBe('/baseUrl/?query#anchor'); expect( applyTrailingSlash('/baseUrl/?query#anchor', params(undefined, baseUrl)), - ).toEqual('/baseUrl/?query#anchor'); + ).toBe('/baseUrl/?query#anchor'); }); it('does not apply to #anchor links', () => { - expect(applyTrailingSlash('#', params(true))).toEqual('#'); - expect(applyTrailingSlash('#', params(false))).toEqual('#'); - expect(applyTrailingSlash('#', params(undefined))).toEqual('#'); - expect(applyTrailingSlash('#anchor', params(true))).toEqual('#anchor'); - expect(applyTrailingSlash('#anchor', params(false))).toEqual('#anchor'); - expect(applyTrailingSlash('#anchor', params(undefined))).toEqual('#anchor'); + expect(applyTrailingSlash('#', params(true))).toBe('#'); + expect(applyTrailingSlash('#', params(false))).toBe('#'); + expect(applyTrailingSlash('#', params(undefined))).toBe('#'); + expect(applyTrailingSlash('#anchor', params(true))).toBe('#anchor'); + expect(applyTrailingSlash('#anchor', params(false))).toBe('#anchor'); + expect(applyTrailingSlash('#anchor', params(undefined))).toBe('#anchor'); }); it('applies to simple paths', () => { - expect(applyTrailingSlash('abc', params(true))).toEqual('abc/'); - expect(applyTrailingSlash('abc', params(false))).toEqual('abc'); - expect(applyTrailingSlash('abc', params(undefined))).toEqual('abc'); - expect(applyTrailingSlash('abc/', params(true))).toEqual('abc/'); - expect(applyTrailingSlash('abc/', params(false))).toEqual('abc'); - expect(applyTrailingSlash('abc/', params(undefined))).toEqual('abc/'); - expect(applyTrailingSlash('/abc', params(true))).toEqual('/abc/'); - expect(applyTrailingSlash('/abc', params(false))).toEqual('/abc'); - expect(applyTrailingSlash('/abc', params(undefined))).toEqual('/abc'); - expect(applyTrailingSlash('/abc/', params(true))).toEqual('/abc/'); - expect(applyTrailingSlash('/abc/', params(false))).toEqual('/abc'); - expect(applyTrailingSlash('/abc/', params(undefined))).toEqual('/abc/'); + expect(applyTrailingSlash('abc', params(true))).toBe('abc/'); + expect(applyTrailingSlash('abc', params(false))).toBe('abc'); + expect(applyTrailingSlash('abc', params(undefined))).toBe('abc'); + expect(applyTrailingSlash('abc/', params(true))).toBe('abc/'); + expect(applyTrailingSlash('abc/', params(false))).toBe('abc'); + expect(applyTrailingSlash('abc/', params(undefined))).toBe('abc/'); + expect(applyTrailingSlash('/abc', params(true))).toBe('/abc/'); + expect(applyTrailingSlash('/abc', params(false))).toBe('/abc'); + expect(applyTrailingSlash('/abc', params(undefined))).toBe('/abc'); + expect(applyTrailingSlash('/abc/', params(true))).toBe('/abc/'); + expect(applyTrailingSlash('/abc/', params(false))).toBe('/abc'); + expect(applyTrailingSlash('/abc/', params(undefined))).toBe('/abc/'); }); it('applies to path with #anchor', () => { - expect(applyTrailingSlash('/abc#anchor', params(true))).toEqual( + expect(applyTrailingSlash('/abc#anchor', params(true))).toBe( '/abc/#anchor', ); - expect(applyTrailingSlash('/abc#anchor', params(false))).toEqual( + expect(applyTrailingSlash('/abc#anchor', params(false))).toBe( '/abc#anchor', ); - expect(applyTrailingSlash('/abc#anchor', params(undefined))).toEqual( + expect(applyTrailingSlash('/abc#anchor', params(undefined))).toBe( '/abc#anchor', ); - expect(applyTrailingSlash('/abc/#anchor', params(true))).toEqual( + expect(applyTrailingSlash('/abc/#anchor', params(true))).toBe( '/abc/#anchor', ); - expect(applyTrailingSlash('/abc/#anchor', params(false))).toEqual( + expect(applyTrailingSlash('/abc/#anchor', params(false))).toBe( '/abc#anchor', ); - expect(applyTrailingSlash('/abc/#anchor', params(undefined))).toEqual( + expect(applyTrailingSlash('/abc/#anchor', params(undefined))).toBe( '/abc/#anchor', ); }); it('applies to path with ?search', () => { - expect(applyTrailingSlash('/abc?search', params(true))).toEqual( + expect(applyTrailingSlash('/abc?search', params(true))).toBe( '/abc/?search', ); - expect(applyTrailingSlash('/abc?search', params(false))).toEqual( + expect(applyTrailingSlash('/abc?search', params(false))).toBe( '/abc?search', ); - expect(applyTrailingSlash('/abc?search', params(undefined))).toEqual( + expect(applyTrailingSlash('/abc?search', params(undefined))).toBe( '/abc?search', ); - expect(applyTrailingSlash('/abc/?search', params(true))).toEqual( + expect(applyTrailingSlash('/abc/?search', params(true))).toBe( '/abc/?search', ); - expect(applyTrailingSlash('/abc/?search', params(false))).toEqual( + expect(applyTrailingSlash('/abc/?search', params(false))).toBe( '/abc?search', ); - expect(applyTrailingSlash('/abc/?search', params(undefined))).toEqual( + expect(applyTrailingSlash('/abc/?search', params(undefined))).toBe( '/abc/?search', ); }); it('applies to path with ?search#anchor', () => { - expect(applyTrailingSlash('/abc?search#anchor', params(true))).toEqual( + expect(applyTrailingSlash('/abc?search#anchor', params(true))).toBe( '/abc/?search#anchor', ); - expect(applyTrailingSlash('/abc?search#anchor', params(false))).toEqual( + expect(applyTrailingSlash('/abc?search#anchor', params(false))).toBe( '/abc?search#anchor', ); - expect(applyTrailingSlash('/abc?search#anchor', params(undefined))).toEqual( + expect(applyTrailingSlash('/abc?search#anchor', params(undefined))).toBe( '/abc?search#anchor', ); - expect(applyTrailingSlash('/abc/?search#anchor', params(true))).toEqual( + expect(applyTrailingSlash('/abc/?search#anchor', params(true))).toBe( '/abc/?search#anchor', ); - expect(applyTrailingSlash('/abc/?search#anchor', params(false))).toEqual( + expect(applyTrailingSlash('/abc/?search#anchor', params(false))).toBe( '/abc?search#anchor', ); - expect( - applyTrailingSlash('/abc/?search#anchor', params(undefined)), - ).toEqual('/abc/?search#anchor'); + expect(applyTrailingSlash('/abc/?search#anchor', params(undefined))).toBe( + '/abc/?search#anchor', + ); }); it('applies to fully qualified urls', () => { expect( applyTrailingSlash('https://xyz.com/abc?search#anchor', params(true)), - ).toEqual('https://xyz.com/abc/?search#anchor'); + ).toBe('https://xyz.com/abc/?search#anchor'); expect( applyTrailingSlash('https://xyz.com/abc?search#anchor', params(false)), - ).toEqual('https://xyz.com/abc?search#anchor'); + ).toBe('https://xyz.com/abc?search#anchor'); expect( applyTrailingSlash( 'https://xyz.com/abc?search#anchor', params(undefined), ), - ).toEqual('https://xyz.com/abc?search#anchor'); + ).toBe('https://xyz.com/abc?search#anchor'); expect( applyTrailingSlash('https://xyz.com/abc/?search#anchor', params(true)), - ).toEqual('https://xyz.com/abc/?search#anchor'); + ).toBe('https://xyz.com/abc/?search#anchor'); expect( applyTrailingSlash('https://xyz.com/abc/?search#anchor', params(false)), - ).toEqual('https://xyz.com/abc?search#anchor'); + ).toBe('https://xyz.com/abc?search#anchor'); expect( applyTrailingSlash( 'https://xyz.com/abc/?search#anchor', params(undefined), ), - ).toEqual('https://xyz.com/abc/?search#anchor'); + ).toBe('https://xyz.com/abc/?search#anchor'); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 7ee81d98e436..a84e8f7a727c 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -67,28 +67,28 @@ describe('readOutputHTMLFile', () => { path.join(__dirname, '__fixtures__/build-snap'), undefined, ).then(String), - ).resolves.toEqual('file\n'); + ).resolves.toBe('file\n'); await expect( readOutputHTMLFile( '/folder', path.join(__dirname, '__fixtures__/build-snap'), undefined, ).then(String), - ).resolves.toEqual('folder\n'); + ).resolves.toBe('folder\n'); await expect( readOutputHTMLFile( '/file/', path.join(__dirname, '__fixtures__/build-snap'), undefined, ).then(String), - ).resolves.toEqual('file\n'); + ).resolves.toBe('file\n'); await expect( readOutputHTMLFile( '/folder/', path.join(__dirname, '__fixtures__/build-snap'), undefined, ).then(String), - ).resolves.toEqual('folder\n'); + ).resolves.toBe('folder\n'); }); it('trailing slash true', async () => { await expect( @@ -97,14 +97,14 @@ describe('readOutputHTMLFile', () => { path.join(__dirname, '__fixtures__/build-snap'), true, ).then(String), - ).resolves.toEqual('folder\n'); + ).resolves.toBe('folder\n'); await expect( readOutputHTMLFile( '/folder/', path.join(__dirname, '__fixtures__/build-snap'), true, ).then(String), - ).resolves.toEqual('folder\n'); + ).resolves.toBe('folder\n'); }); it('trailing slash false', async () => { await expect( @@ -113,14 +113,14 @@ describe('readOutputHTMLFile', () => { path.join(__dirname, '__fixtures__/build-snap'), false, ).then(String), - ).resolves.toEqual('file\n'); + ).resolves.toBe('file\n'); await expect( readOutputHTMLFile( '/file/', path.join(__dirname, '__fixtures__/build-snap'), false, ).then(String), - ).resolves.toEqual('file\n'); + ).resolves.toBe('file\n'); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts index 9bcac88b84aa..e1794e972913 100644 --- a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts @@ -15,53 +15,53 @@ describe('createMatcher', () => { const matcher = createMatcher(GlobExcludeDefault); it('match default exclude MD/MDX partials correctly', () => { - expect(matcher('doc.md')).toEqual(false); - expect(matcher('category/doc.md')).toEqual(false); - expect(matcher('category/subcategory/doc.md')).toEqual(false); + expect(matcher('doc.md')).toBe(false); + expect(matcher('category/doc.md')).toBe(false); + expect(matcher('category/subcategory/doc.md')).toBe(false); // - expect(matcher('doc.mdx')).toEqual(false); - expect(matcher('category/doc.mdx')).toEqual(false); - expect(matcher('category/subcategory/doc.mdx')).toEqual(false); + expect(matcher('doc.mdx')).toBe(false); + expect(matcher('category/doc.mdx')).toBe(false); + expect(matcher('category/subcategory/doc.mdx')).toBe(false); // - expect(matcher('_doc.md')).toEqual(true); - expect(matcher('category/_doc.md')).toEqual(true); - expect(matcher('category/subcategory/_doc.md')).toEqual(true); - expect(matcher('_category/doc.md')).toEqual(true); - expect(matcher('_category/subcategory/doc.md')).toEqual(true); - expect(matcher('category/_subcategory/doc.md')).toEqual(true); + expect(matcher('_doc.md')).toBe(true); + expect(matcher('category/_doc.md')).toBe(true); + expect(matcher('category/subcategory/_doc.md')).toBe(true); + expect(matcher('_category/doc.md')).toBe(true); + expect(matcher('_category/subcategory/doc.md')).toBe(true); + expect(matcher('category/_subcategory/doc.md')).toBe(true); }); it('match default exclude tests correctly', () => { - expect(matcher('xyz.js')).toEqual(false); - expect(matcher('xyz.ts')).toEqual(false); - expect(matcher('xyz.jsx')).toEqual(false); - expect(matcher('xyz.tsx')).toEqual(false); - expect(matcher('folder/xyz.js')).toEqual(false); - expect(matcher('folder/xyz.ts')).toEqual(false); - expect(matcher('folder/xyz.jsx')).toEqual(false); - expect(matcher('folder/xyz.tsx')).toEqual(false); + expect(matcher('xyz.js')).toBe(false); + expect(matcher('xyz.ts')).toBe(false); + expect(matcher('xyz.jsx')).toBe(false); + expect(matcher('xyz.tsx')).toBe(false); + expect(matcher('folder/xyz.js')).toBe(false); + expect(matcher('folder/xyz.ts')).toBe(false); + expect(matcher('folder/xyz.jsx')).toBe(false); + expect(matcher('folder/xyz.tsx')).toBe(false); // - expect(matcher('xyz.test.js')).toEqual(true); - expect(matcher('xyz.test.ts')).toEqual(true); - expect(matcher('xyz.test.jsx')).toEqual(true); - expect(matcher('xyz.test.tsx')).toEqual(true); - expect(matcher('folder/xyz.test.js')).toEqual(true); - expect(matcher('folder/xyz.test.ts')).toEqual(true); - expect(matcher('folder/xyz.test.jsx')).toEqual(true); - expect(matcher('folder/xyz.test.tsx')).toEqual(true); - expect(matcher('folder/subfolder/xyz.test.js')).toEqual(true); - expect(matcher('folder/subfolder/xyz.test.ts')).toEqual(true); - expect(matcher('folder/subfolder/xyz.test.jsx')).toEqual(true); - expect(matcher('folder/subfolder/xyz.test.tsx')).toEqual(true); + expect(matcher('xyz.test.js')).toBe(true); + expect(matcher('xyz.test.ts')).toBe(true); + expect(matcher('xyz.test.jsx')).toBe(true); + expect(matcher('xyz.test.tsx')).toBe(true); + expect(matcher('folder/xyz.test.js')).toBe(true); + expect(matcher('folder/xyz.test.ts')).toBe(true); + expect(matcher('folder/xyz.test.jsx')).toBe(true); + expect(matcher('folder/xyz.test.tsx')).toBe(true); + expect(matcher('folder/subfolder/xyz.test.js')).toBe(true); + expect(matcher('folder/subfolder/xyz.test.ts')).toBe(true); + expect(matcher('folder/subfolder/xyz.test.jsx')).toBe(true); + expect(matcher('folder/subfolder/xyz.test.tsx')).toBe(true); // - expect(matcher('__tests__/subfolder/xyz.js')).toEqual(true); - expect(matcher('__tests__/subfolder/xyz.ts')).toEqual(true); - expect(matcher('__tests__/subfolder/xyz.jsx')).toEqual(true); - expect(matcher('__tests__/subfolder/xyz.tsx')).toEqual(true); - expect(matcher('folder/__tests__/xyz.js')).toEqual(true); - expect(matcher('folder/__tests__/xyz.ts')).toEqual(true); - expect(matcher('folder/__tests__/xyz.jsx')).toEqual(true); - expect(matcher('folder/__tests__/xyz.tsx')).toEqual(true); + expect(matcher('__tests__/subfolder/xyz.js')).toBe(true); + expect(matcher('__tests__/subfolder/xyz.ts')).toBe(true); + expect(matcher('__tests__/subfolder/xyz.jsx')).toBe(true); + expect(matcher('__tests__/subfolder/xyz.tsx')).toBe(true); + expect(matcher('folder/__tests__/xyz.js')).toBe(true); + expect(matcher('folder/__tests__/xyz.ts')).toBe(true); + expect(matcher('folder/__tests__/xyz.jsx')).toBe(true); + expect(matcher('folder/__tests__/xyz.tsx')).toBe(true); }); }); @@ -74,29 +74,29 @@ describe('createAbsoluteFilePathMatcher', () => { ); it('match default exclude MD/MDX partials correctly', () => { - expect(matcher('/_root/docs/myDoc.md')).toEqual(false); - expect(matcher('/_root/docs/myDoc.mdx')).toEqual(false); - expect(matcher('/root/_docs/myDoc.md')).toEqual(false); - expect(matcher('/root/_docs/myDoc.mdx')).toEqual(false); - expect(matcher('/_root/docs/category/myDoc.md')).toEqual(false); - expect(matcher('/_root/docs/category/myDoc.mdx')).toEqual(false); - expect(matcher('/root/_docs/category/myDoc.md')).toEqual(false); - expect(matcher('/root/_docs/category/myDoc.mdx')).toEqual(false); + expect(matcher('/_root/docs/myDoc.md')).toBe(false); + expect(matcher('/_root/docs/myDoc.mdx')).toBe(false); + expect(matcher('/root/_docs/myDoc.md')).toBe(false); + expect(matcher('/root/_docs/myDoc.mdx')).toBe(false); + expect(matcher('/_root/docs/category/myDoc.md')).toBe(false); + expect(matcher('/_root/docs/category/myDoc.mdx')).toBe(false); + expect(matcher('/root/_docs/category/myDoc.md')).toBe(false); + expect(matcher('/root/_docs/category/myDoc.mdx')).toBe(false); // - expect(matcher('/_root/docs/_myDoc.md')).toEqual(true); - expect(matcher('/_root/docs/_myDoc.mdx')).toEqual(true); - expect(matcher('/root/_docs/_myDoc.md')).toEqual(true); - expect(matcher('/root/_docs/_myDoc.mdx')).toEqual(true); - expect(matcher('/_root/docs/_category/myDoc.md')).toEqual(true); - expect(matcher('/_root/docs/_category/myDoc.mdx')).toEqual(true); - expect(matcher('/root/_docs/_category/myDoc.md')).toEqual(true); - expect(matcher('/root/_docs/_category/myDoc.mdx')).toEqual(true); + expect(matcher('/_root/docs/_myDoc.md')).toBe(true); + expect(matcher('/_root/docs/_myDoc.mdx')).toBe(true); + expect(matcher('/root/_docs/_myDoc.md')).toBe(true); + expect(matcher('/root/_docs/_myDoc.mdx')).toBe(true); + expect(matcher('/_root/docs/_category/myDoc.md')).toBe(true); + expect(matcher('/_root/docs/_category/myDoc.mdx')).toBe(true); + expect(matcher('/root/_docs/_category/myDoc.md')).toBe(true); + expect(matcher('/root/_docs/_category/myDoc.mdx')).toBe(true); }); it('match default exclude tests correctly', () => { - expect(matcher('/__test__/website/src/xyz.js')).toEqual(false); - expect(matcher('/__test__/website/src/__test__/xyz.js')).toEqual(true); - expect(matcher('/__test__/website/src/xyz.test.js')).toEqual(true); + expect(matcher('/__test__/website/src/xyz.js')).toBe(false); + expect(matcher('/__test__/website/src/__test__/xyz.js')).toBe(true); + expect(matcher('/__test__/website/src/xyz.test.js')).toBe(true); }); it('throw if file is not contained in any root doc', () => { diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index 2716091437ee..b9646927c01f 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -18,23 +18,23 @@ import _ from 'lodash'; describe('removeSuffix', () => { it("is no-op when suffix doesn't exist", () => { - expect(removeSuffix('abcdef', 'ijk')).toEqual('abcdef'); - expect(removeSuffix('abcdef', 'abc')).toEqual('abcdef'); - expect(removeSuffix('abcdef', '')).toEqual('abcdef'); + expect(removeSuffix('abcdef', 'ijk')).toBe('abcdef'); + expect(removeSuffix('abcdef', 'abc')).toBe('abcdef'); + expect(removeSuffix('abcdef', '')).toBe('abcdef'); }); it('removes suffix', () => { - expect(removeSuffix('abcdef', 'ef')).toEqual('abcd'); + expect(removeSuffix('abcdef', 'ef')).toBe('abcd'); }); }); describe('removePrefix', () => { it("is no-op when prefix doesn't exist", () => { - expect(removePrefix('abcdef', 'ijk')).toEqual('abcdef'); - expect(removePrefix('abcdef', 'def')).toEqual('abcdef'); - expect(removePrefix('abcdef', '')).toEqual('abcdef'); + expect(removePrefix('abcdef', 'ijk')).toBe('abcdef'); + expect(removePrefix('abcdef', 'def')).toBe('abcdef'); + expect(removePrefix('abcdef', '')).toBe('abcdef'); }); it('removes prefix', () => { - expect(removePrefix('abcdef', 'ab')).toEqual('cdef'); + expect(removePrefix('abcdef', 'ab')).toBe('cdef'); }); }); @@ -133,7 +133,7 @@ describe('findAsyncSequential', () => { }); const timeBefore = Date.now(); - await expect(findAsyncSequential(items, findFn)).resolves.toEqual('2'); + await expect(findAsyncSequential(items, findFn)).resolves.toBe('2'); const timeAfter = Date.now(); expect(findFn).toHaveBeenCalledTimes(2); diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts index e928c02fc0c5..661591f5e567 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts @@ -21,7 +21,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual( + ).toBe( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', ); }); @@ -36,7 +36,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual( + ).toBe( // h1 title is skipped on purpose, because we don't want the page to have // SEO metadata title === description 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', @@ -54,7 +54,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual( + ).toBe( // h1 title is skipped on purpose, because we don't want the page to have // SEO metadata title === description 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', @@ -68,7 +68,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual('Lorem ipsum dolor sit amet'); + ).toBe('Lorem ipsum dolor sit amet'); }); it('creates excerpt for content beginning with blockquote', () => { @@ -78,7 +78,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual('Lorem ipsum dolor sit amet'); + ).toBe('Lorem ipsum dolor sit amet'); }); it('creates excerpt for content beginning with image (eg. blog post)', () => { @@ -86,7 +86,7 @@ describe('createExcerpt', () => { createExcerpt(dedent` ![Lorem ipsum](/img/lorem-ipsum.svg) `), - ).toEqual('Lorem ipsum'); + ).toBe('Lorem ipsum'); }); it('creates excerpt for content beginning with admonitions', () => { @@ -102,7 +102,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); + ).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); }); it('creates excerpt for content with imports/exports declarations and Markdown markup, as well as Emoji', () => { @@ -120,7 +120,7 @@ describe('createExcerpt', () => { Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), - ).toEqual( + ).toBe( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', ); }); @@ -130,7 +130,7 @@ describe('createExcerpt', () => { createExcerpt(dedent` ## Markdown title {#my-anchor-id} `), - ).toEqual('Markdown title'); + ).toBe('Markdown title'); }); it('creates excerpt for content with various code blocks', () => { @@ -143,7 +143,7 @@ describe('createExcerpt', () => { Lorem \`ipsum\` dolor sit amet, consectetur \`adipiscing elit\`. `), - ).toEqual('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); + ).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts index c6eabf9d12db..5fddcfb5cfd2 100644 --- a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts @@ -123,9 +123,9 @@ describe('toMessageRelativeFilePath', () => { jest .spyOn(process, 'cwd') .mockImplementationOnce(() => path.join(__dirname, '..')); - expect( - toMessageRelativeFilePath(path.join(__dirname, 'foo/bar.js')), - ).toEqual('__tests__/foo/bar.js'); + expect(toMessageRelativeFilePath(path.join(__dirname, 'foo/bar.js'))).toBe( + '__tests__/foo/bar.js', + ); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/slugger.test.ts b/packages/docusaurus-utils/src/__tests__/slugger.test.ts index 310e4cf33af3..eff493883ad5 100644 --- a/packages/docusaurus-utils/src/__tests__/slugger.test.ts +++ b/packages/docusaurus-utils/src/__tests__/slugger.test.ts @@ -10,18 +10,18 @@ import {createSlugger} from '../slugger'; describe('createSlugger', () => { it('can create unique slugs', () => { const slugger = createSlugger(); - expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue'); - expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue-1'); - expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue-2'); - expect(slugger.slug('Some$/vaLue$!^-1')).toEqual('somevalue-1-1'); + expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue'); + expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue-1'); + expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue-2'); + expect(slugger.slug('Some$/vaLue$!^-1')).toBe('somevalue-1-1'); }); it('can create unique slugs respecting case', () => { const slugger = createSlugger(); const opt = {maintainCase: true}; - expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue'); - expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue-1'); - expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue-2'); - expect(slugger.slug('Some$/vaLue$!^-1', opt)).toEqual('SomevaLue-1-1'); + expect(slugger.slug('Some$/vaLue$!^', opt)).toBe('SomevaLue'); + expect(slugger.slug('Some$/vaLue$!^', opt)).toBe('SomevaLue-1'); + expect(slugger.slug('Some$/vaLue$!^', opt)).toBe('SomevaLue-2'); + expect(slugger.slug('Some$/vaLue$!^-1', opt)).toBe('SomevaLue-1-1'); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts index 306b12bb6e17..4ac1e542711d 100644 --- a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts @@ -146,15 +146,15 @@ describe('getEditUrl', () => { it('returns right path', () => { expect( getEditUrl('foo/bar.md', 'https://github.com/facebook/docusaurus'), - ).toEqual('https://github.com/facebook/docusaurus/foo/bar.md'); + ).toBe('https://github.com/facebook/docusaurus/foo/bar.md'); expect( getEditUrl('foo/你好.md', 'https://github.com/facebook/docusaurus'), - ).toEqual('https://github.com/facebook/docusaurus/foo/你好.md'); + ).toBe('https://github.com/facebook/docusaurus/foo/你好.md'); }); it('always returns valid URL', () => { expect( getEditUrl('foo\\你好.md', 'https://github.com/facebook/docusaurus'), - ).toEqual('https://github.com/facebook/docusaurus/foo/你好.md'); + ).toBe('https://github.com/facebook/docusaurus/foo/你好.md'); }); it('returns undefined for undefined', () => { expect(getEditUrl('foo/bar.md')).toBeUndefined(); @@ -200,28 +200,28 @@ describe('isValidPathname', () => { describe('addTrailingSlash', () => { it('is no-op for path with trailing slash', () => { - expect(addTrailingSlash('/abcd/')).toEqual('/abcd/'); + expect(addTrailingSlash('/abcd/')).toBe('/abcd/'); }); it('adds / for path without trailing slash', () => { - expect(addTrailingSlash('/abcd')).toEqual('/abcd/'); + expect(addTrailingSlash('/abcd')).toBe('/abcd/'); }); }); describe('addLeadingSlash', () => { it('is no-op for path with leading slash', () => { - expect(addLeadingSlash('/abc')).toEqual('/abc'); + expect(addLeadingSlash('/abc')).toBe('/abc'); }); it('adds / for path without leading slash', () => { - expect(addLeadingSlash('abc')).toEqual('/abc'); + expect(addLeadingSlash('abc')).toBe('/abc'); }); }); describe('removeTrailingSlash', () => { it('is no-op for path without trailing slash', () => { - expect(removeTrailingSlash('/abcd')).toEqual('/abcd'); + expect(removeTrailingSlash('/abcd')).toBe('/abcd'); }); it('removes / for path with trailing slash', () => { - expect(removeTrailingSlash('/abcd/')).toEqual('/abcd'); + expect(removeTrailingSlash('/abcd/')).toBe('/abcd'); }); }); @@ -229,21 +229,21 @@ describe('resolvePathname', () => { it('works', () => { // These tests are directly copied from https://github.com/mjackson/resolve-pathname/blob/master/modules/__tests__/resolvePathname-test.js // Maybe we want to wrap that logic in the future? - expect(resolvePathname('c')).toEqual('c'); - expect(resolvePathname('c', 'a/b')).toEqual('a/c'); - expect(resolvePathname('/c', '/a/b')).toEqual('/c'); - expect(resolvePathname('', '/a/b')).toEqual('/a/b'); - expect(resolvePathname('../c', '/a/b')).toEqual('/c'); - expect(resolvePathname('c', '/a/b')).toEqual('/a/c'); - expect(resolvePathname('c', '/a/')).toEqual('/a/c'); - expect(resolvePathname('..', '/a/b')).toEqual('/'); + expect(resolvePathname('c')).toBe('c'); + expect(resolvePathname('c', 'a/b')).toBe('a/c'); + expect(resolvePathname('/c', '/a/b')).toBe('/c'); + expect(resolvePathname('', '/a/b')).toBe('/a/b'); + expect(resolvePathname('../c', '/a/b')).toBe('/c'); + expect(resolvePathname('c', '/a/b')).toBe('/a/c'); + expect(resolvePathname('c', '/a/')).toBe('/a/c'); + expect(resolvePathname('..', '/a/b')).toBe('/'); }); }); describe('encodePath', () => { it('works', () => { - expect(encodePath('a/foo/')).toEqual('a/foo/'); - expect(encodePath('a//')).toEqual('a/%3Cfoo%3E/'); - expect(encodePath('a/你好/')).toEqual('a/%E4%BD%A0%E5%A5%BD/'); + expect(encodePath('a/foo/')).toBe('a/foo/'); + expect(encodePath('a//')).toBe('a/%3Cfoo%3E/'); + expect(encodePath('a/你好/')).toBe('a/%E4%BD%A0%E5%A5%BD/'); }); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx index 2b8c3d27e3cd..b1e8efb76ac3 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx @@ -9,15 +9,15 @@ import {translate} from '../Translate'; describe('translate', () => { it('accept id and use it as fallback', () => { - expect(translate({id: 'some-id'})).toEqual('some-id'); + expect(translate({id: 'some-id'})).toBe('some-id'); }); it('accept message and use it as fallback', () => { - expect(translate({message: 'some-message'})).toEqual('some-message'); + expect(translate({message: 'some-message'})).toBe('some-message'); }); it('accept id+message and use message as fallback', () => { - expect(translate({id: 'some-id', message: 'some-message'})).toEqual( + expect(translate({id: 'some-id', message: 'some-message'})).toBe( 'some-message', ); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts deleted file mode 100644 index 7b713ffa8be7..000000000000 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {jest} from '@jest/globals'; -import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl'; -import useDocusaurusContext from '../useDocusaurusContext'; - -jest.mock('../useDocusaurusContext'); - -const mockedContext = useDocusaurusContext as jest.Mock; - -const forcePrepend = {forcePrependBaseUrl: true}; - -describe('useBaseUrl', () => { - it('empty base URL', () => { - mockedContext.mockImplementation(() => ({ - siteConfig: { - baseUrl: '/', - url: 'https://docusaurus.io', - }, - })); - - expect(useBaseUrl('hello')).toEqual('/hello'); - expect(useBaseUrl('/hello')).toEqual('/hello'); - expect(useBaseUrl('hello/')).toEqual('/hello/'); - expect(useBaseUrl('/hello/')).toEqual('/hello/'); - expect(useBaseUrl('hello/byebye')).toEqual('/hello/byebye'); - expect(useBaseUrl('/hello/byebye')).toEqual('/hello/byebye'); - expect(useBaseUrl('hello/byebye/')).toEqual('/hello/byebye/'); - expect(useBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/'); - expect(useBaseUrl('https://github.com')).toEqual('https://github.com'); - expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org'); - expect(useBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org'); - expect(useBaseUrl('https://site.com', forcePrepend)).toEqual( - 'https://site.com', - ); - expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual( - 'https://docusaurus.io/hello/byebye', - ); - expect(useBaseUrl('#hello')).toEqual('#hello'); - }); - - it('non-empty base URL', () => { - mockedContext.mockImplementation(() => ({ - siteConfig: { - baseUrl: '/docusaurus/', - url: 'https://docusaurus.io', - }, - })); - - expect(useBaseUrl('')).toEqual(''); - expect(useBaseUrl('hello')).toEqual('/docusaurus/hello'); - expect(useBaseUrl('/hello')).toEqual('/docusaurus/hello'); - expect(useBaseUrl('hello/')).toEqual('/docusaurus/hello/'); - expect(useBaseUrl('/hello/')).toEqual('/docusaurus/hello/'); - expect(useBaseUrl('hello/byebye')).toEqual('/docusaurus/hello/byebye'); - expect(useBaseUrl('/hello/byebye')).toEqual('/docusaurus/hello/byebye'); - expect(useBaseUrl('hello/byebye/')).toEqual('/docusaurus/hello/byebye/'); - expect(useBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/'); - expect(useBaseUrl('https://github.com')).toEqual('https://github.com'); - expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org'); - expect(useBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org'); - expect(useBaseUrl('/hello', forcePrepend)).toEqual('/docusaurus/hello'); - expect(useBaseUrl('https://site.com', forcePrepend)).toEqual( - 'https://site.com', - ); - expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual( - 'https://docusaurus.io/docusaurus/hello/byebye', - ); - expect(useBaseUrl('/docusaurus/')).toEqual('/docusaurus/'); - expect(useBaseUrl('/docusaurus/hello')).toEqual('/docusaurus/hello'); - expect(useBaseUrl('#hello')).toEqual('#hello'); - }); -}); - -describe('useBaseUrlUtils().withBaseUrl()', () => { - it('empty base URL', () => { - mockedContext.mockImplementation(() => ({ - siteConfig: { - baseUrl: '/', - url: 'https://docusaurus.io', - }, - })); - const {withBaseUrl} = useBaseUrlUtils(); - - expect(withBaseUrl('hello')).toEqual('/hello'); - expect(withBaseUrl('/hello')).toEqual('/hello'); - expect(withBaseUrl('hello/')).toEqual('/hello/'); - expect(withBaseUrl('/hello/')).toEqual('/hello/'); - expect(withBaseUrl('hello/byebye')).toEqual('/hello/byebye'); - expect(withBaseUrl('/hello/byebye')).toEqual('/hello/byebye'); - expect(withBaseUrl('hello/byebye/')).toEqual('/hello/byebye/'); - expect(withBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/'); - expect(withBaseUrl('https://github.com')).toEqual('https://github.com'); - expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org'); - expect(withBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org'); - expect(withBaseUrl('https://site.com', forcePrepend)).toEqual( - 'https://site.com', - ); - expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual( - 'https://docusaurus.io/hello/byebye', - ); - expect(withBaseUrl('#hello')).toEqual('#hello'); - }); - - it('non-empty base URL', () => { - mockedContext.mockImplementation(() => ({ - siteConfig: { - baseUrl: '/docusaurus/', - url: 'https://docusaurus.io', - }, - })); - const {withBaseUrl} = useBaseUrlUtils(); - - expect(withBaseUrl('hello')).toEqual('/docusaurus/hello'); - expect(withBaseUrl('/hello')).toEqual('/docusaurus/hello'); - expect(withBaseUrl('hello/')).toEqual('/docusaurus/hello/'); - expect(withBaseUrl('/hello/')).toEqual('/docusaurus/hello/'); - expect(withBaseUrl('hello/byebye')).toEqual('/docusaurus/hello/byebye'); - expect(withBaseUrl('/hello/byebye')).toEqual('/docusaurus/hello/byebye'); - expect(withBaseUrl('hello/byebye/')).toEqual('/docusaurus/hello/byebye/'); - expect(withBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/'); - expect(withBaseUrl('https://github.com')).toEqual('https://github.com'); - expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org'); - expect(withBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org'); - expect(withBaseUrl('https://site.com', forcePrepend)).toEqual( - 'https://site.com', - ); - expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual( - 'https://docusaurus.io/docusaurus/hello/byebye', - ); - expect(withBaseUrl('/docusaurus/')).toEqual('/docusaurus/'); - expect(withBaseUrl('/docusaurus/hello')).toEqual('/docusaurus/hello'); - expect(withBaseUrl('#hello')).toEqual('#hello'); - }); -}); diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx new file mode 100644 index 000000000000..303e8c264962 --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx @@ -0,0 +1,150 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks'; +import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl'; +import {Context} from '../docusaurusContext'; +import type {DocusaurusContext} from '@docusaurus/types'; +import type {BaseUrlOptions} from '@docusaurus/useBaseUrl'; + +const forcePrepend = {forcePrependBaseUrl: true}; + +describe('useBaseUrl', () => { + const createUseBaseUrlMock = + (context: DocusaurusContext) => (url: string, options?: BaseUrlOptions) => + renderHook(() => useBaseUrl(url, options), { + wrapper: ({children}) => ( + {children} + ), + }).result.current; + it('works with empty base URL', () => { + const mockUseBaseUrl = createUseBaseUrlMock({ + siteConfig: { + baseUrl: '/', + url: 'https://docusaurus.io', + }, + }); + + expect(mockUseBaseUrl('hello')).toBe('/hello'); + expect(mockUseBaseUrl('/hello')).toBe('/hello'); + expect(mockUseBaseUrl('hello/')).toBe('/hello/'); + expect(mockUseBaseUrl('/hello/')).toBe('/hello/'); + expect(mockUseBaseUrl('hello/byebye')).toBe('/hello/byebye'); + expect(mockUseBaseUrl('/hello/byebye')).toBe('/hello/byebye'); + expect(mockUseBaseUrl('hello/byebye/')).toBe('/hello/byebye/'); + expect(mockUseBaseUrl('/hello/byebye/')).toBe('/hello/byebye/'); + expect(mockUseBaseUrl('https://github.com')).toBe('https://github.com'); + expect(mockUseBaseUrl('//reactjs.org')).toBe('//reactjs.org'); + expect(mockUseBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); + expect(mockUseBaseUrl('https://site.com', forcePrepend)).toBe( + 'https://site.com', + ); + expect(mockUseBaseUrl('/hello/byebye', {absolute: true})).toBe( + 'https://docusaurus.io/hello/byebye', + ); + expect(mockUseBaseUrl('#hello')).toBe('#hello'); + }); + + it('works with non-empty base URL', () => { + const mockUseBaseUrl = createUseBaseUrlMock({ + siteConfig: { + baseUrl: '/docusaurus/', + url: 'https://docusaurus.io', + }, + }); + + expect(mockUseBaseUrl('')).toBe(''); + expect(mockUseBaseUrl('hello')).toBe('/docusaurus/hello'); + expect(mockUseBaseUrl('/hello')).toBe('/docusaurus/hello'); + expect(mockUseBaseUrl('hello/')).toBe('/docusaurus/hello/'); + expect(mockUseBaseUrl('/hello/')).toBe('/docusaurus/hello/'); + expect(mockUseBaseUrl('hello/byebye')).toBe('/docusaurus/hello/byebye'); + expect(mockUseBaseUrl('/hello/byebye')).toBe('/docusaurus/hello/byebye'); + expect(mockUseBaseUrl('hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(mockUseBaseUrl('/hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(mockUseBaseUrl('https://github.com')).toBe('https://github.com'); + expect(mockUseBaseUrl('//reactjs.org')).toBe('//reactjs.org'); + expect(mockUseBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); + expect(mockUseBaseUrl('/hello', forcePrepend)).toBe('/docusaurus/hello'); + expect(mockUseBaseUrl('https://site.com', forcePrepend)).toBe( + 'https://site.com', + ); + expect(mockUseBaseUrl('/hello/byebye', {absolute: true})).toBe( + 'https://docusaurus.io/docusaurus/hello/byebye', + ); + expect(mockUseBaseUrl('/docusaurus/')).toBe('/docusaurus/'); + expect(mockUseBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); + expect(mockUseBaseUrl('#hello')).toBe('#hello'); + }); +}); + +describe('useBaseUrlUtils().withBaseUrl()', () => { + const mockUseBaseUrlUtils = (context: DocusaurusContext) => + renderHook(() => useBaseUrlUtils(), { + wrapper: ({children}) => ( + {children} + ), + }).result.current; + it('empty base URL', () => { + const {withBaseUrl} = mockUseBaseUrlUtils({ + siteConfig: { + baseUrl: '/', + url: 'https://docusaurus.io', + }, + }); + + expect(withBaseUrl('hello')).toBe('/hello'); + expect(withBaseUrl('/hello')).toBe('/hello'); + expect(withBaseUrl('hello/')).toBe('/hello/'); + expect(withBaseUrl('/hello/')).toBe('/hello/'); + expect(withBaseUrl('hello/byebye')).toBe('/hello/byebye'); + expect(withBaseUrl('/hello/byebye')).toBe('/hello/byebye'); + expect(withBaseUrl('hello/byebye/')).toBe('/hello/byebye/'); + expect(withBaseUrl('/hello/byebye/')).toBe('/hello/byebye/'); + expect(withBaseUrl('https://github.com')).toBe('https://github.com'); + expect(withBaseUrl('//reactjs.org')).toBe('//reactjs.org'); + expect(withBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); + expect(withBaseUrl('https://site.com', forcePrepend)).toBe( + 'https://site.com', + ); + expect(withBaseUrl('/hello/byebye', {absolute: true})).toBe( + 'https://docusaurus.io/hello/byebye', + ); + expect(withBaseUrl('#hello')).toBe('#hello'); + }); + + it('non-empty base URL', () => { + const {withBaseUrl} = mockUseBaseUrlUtils({ + siteConfig: { + baseUrl: '/docusaurus/', + url: 'https://docusaurus.io', + }, + }); + + expect(withBaseUrl('hello')).toBe('/docusaurus/hello'); + expect(withBaseUrl('/hello')).toBe('/docusaurus/hello'); + expect(withBaseUrl('hello/')).toBe('/docusaurus/hello/'); + expect(withBaseUrl('/hello/')).toBe('/docusaurus/hello/'); + expect(withBaseUrl('hello/byebye')).toBe('/docusaurus/hello/byebye'); + expect(withBaseUrl('/hello/byebye')).toBe('/docusaurus/hello/byebye'); + expect(withBaseUrl('hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(withBaseUrl('/hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(withBaseUrl('https://github.com')).toBe('https://github.com'); + expect(withBaseUrl('//reactjs.org')).toBe('//reactjs.org'); + expect(withBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); + expect(withBaseUrl('https://site.com', forcePrepend)).toBe( + 'https://site.com', + ); + expect(withBaseUrl('/hello/byebye', {absolute: true})).toBe( + 'https://docusaurus.io/docusaurus/hello/byebye', + ); + expect(withBaseUrl('/docusaurus/')).toBe('/docusaurus/'); + expect(withBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); + expect(withBaseUrl('#hello')).toBe('#hello'); + }); +}); diff --git a/packages/docusaurus/src/commands/__tests__/deploy.test.ts b/packages/docusaurus/src/commands/__tests__/deploy.test.ts index ca5dd0645883..a326ba08fac1 100644 --- a/packages/docusaurus/src/commands/__tests__/deploy.test.ts +++ b/packages/docusaurus/src/commands/__tests__/deploy.test.ts @@ -10,11 +10,11 @@ import {buildSshUrl, buildHttpsUrl, hasSSHProtocol} from '../deploy'; describe('remoteBranchUrl', () => { it('builds a normal ssh url', () => { const url = buildSshUrl('github.com', 'facebook', 'docusaurus'); - expect(url).toEqual('git@github.com:facebook/docusaurus.git'); + expect(url).toBe('git@github.com:facebook/docusaurus.git'); }); it('builds a ssh url with port', () => { const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422'); - expect(url).toEqual('ssh://git@github.com:422/facebook/docusaurus.git'); + expect(url).toBe('ssh://git@github.com:422/facebook/docusaurus.git'); }); it('builds a normal http url', () => { const url = buildHttpsUrl( @@ -23,7 +23,7 @@ describe('remoteBranchUrl', () => { 'facebook', 'docusaurus', ); - expect(url).toEqual('https://user:pass@github.com/facebook/docusaurus.git'); + expect(url).toBe('https://user:pass@github.com/facebook/docusaurus.git'); }); it('builds a normal http url with port', () => { const url = buildHttpsUrl( @@ -33,7 +33,7 @@ describe('remoteBranchUrl', () => { 'docusaurus', '5433', ); - expect(url).toEqual( + expect(url).toBe( 'https://user:pass@github.com:5433/facebook/docusaurus.git', ); }); @@ -42,21 +42,21 @@ describe('remoteBranchUrl', () => { describe('hasSSHProtocol', () => { it('recognizes explicit SSH protocol', () => { const url = 'ssh://git@github.com:422/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toEqual(true); + expect(hasSSHProtocol(url)).toBe(true); }); it('recognizes implied SSH protocol', () => { const url = 'git@github.com:facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toEqual(true); + expect(hasSSHProtocol(url)).toBe(true); }); it('does not recognize HTTPS with credentials', () => { const url = 'https://user:pass@github.com/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toEqual(false); + expect(hasSSHProtocol(url)).toBe(false); }); it('does not recognize plain HTTPS URL', () => { const url = 'https://github.com:5433/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toEqual(false); + expect(hasSSHProtocol(url)).toBe(false); }); }); diff --git a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts index 05f43abd7152..0eedbd583c03 100644 --- a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts +++ b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts @@ -9,39 +9,39 @@ import {transformMarkdownContent} from '../writeHeadingIds'; describe('transformMarkdownContent', () => { it('works for simple level-2 heading', () => { - expect(transformMarkdownContent('## ABC')).toEqual('## ABC {#abc}'); + expect(transformMarkdownContent('## ABC')).toBe('## ABC {#abc}'); }); it('works for simple level-3 heading', () => { - expect(transformMarkdownContent('### ABC')).toEqual('### ABC {#abc}'); + expect(transformMarkdownContent('### ABC')).toBe('### ABC {#abc}'); }); it('works for simple level-4 heading', () => { - expect(transformMarkdownContent('#### ABC')).toEqual('#### ABC {#abc}'); + expect(transformMarkdownContent('#### ABC')).toBe('#### ABC {#abc}'); }); it('unwraps markdown links', () => { const input = `## hello [facebook](https://facebook.com) [crowdin](https://crowdin.com/translate/docusaurus-v2/126/en-fr?filter=basic&value=0)`; - expect(transformMarkdownContent(input)).toEqual( + expect(transformMarkdownContent(input)).toBe( `${input} {#hello-facebook-crowdin}`, ); }); it('can slugify complex headings', () => { const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756'; - expect(transformMarkdownContent(input)).toEqual( + expect(transformMarkdownContent(input)).toBe( `${input} {#abc-hello-how-are-you-sébastien_-_---56756}`, ); }); it('does not duplicate duplicate id', () => { - expect(transformMarkdownContent('## hello world {#hello-world}')).toEqual( + expect(transformMarkdownContent('## hello world {#hello-world}')).toBe( '## hello world {#hello-world}', ); }); it('respects existing heading', () => { - expect(transformMarkdownContent('## New heading {#old-heading}')).toEqual( + expect(transformMarkdownContent('## New heading {#old-heading}')).toBe( '## New heading {#old-heading}', ); }); @@ -51,7 +51,7 @@ describe('transformMarkdownContent', () => { transformMarkdownContent('## New heading {#old-heading}', { overwrite: true, }), - ).toEqual('## New heading {#new-heading}'); + ).toBe('## New heading {#new-heading}'); }); it('maintains casing when asked to', () => { @@ -59,7 +59,7 @@ describe('transformMarkdownContent', () => { transformMarkdownContent('## getDataFromAPI()', { maintainCase: true, }), - ).toEqual('## getDataFromAPI() {#getDataFromAPI}'); + ).toBe('## getDataFromAPI() {#getDataFromAPI}'); }); it('transform the headings', () => { diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts index 41a68aaebf01..7a5b3db9b6b7 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts @@ -118,15 +118,15 @@ describe('getThemeComponents', () => { themePath, swizzleConfig, }); - expect( - themeComponents.getDescription(Components.ComponentInFolder), - ).toEqual('ComponentInFolder description'); + expect(themeComponents.getDescription(Components.ComponentInFolder)).toBe( + 'ComponentInFolder description', + ); expect( themeComponents.getDescription(Components.ComponentInSubFolder), - ).toEqual('N/A'); - expect( - themeComponents.getDescription(Components.FirstLevelComponent), - ).toEqual('N/A'); + ).toBe('N/A'); + expect(themeComponents.getDescription(Components.FirstLevelComponent)).toBe( + 'N/A', + ); }); it('getActionStatus', async () => { @@ -137,24 +137,24 @@ describe('getThemeComponents', () => { }); expect( themeComponents.getActionStatus(Components.ComponentInFolder, 'wrap'), - ).toEqual('safe'); + ).toBe('safe'); expect( themeComponents.getActionStatus(Components.ComponentInFolder, 'eject'), - ).toEqual('unsafe'); + ).toBe('unsafe'); expect( themeComponents.getActionStatus(Components.ComponentInSubFolder, 'wrap'), - ).toEqual('unsafe'); + ).toBe('unsafe'); expect( themeComponents.getActionStatus(Components.ComponentInSubFolder, 'eject'), - ).toEqual('safe'); + ).toBe('safe'); expect( themeComponents.getActionStatus(Components.FirstLevelComponent, 'wrap'), - ).toEqual('unsafe'); + ).toBe('unsafe'); expect( themeComponents.getActionStatus(Components.FirstLevelComponent, 'eject'), - ).toEqual('unsafe'); + ).toBe('unsafe'); }); it('isSafeAction', async () => { @@ -165,24 +165,24 @@ describe('getThemeComponents', () => { }); expect( themeComponents.isSafeAction(Components.ComponentInFolder, 'wrap'), - ).toEqual(true); + ).toBe(true); expect( themeComponents.isSafeAction(Components.ComponentInFolder, 'eject'), - ).toEqual(false); + ).toBe(false); expect( themeComponents.isSafeAction(Components.ComponentInSubFolder, 'wrap'), - ).toEqual(false); + ).toBe(false); expect( themeComponents.isSafeAction(Components.ComponentInSubFolder, 'eject'), - ).toEqual(true); + ).toBe(true); expect( themeComponents.isSafeAction(Components.FirstLevelComponent, 'wrap'), - ).toEqual(false); + ).toBe(false); expect( themeComponents.isSafeAction(Components.FirstLevelComponent, 'eject'), - ).toEqual(false); + ).toBe(false); }); it('hasAnySafeAction', async () => { @@ -191,14 +191,14 @@ describe('getThemeComponents', () => { themePath, swizzleConfig, }); - expect( - themeComponents.hasAnySafeAction(Components.ComponentInFolder), - ).toEqual(true); + expect(themeComponents.hasAnySafeAction(Components.ComponentInFolder)).toBe( + true, + ); expect( themeComponents.hasAnySafeAction(Components.ComponentInSubFolder), - ).toEqual(true); + ).toBe(true); expect( themeComponents.hasAnySafeAction(Components.FirstLevelComponent), - ).toEqual(false); + ).toBe(false); }); }); diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index c8b3d6942eee..82f1a8d3dc24 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -287,8 +287,8 @@ describe('config warnings', () => { url: 'https://mysite.com/someSubpath', }); expect(warning).toBeDefined(); - expect(warning?.details.length).toEqual(1); - expect(warning?.details[0].message).toMatchInlineSnapshot( + expect(warning.details).toHaveLength(1); + expect(warning.details[0].message).toMatchInlineSnapshot( `"Docusaurus config validation warning. Field \\"url\\": the url is not supposed to contain a sub-path like '/someSubpath', please use the baseUrl field for sub-paths"`, ); }); diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index cb47daeb4471..6f57ca9eee6c 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -181,7 +181,7 @@ describe('localizePath', () => { }, options: {localizePath: true}, }), - ).toEqual('/baseUrl/fr/'); + ).toBe('/baseUrl/fr/'); }); it('localizes fs path with current locale', () => { @@ -197,7 +197,7 @@ describe('localizePath', () => { }, options: {localizePath: true}, }), - ).toEqual(`${path.sep}baseFsPath${path.sep}fr`); + ).toBe(`${path.sep}baseFsPath${path.sep}fr`); }); it('localizes path for default locale, if requested', () => { @@ -213,7 +213,7 @@ describe('localizePath', () => { }, options: {localizePath: true}, }), - ).toEqual('/baseUrl/en/'); + ).toBe('/baseUrl/en/'); }); it('does not localize path for default locale by default', () => { @@ -229,7 +229,7 @@ describe('localizePath', () => { }, // options: {localizePath: true}, }), - ).toEqual('/baseUrl/'); + ).toBe('/baseUrl/'); }); it('localizes path for non-default locale by default', () => { @@ -245,6 +245,6 @@ describe('localizePath', () => { }, // options: {localizePath: true}, }), - ).toEqual('/baseUrl/'); + ).toBe('/baseUrl/'); }); }); diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap index 22f56e0389c9..178307afa67c 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`initPlugins plugins with bad values throw user-friendly error message 1`] = ` +exports[`initPlugins throws user-friendly error message for plugins with bad values 1`] = ` " => Bad Docusaurus plugin value as path [plugins,0]. Example valid plugin config: { diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index d2b06abbda00..a000f6e471f7 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -29,10 +29,10 @@ describe('initPlugins', () => { return {siteDir, context, plugins}; } - it('plugins gets parsed correctly and loads in correct order', async () => { + it('parses plugins correctly and loads them in correct order', async () => { const {context, plugins} = await loadSite(); expect(context.siteConfig.plugins?.length).toBe(4); - expect(plugins.length).toBe(8); + expect(plugins).toHaveLength(8); expect(plugins[0].name).toBe('preset-plugin1'); expect(plugins[1].name).toBe('preset-plugin2'); @@ -45,7 +45,7 @@ describe('initPlugins', () => { expect(context.siteConfig.themeConfig).toEqual({a: 1}); }); - it('plugins with bad values throw user-friendly error message', async () => { + it('throws user-friendly error message for plugins with bad values', async () => { await expect(() => loadSite({ customConfigFilePath: 'badPlugins.docusaurus.config.js', diff --git a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts index fd9c7818f655..54871689edf8 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts @@ -348,9 +348,7 @@ describe('writePluginTranslations', () => { }); } - await expect(readTranslationFileContent(filePath)).resolves.toEqual( - undefined, - ); + await expect(readTranslationFileContent(filePath)).resolves.toBeUndefined(); await doWritePluginTranslations({ key1: {message: 'key1 message', description: 'key1 desc'}, diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts index 6c21fd1338d8..72dc95d9da12 100644 --- a/packages/docusaurus/src/webpack/__tests__/base.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts @@ -28,7 +28,7 @@ describe('babel transpilation exclude logic', () => { path.join('exports', 'Link.js'), ]; clientFiles.forEach((file) => { - expect(excludeJS(path.join(clientDir, file))).toEqual(false); + expect(excludeJS(path.join(clientDir, file))).toBe(false); }); }); @@ -39,7 +39,7 @@ describe('babel transpilation exclude logic', () => { '/src/theme/SearchBar/index.js', ]; moduleFiles.forEach((file) => { - expect(excludeJS(file)).toEqual(false); + expect(excludeJS(file)).toBe(false); }); }); @@ -50,7 +50,7 @@ describe('babel transpilation exclude logic', () => { '/docusaurus/website/node_modules/@docusaurus/theme-search-algolia/theme/SearchBar.js', ]; moduleFiles.forEach((file) => { - expect(excludeJS(file)).toEqual(false); + expect(excludeJS(file)).toBe(false); }); }); @@ -63,7 +63,7 @@ describe('babel transpilation exclude logic', () => { 'node_modules/docusaurus-theme-classic/node_modules/react-daypicker/index.js', ]; moduleFiles.forEach((file) => { - expect(excludeJS(file)).toEqual(true); + expect(excludeJS(file)).toBe(true); }); }); }); diff --git a/packages/docusaurus/src/webpack/__tests__/server.test.ts b/packages/docusaurus/src/webpack/__tests__/server.test.ts index a7a9641799aa..fd4254258fb7 100644 --- a/packages/docusaurus/src/webpack/__tests__/server.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/server.test.ts @@ -13,7 +13,7 @@ import loadSetup from '../../server/__tests__/testUtils'; describe('webpack production config', () => { it('simple', async () => { - console.log = jest.fn(); + jest.spyOn(console, 'log').mockImplementation(); const props = await loadSetup('simple'); const config = await createServerConfig({props}); const errors = webpack.validate(config); @@ -21,7 +21,7 @@ describe('webpack production config', () => { }); it('custom', async () => { - console.log = jest.fn(); + jest.spyOn(console, 'log').mockImplementation(); const props = await loadSetup('custom'); const config = await createServerConfig({props}); const errors = webpack.validate(config); diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index a19193934c47..2b29331dbdea 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -268,7 +268,7 @@ describe('extending PostCSS', () => { // @ts-expect-error: relax type const postCssLoader1 = webpackConfig.module?.rules[0].use[2]; - expect(postCssLoader1.loader).toEqual('postcss-loader-1'); + expect(postCssLoader1.loader).toBe('postcss-loader-1'); const pluginNames1 = postCssLoader1.options.postcssOptions.plugins.map( (p: unknown) => p[0], @@ -283,7 +283,7 @@ describe('extending PostCSS', () => { // @ts-expect-error: relax type const postCssLoader2 = webpackConfig.module?.rules[1].use[0]; - expect(postCssLoader2.loader).toEqual('postcss-loader-2'); + expect(postCssLoader2.loader).toBe('postcss-loader-2'); const pluginNames2 = postCssLoader2.options.postcssOptions.plugins.map( (p: unknown) => p[0], diff --git a/packages/lqip-loader/src/__tests__/utils.test.ts b/packages/lqip-loader/src/__tests__/utils.test.ts index 0f32e2d4b989..162f6b728afa 100644 --- a/packages/lqip-loader/src/__tests__/utils.test.ts +++ b/packages/lqip-loader/src/__tests__/utils.test.ts @@ -15,7 +15,7 @@ describe('toBase64', () => { it('returns a properly formatted Base64 image string', () => { const mockedMimeType = 'image/jpeg'; const mockedBase64Data = Buffer.from('hello world'); - expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual( + expect(toBase64(mockedMimeType, mockedBase64Data)).toBe( 'data:image/jpeg;base64,aGVsbG8gd29ybGQ=', ); }); From 76cb012209f0b96f401df19343632f2917545eba Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 12 Mar 2022 15:24:56 +0800 Subject: [PATCH 005/405] chore: spell-check test files (#6903) --- .cspell.json | 3 +- __tests__/validate-package-json.test.ts | 2 +- .../src/__tests__/index.test.ts | 2 + .../remark/headings/__tests__/index.test.ts | 15 +++--- .../__tests__/__fixtures__/asset.md | 2 +- .../{staticjson.json => static-json.json} | 0 .../__snapshots__/index.test.ts.snap | 2 +- .../src/__tests__/frontMatter.test.ts | 1 + .../redirectValidation.test.ts.snap | 2 +- .../src/__tests__/collectRedirects.test.ts | 12 ++--- .../src/__tests__/redirectValidation.test.ts | 2 +- .../pluginOptionSchema.test.ts.snap | 2 +- .../src/__tests__/blogFrontMatter.test.ts | 2 +- .../src/__tests__/blogUtils.test.ts | 18 +++---- .../src/__tests__/pluginOptionSchema.test.ts | 2 +- .../__fixtures__/simple-site/docs/foo/baz.md | 2 +- .../simple-site/wrong-sidebars.json | 2 +- .../__snapshots__/index.test.ts.snap | 2 +- .../src/__tests__/docFrontMatter.test.ts | 2 +- .../src/__tests__/docs.test.ts | 4 +- .../src/__tests__/index.test.ts | 10 ++-- .../src/__tests__/slug.test.ts | 8 ++-- .../src/__tests__/versions.test.ts | 30 ++++++------ .../__snapshots__/generator.test.ts.snap | 6 +-- .../src/sidebars/__tests__/generator.test.ts | 6 +-- .../src/sidebars/__tests__/index.test.ts | 6 +-- .../sidebars/__tests__/normalization.test.ts | 1 + .../src/__tests__/createSitemap.test.ts | 2 +- .../__snapshots__/index.test.ts.snap | 2 +- .../src/__tests__/index.test.ts | 2 +- .../src/__tests__/validateThemeConfig.test.ts | 4 +- .../__snapshots__/codeBlockUtils.test.ts.snap | 2 +- .../utils/__tests__/codeBlockUtils.test.ts | 2 +- .../src/utils/__tests__/docsUtils.test.tsx | 6 +-- .../src/utils/__tests__/regexpUtils.test.ts | 5 +- .../src/utils/__tests__/tagUtils.test.ts | 18 +++---- .../src/__tests__/validateThemeConfig.test.ts | 2 +- .../src/__tests__/index.test.ts | 2 +- .../src/__tests__/dataFileUtils.test.ts | 14 +++--- .../src/__tests__/i18nUtils.test.ts | 2 +- .../src/__tests__/jsUtils.test.ts | 2 +- .../src/__tests__/markdownParser.test.ts | 2 +- .../src/__tests__/pathUtils.test.ts | 2 +- .../src/__tests__/slugger.test.ts | 1 + .../src/__tests__/urlUtils.test.ts | 1 + .../docusaurus-utils/src/dataFileUtils.ts | 2 +- .../exports/__tests__/useBaseUrl.test.tsx | 48 +++++++++---------- .../__tests__/writeHeadingIds.test.ts | 1 + .../commands/swizzle/__tests__/testUtils.ts | 2 +- .../custom-site/docusaurus.config.js | 6 +-- .../__tests__/__fixtures__/docs/foo/baz.md | 2 +- .../src/server/__tests__/brokenLinks.test.ts | 1 + .../server/__tests__/configValidation.test.ts | 2 +- .../src/server/__tests__/i18n.test.ts | 24 +++++----- .../html-tags/__tests__/htmlTags.test.ts | 4 +- .../__tests__/translationsExtractor.test.ts | 2 +- .../src/webpack/__tests__/base.test.ts | 2 +- project-words.txt | 25 +++++++++- website/src/data/__tests__/user.test.ts | 1 + 59 files changed, 184 insertions(+), 155 deletions(-) rename packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/static/{staticjson.json => static-json.json} (100%) diff --git a/.cspell.json b/.cspell.json index 92f8bf1dfb6c..ba31d09cfd5d 100644 --- a/.cspell.json +++ b/.cspell.json @@ -21,12 +21,11 @@ ], "ignorePaths": [ "CHANGELOG.md", - "examples", "packages/docusaurus-theme-translations/locales", - "__tests__", "package.json", "yarn.lock", "project-words.txt", + "__snapshots__", "website/src/data/users.tsx", "website/src/data/tweets.tsx", "*.xyz", diff --git a/__tests__/validate-package-json.test.ts b/__tests__/validate-package-json.test.ts index 23b81e4f2786..b4bdd9a8b98c 100644 --- a/__tests__/validate-package-json.test.ts +++ b/__tests__/validate-package-json.test.ts @@ -47,7 +47,7 @@ describe('packages', () => { /* If a package starts with @, if won't be published to public npm registry - without an additional publishConfig.acces: "public" config + without an additional publishConfig.access: "public" config This will make you publish an incomplete list of Docusaurus packages when trying to release with lerna-publish */ diff --git a/packages/docusaurus-logger/src/__tests__/index.test.ts b/packages/docusaurus-logger/src/__tests__/index.test.ts index e564fc2bb11b..ba7ecfbebcbf 100644 --- a/packages/docusaurus-logger/src/__tests__/index.test.ts +++ b/packages/docusaurus-logger/src/__tests__/index.test.ts @@ -10,6 +10,7 @@ import logger from '../index'; describe('formatters', () => { it('path', () => { + // cSpell:ignore mhey expect(logger.path('hey')).toMatchInlineSnapshot(`"hey"`); }); it('id', () => { @@ -39,6 +40,7 @@ describe('interpolate', () => { expect( logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, ).toMatchInlineSnapshot( + // cSpell:ignore mpackages `"The package at packages/docusaurus has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, ); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts index 371080d2737e..2f9683e6e8de 100644 --- a/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/headings/__tests__/index.test.ts @@ -199,7 +199,9 @@ describe('headings remark plugin', () => { const expected = u('root', [ heading('I ♥ unicode', 'i--unicode'), heading('Dash-dash', 'dash-dash'), + // cSpell:ignore endash heading('en–dash', 'endash'), + // cSpell:ignore emdash heading('em–dash', 'emdash'), heading('😄 unicode emoji', '-unicode-emoji'), heading('😄-😄 unicode emoji', '--unicode-emoji'), @@ -214,6 +216,7 @@ describe('headings remark plugin', () => { heading(':ok_hand: Single', 'ok_hand-single'), heading( ':ok_hand::hatched_chick: Two in a row with no spaces', + // cSpell:ignore handhatched 'ok_handhatched_chick-two-in-a-row-with-no-spaces', ), heading( @@ -251,11 +254,11 @@ describe('headings remark plugin', () => { ## Heading Two {#custom-heading-two} -# With *Bold* {#custom-withbold} +# With *Bold* {#custom-with-bold} -# With *Bold* hello{#custom-withbold-hello} +# With *Bold* hello{#custom-with-bold-hello} -# With *Bold* hello2 {#custom-withbold-hello2} +# With *Bold* hello2 {#custom-with-bold-hello2} # Snake-cased ID {#this_is_custom_id} @@ -281,15 +284,15 @@ describe('headings remark plugin', () => { text: 'Heading Two', }, { - id: 'custom-withbold', + id: 'custom-with-bold', text: 'With Bold', }, { - id: 'custom-withbold-hello', + id: 'custom-with-bold-hello', text: 'With Bold hello', }, { - id: 'custom-withbold-hello2', + id: 'custom-with-bold-hello2', text: 'With Bold hello2', }, { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md index 407c853eb14f..a23a16a92832 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/asset.md @@ -40,4 +40,4 @@ [json](./data.json) -[static json](/staticjson.json) +[static json](/static-json.json) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/static/staticjson.json b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/static/static-json.json similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/static/staticjson.json rename to packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/static/static-json.json diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap index 1c27e176dcb7..baa694b15625 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap @@ -52,6 +52,6 @@ exports[`transformAsset plugin transform md links to 1`] = ` /node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json').default}>json -/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticjson.json').default}>static json +/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json').default}>static json " `; diff --git a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts index 35de9e01cbf5..c75d885f34e5 100644 --- a/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/frontMatter.test.ts @@ -13,6 +13,7 @@ describe('shouldQuotifyFrontMatter', () => { expect( shouldQuotifyFrontMatter([ 'title', + // cSpell:ignore sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ "Some title front matter with allowed special chars like sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+-_?'`&#()[]§%€$", ]), ).toBe(false); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap index 62b3059d0e7d..0153b77a23dd 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap @@ -8,4 +8,4 @@ exports[`validateRedirect throw for bad redirects 3`] = `"{\\"from\\":\\"/fromSo exports[`validateRedirect throw for bad redirects 4`] = `"{\\"from\\":null,\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"from\\" must be a string"`; -exports[`validateRedirect throw for bad redirects 5`] = `"{\\"from\\":[\\"heyho\\"],\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"from\\" must be a string"`; +exports[`validateRedirect throw for bad redirects 5`] = `"{\\"from\\":[\\"hey\\"],\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"from\\" must be a string"`; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts index e1f24e5949bc..2b7d12f1aa41 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts @@ -226,7 +226,7 @@ describe('collectRedirects', () => { `${removeTrailingSlash(routePath)}/some/other/path/suffix2`, ], }, - ['/', '/testpath', '/otherPath.html'], + ['/', '/testPath', '/otherPath.html'], ), undefined, ), @@ -241,12 +241,12 @@ describe('collectRedirects', () => { }, { - from: '/testpath/some/path/suffix1', - to: '/testpath', + from: '/testPath/some/path/suffix1', + to: '/testPath', }, { - from: '/testpath/some/other/path/suffix2', - to: '/testpath', + from: '/testPath/some/other/path/suffix2', + to: '/testPath', }, { @@ -272,7 +272,7 @@ describe('collectRedirects', () => { return undefined; }, }, - ['/', '/testpath', '/otherPath.html'], + ['/', '/testPath', '/otherPath.html'], ), undefined, ), diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts index 727fd1184258..2d357985ba04 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/redirectValidation.test.ts @@ -60,7 +60,7 @@ describe('validateRedirect', () => { expect(() => validateRedirect({ - from: ['heyho'] as unknown as string, + from: ['hey'] as unknown as string, to: '/toSomePath?queryString=xyz', }), ).toThrowErrorMatchingSnapshot(); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap index dd55a4cd1dce..c598236fd0eb 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`blog plugin options schema throws Error in case of invalid feedtype 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`; +exports[`blog plugin options schema throws Error in case of invalid feed type 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`; exports[`blog plugin options schema throws Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be greater than or equal to 1]`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts index 7622034b0954..b8d7d9047ff6 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts @@ -15,7 +15,7 @@ function testField(params: { fieldName: keyof BlogPostFrontMatter; validFrontMatters: BlogPostFrontMatter[]; convertibleFrontMatter?: [ - ConvertableFrontMatter: Record, + ConvertibleFrontMatter: Record, ConvertedFrontMatter: BlogPostFrontMatter, ][]; invalidFrontMatters?: [ diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts index 027979ba52b5..c7d638771c08 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts @@ -74,16 +74,16 @@ const transform = async ( describe('truncate', () => { it('truncates texts', () => { expect( - truncate('aaa\n\nbbb\nccc', //), + truncate('aaa\n\nbbb\n ccc', //), ).toBe('aaa\n'); - expect(truncate('\n\nbbb\nccc', //)).toBe( - '\n', - ); + expect( + truncate('\n\nbbb\n ccc', //), + ).toBe('\n'); }); it('leaves texts without markers', () => { - expect(truncate('aaa\nbbb\nccc', //)).toBe( - 'aaa\nbbb\nccc', + expect(truncate('aaa\nbbb\n ccc', //)).toBe( + 'aaa\nbbb\n ccc', ); expect(truncate('', //)).toBe(''); }); @@ -165,12 +165,12 @@ describe('parseBlogFileName', () => { it('parses nested folder tree respecting date convention', () => { expect( parseBlogFileName( - '2021/05/12/announcing-docusaurus-two-beta/subfolder/subfile.md', + '2021/05/12/announcing-docusaurus-two-beta/subfolder/file.md', ), ).toEqual({ date: new Date('2021-05-12Z'), - text: 'announcing-docusaurus-two-beta/subfolder/subfile', - slug: '/2021/05/12/announcing-docusaurus-two-beta/subfolder/subfile', + text: 'announcing-docusaurus-two-beta/subfolder/file', + slug: '/2021/05/12/announcing-docusaurus-two-beta/subfolder/file', }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts index 49fa16a21f78..5aa55c353510 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts @@ -63,7 +63,7 @@ describe('blog plugin options schema', () => { expect(error).toMatchSnapshot(); }); - it('throws Error in case of invalid feedtype', () => { + it('throws Error in case of invalid feed type', () => { const {error} = PluginOptionSchema.validate({ feedOptions: { type: 'none', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md index 95d048670453..3407ccd1b033 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md @@ -70,6 +70,6 @@ Term 2 ~ Definition 2a ~ Definition 2b This is HTML abbreviation example. -It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. +It converts "HTML", but keep intact partial entries like "xxxHTMLxxx" and so on. \*[HTML]: Hyper Text Markup Language diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json index 6f56ce2c0b5a..37dd62535414 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json @@ -1,7 +1,7 @@ { "docs": { "Test": [ - "goku" + "nonExistent" ] } } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 7e1365f46d8a..11e6478de794 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -19,7 +19,7 @@ Object { exports[`sidebar site with wrong sidebar content 1`] = ` "Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". These sidebar document ids do not exist: -- goku +- nonExistent Available document ids are: - doc with space diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts index 727861d7d690..5f8aa9d787e7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts @@ -13,7 +13,7 @@ function testField(params: { prefix: string; validFrontMatters: DocFrontMatter[]; convertibleFrontMatter?: [ - ConvertableFrontMatter: Record, + ConvertibleFrontMatter: Record, ConvertedFrontMatter: DocFrontMatter, ][]; invalidFrontMatters?: [ diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 1fcffb05e720..eed15f05763f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -502,14 +502,14 @@ describe('simple site', () => { const docs = await readVersionDocs(versionsMetadata[0], options); docs.push( createFakeDocFile({ - source: 'hehe', + source: 'bad', frontMatter: {pagination_prev: 'nonexistent'}, }), ); await expect( defaultTestUtils.generateNavigation(docs), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Error when loading hehe in .: the pagination_prev front matter points to a non-existent ID nonexistent."`, + `"Error when loading bad in .: the pagination_prev front matter points to a non-existent ID nonexistent."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index b2e1ed440e07..4d62b47700ce 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -201,15 +201,11 @@ describe('empty/no docs website', () => { pluginContentDocs( context, normalizePluginOptions(OptionsSchema, { - path: `path/doesnt/exist`, + path: `path/does/not/exist`, }), ), - ).rejects.toThrowError( - `The docs folder does not exist for version "current". A docs folder is expected to be found at ${ - process.platform === 'win32' - ? 'path\\doesnt\\exist' - : 'path/doesnt/exist' - }.`, + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"The docs folder does not exist for version \\"current\\". A docs folder is expected to be found at path/does/not/exist."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts index eed2abde2c3f..f9f774b693ae 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts @@ -167,11 +167,11 @@ describe('getSlug', () => { expect( getSlug({ baseID: 'any', - source: '@site/docs/unslashedDir/doc.md', - sourceDirName: 'unslashedDir', + source: '@site/docs/nonSlashedDir/doc.md', + sourceDirName: 'nonSlashedDir', frontMatterSlug: 'abc/def', }), - ).toBe('/unslashedDir/abc/def'); + ).toBe('/nonSlashedDir/abc/def'); expect( getSlug({ baseID: 'any', @@ -207,7 +207,7 @@ describe('getSlug', () => { expect( getSlug({ baseID: 'any', - source: '@site/docs/dir/subdirdoc.md', + source: '@site/docs/dir/subdirDoc.md', sourceDirName: '/dir/subdir', frontMatterSlug: '../../../../../abc/../def', }), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index 1da8d275149b..9a4aacb873ae 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -290,7 +290,7 @@ describe('versioned site, pluginId=default', () => { versionClassName: 'docs-version-1.0.0', }; - const vwithSlugs: VersionMetadata = { + const vWithSlugs: VersionMetadata = { contentPath: path.join( versionedSiteDir, 'versioned_docs/version-withSlugs', @@ -321,12 +321,12 @@ describe('versioned site, pluginId=default', () => { vCurrent, v101, v100, - vwithSlugs, + vWithSlugs, }; } it('readVersionsMetadata versioned site', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -334,11 +334,11 @@ describe('versioned site, pluginId=default', () => { context: defaultContext, }); - expect(versionsMetadata).toEqual([vCurrent, v101, v100, vwithSlugs]); + expect(versionsMetadata).toEqual([vCurrent, v101, v100, vWithSlugs]); }); it('readVersionsMetadata versioned site with includeCurrentVersion=false', async () => { - const {defaultOptions, defaultContext, v101, v100, vwithSlugs} = + const {defaultOptions, defaultContext, v101, v100, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -350,12 +350,12 @@ describe('versioned site, pluginId=default', () => { // vCurrent removed v101, v100, - vwithSlugs, + vWithSlugs, ]); }); it('readVersionsMetadata versioned site with version options', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -404,12 +404,12 @@ describe('versioned site, pluginId=default', () => { versionPath: '/docs', versionBanner: 'unreleased', }, - vwithSlugs, + vWithSlugs, ]); }); it('readVersionsMetadata versioned site with editUrl', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -443,7 +443,7 @@ describe('versioned site, pluginId=default', () => { 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0', }, { - ...vwithSlugs, + ...vWithSlugs, versionEditUrl: 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs', versionEditUrlLocalized: @@ -453,7 +453,7 @@ describe('versioned site, pluginId=default', () => { }); it('readVersionsMetadata versioned site with editUrl and editCurrentVersion=true', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vwithSlugs} = + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ @@ -488,7 +488,7 @@ describe('versioned site, pluginId=default', () => { 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, { - ...vwithSlugs, + ...vWithSlugs, versionEditUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', versionEditUrlLocalized: @@ -498,18 +498,18 @@ describe('versioned site, pluginId=default', () => { }); it('readVersionsMetadata versioned site with onlyIncludeVersions option', async () => { - const {defaultOptions, defaultContext, v101, vwithSlugs} = await loadSite(); + const {defaultOptions, defaultContext, v101, vWithSlugs} = await loadSite(); const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, // Order reversed on purpose: should not have any impact - onlyIncludeVersions: [vwithSlugs.versionName, v101.versionName], + onlyIncludeVersions: [vWithSlugs.versionName, v101.versionName], }, context: defaultContext, }); - expect(versionsMetadata).toEqual([v101, vwithSlugs]); + expect(versionsMetadata).toEqual([v101, vWithSlugs]); }); it('readVersionsMetadata versioned site with disableVersioning', async () => { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap index 3338aa1cd534..91902a834a74 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap @@ -49,9 +49,9 @@ Array [ ], "label": "SubGuides (metadata file label)", "link": Object { - "description": "subguides-description", - "slug": "subguides-generated-index-slug", - "title": "subguides-title", + "description": "subGuides-description", + "slug": "subGuides-generated-index-slug", + "title": "subGuides-title", "type": "generated-index", }, "type": "category", diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts index 3b383756f2fb..a80aee0433c8 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts @@ -131,9 +131,9 @@ describe('DefaultSidebarItemsGenerator', () => { label: 'SubGuides (metadata file label)', link: { type: 'generated-index', - slug: 'subguides-generated-index-slug', - title: 'subguides-title', - description: 'subguides-description', + slug: 'subGuides-generated-index-slug', + title: 'subGuides-title', + description: 'subGuides-description', }, }, }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts index 89fc1696cb3c..b57a044bae38 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts @@ -43,7 +43,7 @@ describe('loadSidebars', () => { expect(result).toMatchSnapshot(); }); - it('sidebars shorthand and longform lead to exact same sidebar', async () => { + it('sidebars shorthand and longhand lead to exact same sidebar', async () => { const sidebarPath1 = path.join(fixtureDir, 'sidebars-category.js'); const sidebarPath2 = path.join( fixtureDir, @@ -81,8 +81,8 @@ describe('loadSidebars', () => { expect(result).toMatchSnapshot(); }); - it('unexisting path', async () => { - await expect(loadSidebars('badpath', params)).resolves.toEqual( + it('nonexistent path', async () => { + await expect(loadSidebars('bad/path', params)).resolves.toEqual( DisabledSidebars, ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts index 3dcf930be0e3..66a27886d0ba 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts @@ -83,6 +83,7 @@ describe('normalization', () => { sidebar: 'item', }), ).toThrowErrorMatchingInlineSnapshot( + // cSpell:ignore msidebar `"Invalid sidebar items collection \`\\"item\\"\` in sidebar sidebar: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); }); diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index 3c3fa1172f98..c041bff79b6b 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -38,7 +38,7 @@ describe('createSitemap', () => { { url: 'https://example.com', } as DocusaurusConfig, - ['/', '/404.html', '/mypage'], + ['/', '/404.html', '/my-page'], { changefreq: EnumChangefreq.DAILY, priority: 0.7, diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap index 82db48b367ad..9b3a2be47cab 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap @@ -24,7 +24,7 @@ import TabItem from '@theme/TabItem'; " `; -exports[`npm2yarn plugin tdoes not re-import tabs components when already imported below 1`] = ` +exports[`npm2yarn plugin does not re-import tabs components when already imported below 1`] = ` " diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts index c33e7452ccdf..c8425b874f61 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts @@ -49,7 +49,7 @@ describe('npm2yarn plugin', () => { expect(result).toMatchSnapshot(); }); - it('tdoes not re-import tabs components when already imported below', async () => { + it('does not re-import tabs components when already imported below', async () => { const result = await processFixture('import-tabs-below'); expect(result).toMatchSnapshot(); diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index 44cb618bd3a3..1b0abbe7bb8e 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -38,7 +38,7 @@ describe('themeConfig', () => { additionalLanguages: ['kotlin', 'java'], }, announcementBar: { - id: 'supportus', + id: 'supports', content: 'pls support', backgroundColor: '#fff', textColor: '#000', @@ -206,7 +206,7 @@ describe('themeConfig', () => { { type: 'joke', position: 'left', - label: 'haha', + label: 'hahaha', }, ], }, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap index cf5493e481f5..40f7d68143b5 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap @@ -3,7 +3,7 @@ exports[`parseLines does not parse content with metastring 1`] = ` Object { "code": "aaaaa -bbbbb", +nnnnn", "highlightLines": Array [ 0, ], diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts index efc84c6de68e..bc4e77b0d1d9 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts @@ -68,7 +68,7 @@ describe('parseLanguage', () => { describe('parseLines', () => { it('does not parse content with metastring', () => { - expect(parseLines('aaaaa\nbbbbb', '{1}', 'js')).toMatchSnapshot(); + expect(parseLines('aaaaa\nnnnnn', '{1}', 'js')).toMatchSnapshot(); expect( parseLines( `// highlight-next-line diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index 04929a76f42b..8c76436c9cc5 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -270,7 +270,7 @@ describe('isActiveSidebarItem', () => { label: 'Label', }; - expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); + expect(isActiveSidebarItem(item, '/nonexistentPath')).toBe(false); expect(isActiveSidebarItem(item, '/itemPath')).toBe(true); @@ -286,7 +286,7 @@ describe('isActiveSidebarItem', () => { href: '/itemPath', }); - expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); + expect(isActiveSidebarItem(item, '/nonexistentPath')).toBe(false); expect(isActiveSidebarItem(item, '/itemPath')).toBe(true); @@ -319,7 +319,7 @@ describe('isActiveSidebarItem', () => { ], }); - expect(isActiveSidebarItem(item, '/unexistingPath')).toBe(false); + expect(isActiveSidebarItem(item, '/nonexistentPath')).toBe(false); expect(isActiveSidebarItem(item, '/category-path')).toBe(true); expect(isActiveSidebarItem(item, '/sub-link-path')).toBe(true); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts index 2101c647e92d..9d65d74a7a6f 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/regexpUtils.test.ts @@ -13,9 +13,10 @@ describe('isRegexpStringMatch', () => { expect(isRegexpStringMatch('bar', undefined)).toBe(false); expect(isRegexpStringMatch('foo', 'bar')).toBe(false); expect(isRegexpStringMatch('foo', 'foo')).toBe(true); + // cSpell:ignore fooooooooooo expect(isRegexpStringMatch('fooooooooooo', 'foo')).toBe(false); - expect(isRegexpStringMatch('foo', 'fooooooo')).toBe(true); - expect(isRegexpStringMatch('f.*o', 'fggo')).toBe(true); + expect(isRegexpStringMatch('foo', 'fooooooooooo')).toBe(true); + expect(isRegexpStringMatch('f.*o', 'fooooooooooo')).toBe(true); expect(isRegexpStringMatch('FOO', 'foo')).toBe(true); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts index 495adad67bba..2de931f7e047 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts @@ -24,7 +24,7 @@ describe('listTagsByLetters', () => { permalink: '/tag2', count: 11, }; - const tagzxy: Tag = { + const tagZxy: Tag = { name: 'zxy', permalink: '/zxy', count: 987, @@ -34,34 +34,34 @@ describe('listTagsByLetters', () => { permalink: '/abc', count: 123, }; - const tagdef: Tag = { + const tagDef: Tag = { name: 'def', permalink: '/def', count: 1, }; - const tagaaa: Tag = { + const tagAaa: Tag = { name: 'aaa', permalink: '/aaa', count: 10, }; const expectedResult: Result = [ - {letter: 'A', tags: [tagaaa, tagAbc]}, - {letter: 'D', tags: [tagdef]}, + {letter: 'A', tags: [tagAaa, tagAbc]}, + {letter: 'D', tags: [tagDef]}, {letter: 'T', tags: [tag1, tag2]}, - {letter: 'Z', tags: [tagzxy]}, + {letter: 'Z', tags: [tagZxy]}, ]; // Input order shouldn't matter, output is always consistently sorted expect( - listTagsByLetters([tag1, tag2, tagzxy, tagAbc, tagdef, tagaaa]), + listTagsByLetters([tag1, tag2, tagZxy, tagAbc, tagDef, tagAaa]), ).toEqual(expectedResult); expect( - listTagsByLetters([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1]), + listTagsByLetters([tagZxy, tagDef, tagAaa, tag2, tagAbc, tag1]), ).toEqual(expectedResult); expect( listTagsByLetters( - _.shuffle([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1]), + _.shuffle([tagZxy, tagDef, tagAaa, tag2, tagAbc, tag1]), ), ).toEqual(expectedResult); }); diff --git a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts index a855ccba3a5f..33fe017f0fd9 100644 --- a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts @@ -31,7 +31,7 @@ describe('validateThemeConfig', () => { }); }); - it('unexist config', () => { + it('nonexistent config', () => { expect(testValidateThemeConfig({})).toEqual({ liveCodeBlock: { ...DEFAULT_CONFIG, diff --git a/packages/docusaurus-theme-translations/src/__tests__/index.test.ts b/packages/docusaurus-theme-translations/src/__tests__/index.test.ts index 5d7bb1199bdb..980fa83d87ee 100644 --- a/packages/docusaurus-theme-translations/src/__tests__/index.test.ts +++ b/packages/docusaurus-theme-translations/src/__tests__/index.test.ts @@ -67,7 +67,7 @@ describe('readDefaultCodeTranslationMessages', () => { ); }); - it('for unexisting locale', async () => { + it('for nonexistent locale', async () => { await expect( readDefaultCodeTranslationMessages({ locale: 'es', diff --git a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts index 689e338f6cff..251a1f6dbe2c 100644 --- a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts @@ -172,7 +172,7 @@ describe('findFolderContainingFile', () => { it('find appropriate folder', async () => { await expect( findFolderContainingFile( - ['/abcdef', '/gehij', __dirname, '/klmn'], + ['/foo', '/baz', __dirname, '/bar'], 'dataFileUtils.test.ts', ), ).resolves.toEqual(__dirname); @@ -180,7 +180,7 @@ describe('findFolderContainingFile', () => { it('return undefined if no folder contain such file', async () => { await expect( - findFolderContainingFile(['/abcdef', '/gehij', '/klmn'], 'index.test.ts'), + findFolderContainingFile(['/foo', '/bar', '/baz'], 'index.test.ts'), ).resolves.toBeUndefined(); }); }); @@ -189,7 +189,7 @@ describe('getFolderContainingFile', () => { it('get appropriate folder', async () => { await expect( getFolderContainingFile( - ['/abcdef', '/gehij', __dirname, '/klmn'], + ['/foo', '/baz', __dirname, '/bar'], 'dataFileUtils.test.ts', ), ).resolves.toEqual(__dirname); @@ -198,14 +198,14 @@ describe('getFolderContainingFile', () => { it('throw if no folder contain such file', async () => { await expect( getFolderContainingFile( - ['/abcdef', '/gehij', '/klmn'], + ['/foo', '/bar', '/baz'], 'dataFileUtils.test.ts', ), ).rejects.toThrowErrorMatchingInlineSnapshot(` "File \\"dataFileUtils.test.ts\\" does not exist in any of these folders: - - /abcdef - - /gehij - - /klmn]" + - /foo + - /bar + - /baz" `); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts index b5321520b6b2..e33207afc6d0 100644 --- a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts @@ -83,7 +83,7 @@ describe('getPluginI18nPath', () => { }).replace(__dirname, ''), ).toMatchInlineSnapshot(`"/i18n/zh-Hans/plugin-content-docs/foo"`); }); - it('gets correct path when no subpaths', () => { + it('gets correct path when no sub-paths', () => { expect( getPluginI18nPath({ siteDir: __dirname, diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index b9646927c01f..1092e85ff716 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -34,7 +34,7 @@ describe('removePrefix', () => { expect(removePrefix('abcdef', '')).toBe('abcdef'); }); it('removes prefix', () => { - expect(removePrefix('abcdef', 'ab')).toBe('cdef'); + expect(removePrefix('prefix', 'pre')).toBe('fix'); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts index 661591f5e567..bc565f7550a9 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts @@ -116,7 +116,7 @@ describe('createExcerpt', () => { export function ItemCol(props) { return }; - Lorem **ipsum** dolor sit \`amet\`[^1], consectetur _adipiscing_ elit. [**Vestibulum**](https://wiktionary.org/wiki/vestibulum) ex urna[^bignote], ~~molestie~~ et sagittis ut, varius ac justo :wink:. + Lorem **ipsum** dolor sit \`amet\`[^1], consectetur _adipiscing_ elit. [**Vestibulum**](https://wiktionary.org/wiki/vestibulum) ex urna[^note], ~~molestie~~ et sagittis ut, varius ac justo :wink:. Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. `), diff --git a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts index 5fddcfb5cfd2..2eebb267eae6 100644 --- a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts @@ -31,7 +31,7 @@ describe('isNameTooLong', () => { true, 'foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-test-1-test-2-787': true, - // Every Hanzi is three bytes + // Every Han zi is three bytes 字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字字: {apfs: false, xfs: true}, }; diff --git a/packages/docusaurus-utils/src/__tests__/slugger.test.ts b/packages/docusaurus-utils/src/__tests__/slugger.test.ts index eff493883ad5..02eec00fd837 100644 --- a/packages/docusaurus-utils/src/__tests__/slugger.test.ts +++ b/packages/docusaurus-utils/src/__tests__/slugger.test.ts @@ -10,6 +10,7 @@ import {createSlugger} from '../slugger'; describe('createSlugger', () => { it('can create unique slugs', () => { const slugger = createSlugger(); + // cSpell:ignore somevalue expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue'); expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue-1'); expect(slugger.slug('Some$/vaLue$!^')).toBe('somevalue-2'); diff --git a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts index 4ac1e542711d..178ff254d2d0 100644 --- a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts @@ -243,6 +243,7 @@ describe('resolvePathname', () => { describe('encodePath', () => { it('works', () => { expect(encodePath('a/foo/')).toBe('a/foo/'); + // cSpell:ignore cfoo expect(encodePath('a//')).toBe('a/%3Cfoo%3E/'); expect(encodePath('a/你好/')).toBe('a/%E4%BD%A0%E5%A5%BD/'); }); diff --git a/packages/docusaurus-utils/src/dataFileUtils.ts b/packages/docusaurus-utils/src/dataFileUtils.ts index 0343db63c855..274cace2426f 100644 --- a/packages/docusaurus-utils/src/dataFileUtils.ts +++ b/packages/docusaurus-utils/src/dataFileUtils.ts @@ -83,7 +83,7 @@ export async function getFolderContainingFile( throw new Error( `File "${relativeFilePath}" does not exist in any of these folders:\n- ${folderPaths.join( '\n- ', - )}]`, + )}`, ); } return maybeFolderPath; diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx index 303e8c264962..228a6cd483ae 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx @@ -34,18 +34,18 @@ describe('useBaseUrl', () => { expect(mockUseBaseUrl('/hello')).toBe('/hello'); expect(mockUseBaseUrl('hello/')).toBe('/hello/'); expect(mockUseBaseUrl('/hello/')).toBe('/hello/'); - expect(mockUseBaseUrl('hello/byebye')).toBe('/hello/byebye'); - expect(mockUseBaseUrl('/hello/byebye')).toBe('/hello/byebye'); - expect(mockUseBaseUrl('hello/byebye/')).toBe('/hello/byebye/'); - expect(mockUseBaseUrl('/hello/byebye/')).toBe('/hello/byebye/'); + expect(mockUseBaseUrl('hello/foo')).toBe('/hello/foo'); + expect(mockUseBaseUrl('/hello/foo')).toBe('/hello/foo'); + expect(mockUseBaseUrl('hello/foo/')).toBe('/hello/foo/'); + expect(mockUseBaseUrl('/hello/foo/')).toBe('/hello/foo/'); expect(mockUseBaseUrl('https://github.com')).toBe('https://github.com'); expect(mockUseBaseUrl('//reactjs.org')).toBe('//reactjs.org'); expect(mockUseBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); expect(mockUseBaseUrl('https://site.com', forcePrepend)).toBe( 'https://site.com', ); - expect(mockUseBaseUrl('/hello/byebye', {absolute: true})).toBe( - 'https://docusaurus.io/hello/byebye', + expect(mockUseBaseUrl('/hello/foo', {absolute: true})).toBe( + 'https://docusaurus.io/hello/foo', ); expect(mockUseBaseUrl('#hello')).toBe('#hello'); }); @@ -63,10 +63,10 @@ describe('useBaseUrl', () => { expect(mockUseBaseUrl('/hello')).toBe('/docusaurus/hello'); expect(mockUseBaseUrl('hello/')).toBe('/docusaurus/hello/'); expect(mockUseBaseUrl('/hello/')).toBe('/docusaurus/hello/'); - expect(mockUseBaseUrl('hello/byebye')).toBe('/docusaurus/hello/byebye'); - expect(mockUseBaseUrl('/hello/byebye')).toBe('/docusaurus/hello/byebye'); - expect(mockUseBaseUrl('hello/byebye/')).toBe('/docusaurus/hello/byebye/'); - expect(mockUseBaseUrl('/hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(mockUseBaseUrl('hello/foo')).toBe('/docusaurus/hello/foo'); + expect(mockUseBaseUrl('/hello/foo')).toBe('/docusaurus/hello/foo'); + expect(mockUseBaseUrl('hello/foo/')).toBe('/docusaurus/hello/foo/'); + expect(mockUseBaseUrl('/hello/foo/')).toBe('/docusaurus/hello/foo/'); expect(mockUseBaseUrl('https://github.com')).toBe('https://github.com'); expect(mockUseBaseUrl('//reactjs.org')).toBe('//reactjs.org'); expect(mockUseBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); @@ -74,8 +74,8 @@ describe('useBaseUrl', () => { expect(mockUseBaseUrl('https://site.com', forcePrepend)).toBe( 'https://site.com', ); - expect(mockUseBaseUrl('/hello/byebye', {absolute: true})).toBe( - 'https://docusaurus.io/docusaurus/hello/byebye', + expect(mockUseBaseUrl('/hello/foo', {absolute: true})).toBe( + 'https://docusaurus.io/docusaurus/hello/foo', ); expect(mockUseBaseUrl('/docusaurus/')).toBe('/docusaurus/'); expect(mockUseBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); @@ -102,18 +102,18 @@ describe('useBaseUrlUtils().withBaseUrl()', () => { expect(withBaseUrl('/hello')).toBe('/hello'); expect(withBaseUrl('hello/')).toBe('/hello/'); expect(withBaseUrl('/hello/')).toBe('/hello/'); - expect(withBaseUrl('hello/byebye')).toBe('/hello/byebye'); - expect(withBaseUrl('/hello/byebye')).toBe('/hello/byebye'); - expect(withBaseUrl('hello/byebye/')).toBe('/hello/byebye/'); - expect(withBaseUrl('/hello/byebye/')).toBe('/hello/byebye/'); + expect(withBaseUrl('hello/foo')).toBe('/hello/foo'); + expect(withBaseUrl('/hello/foo')).toBe('/hello/foo'); + expect(withBaseUrl('hello/foo/')).toBe('/hello/foo/'); + expect(withBaseUrl('/hello/foo/')).toBe('/hello/foo/'); expect(withBaseUrl('https://github.com')).toBe('https://github.com'); expect(withBaseUrl('//reactjs.org')).toBe('//reactjs.org'); expect(withBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); expect(withBaseUrl('https://site.com', forcePrepend)).toBe( 'https://site.com', ); - expect(withBaseUrl('/hello/byebye', {absolute: true})).toBe( - 'https://docusaurus.io/hello/byebye', + expect(withBaseUrl('/hello/foo', {absolute: true})).toBe( + 'https://docusaurus.io/hello/foo', ); expect(withBaseUrl('#hello')).toBe('#hello'); }); @@ -130,18 +130,18 @@ describe('useBaseUrlUtils().withBaseUrl()', () => { expect(withBaseUrl('/hello')).toBe('/docusaurus/hello'); expect(withBaseUrl('hello/')).toBe('/docusaurus/hello/'); expect(withBaseUrl('/hello/')).toBe('/docusaurus/hello/'); - expect(withBaseUrl('hello/byebye')).toBe('/docusaurus/hello/byebye'); - expect(withBaseUrl('/hello/byebye')).toBe('/docusaurus/hello/byebye'); - expect(withBaseUrl('hello/byebye/')).toBe('/docusaurus/hello/byebye/'); - expect(withBaseUrl('/hello/byebye/')).toBe('/docusaurus/hello/byebye/'); + expect(withBaseUrl('hello/foo')).toBe('/docusaurus/hello/foo'); + expect(withBaseUrl('/hello/foo')).toBe('/docusaurus/hello/foo'); + expect(withBaseUrl('hello/foo/')).toBe('/docusaurus/hello/foo/'); + expect(withBaseUrl('/hello/foo/')).toBe('/docusaurus/hello/foo/'); expect(withBaseUrl('https://github.com')).toBe('https://github.com'); expect(withBaseUrl('//reactjs.org')).toBe('//reactjs.org'); expect(withBaseUrl('//reactjs.org', forcePrepend)).toBe('//reactjs.org'); expect(withBaseUrl('https://site.com', forcePrepend)).toBe( 'https://site.com', ); - expect(withBaseUrl('/hello/byebye', {absolute: true})).toBe( - 'https://docusaurus.io/docusaurus/hello/byebye', + expect(withBaseUrl('/hello/foo', {absolute: true})).toBe( + 'https://docusaurus.io/docusaurus/hello/foo', ); expect(withBaseUrl('/docusaurus/')).toBe('/docusaurus/'); expect(withBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); diff --git a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts index 0eedbd583c03..f8b9df882b4c 100644 --- a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts +++ b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts @@ -30,6 +30,7 @@ describe('transformMarkdownContent', () => { it('can slugify complex headings', () => { const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756'; expect(transformMarkdownContent(input)).toBe( + // cSpell:ignore ébastien `${input} {#abc-hello-how-are-you-sébastien_-_---56756}`, ); }); diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/testUtils.ts b/packages/docusaurus/src/commands/swizzle/__tests__/testUtils.ts index 53a4ee3090b6..97e0aba8a774 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/testUtils.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/testUtils.ts @@ -19,5 +19,5 @@ export const Components = { }; export async function createTempSiteDir(): Promise { - return fs.mkdtemp(path.join(os.tmpdir(), 'docusaurus-test-swizzle-sitedir')); + return fs.mkdtemp(path.join(os.tmpdir(), 'docusaurus-test-swizzle-siteDir')); } diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/custom-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/custom-site/docusaurus.config.js index b7774313848d..169e78863a74 100644 --- a/packages/docusaurus/src/server/__tests__/__fixtures__/custom-site/docusaurus.config.js +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/custom-site/docusaurus.config.js @@ -6,11 +6,11 @@ */ module.exports = { - title: 'Sakura', + title: 'Site', tagline: 'This is not an ordinary site', organizationName: 'endiliey', - projectName: 'sakura', - baseUrl: '/sakura/', + projectName: 'site', + baseUrl: '/site/', url: 'https://docusaurus.io', favicon: 'img/docusaurus.ico', plugins: [ diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/docs/foo/baz.md b/packages/docusaurus/src/server/__tests__/__fixtures__/docs/foo/baz.md index bc29b950dc07..534321989fa4 100644 --- a/packages/docusaurus/src/server/__tests__/__fixtures__/docs/foo/baz.md +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/docs/foo/baz.md @@ -61,6 +61,6 @@ Term 2 ~ Definition 2a ~ Definition 2b This is HTML abbreviation example. -It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. +It converts "HTML", but keep intact partial entries like "fooHTMLoo" and so on. \*[HTML]: Hyper Text Markup Language diff --git a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts index ad25d5ffde36..d1e29b619faf 100644 --- a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts +++ b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts @@ -58,6 +58,7 @@ describe('handleBrokenLinks', () => { // bad - non-existent file with spaces in name './some%20other%20non-existent%20doc1', // evil - trying to use ../../ but '/' won't get decoded + // cSpell:ignore Fout './break%2F..%2F..%2Fout2', ], '/docs/goodDoc': [ diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 82f1a8d3dc24..a0cac4dbd9fd 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -86,7 +86,7 @@ describe('normalizeConfig', () => { it('throws error for baseUrl without trailing `/`', () => { expect(() => { normalizeConfig({ - baseUrl: 'noslash', + baseUrl: 'noSlash', }); }).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index 6f57ca9eee6c..27fca3f2a89a 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -28,51 +28,51 @@ function loadI18nTest(i18nConfig: I18nConfig, locale?: string) { } describe('defaultLocaleConfig', () => { - const canComputeLabel = typeof Intl.DisplayNames !== 'undefined'; - it('returns correct labels', () => { expect(getDefaultLocaleConfig('fr')).toEqual({ - label: canComputeLabel ? 'Français' : 'fr', + label: 'Français', direction: 'ltr', htmlLang: 'fr', }); expect(getDefaultLocaleConfig('fr-FR')).toEqual({ - label: canComputeLabel ? 'Français (France)' : 'fr-FR', + label: 'Français (France)', direction: 'ltr', htmlLang: 'fr-FR', }); expect(getDefaultLocaleConfig('en')).toEqual({ - label: canComputeLabel ? 'English' : 'en', + label: 'English', direction: 'ltr', htmlLang: 'en', }); expect(getDefaultLocaleConfig('en-US')).toEqual({ - label: canComputeLabel ? 'American English' : 'en-US', + label: 'American English', direction: 'ltr', htmlLang: 'en-US', }); expect(getDefaultLocaleConfig('zh')).toEqual({ - label: canComputeLabel ? '中文' : 'zh', + label: '中文', direction: 'ltr', htmlLang: 'zh', }); expect(getDefaultLocaleConfig('zh-CN')).toEqual({ - label: canComputeLabel ? '中文(中国)' : 'zh-CN', + label: '中文(中国)', direction: 'ltr', htmlLang: 'zh-CN', }); expect(getDefaultLocaleConfig('en-US')).toEqual({ - label: canComputeLabel ? 'American English' : 'en-US', + label: 'American English', direction: 'ltr', htmlLang: 'en-US', }); expect(getDefaultLocaleConfig('fa')).toEqual({ - label: canComputeLabel ? 'فارسی' : 'fa', + // cSpell:ignore فارسی + label: 'فارسی', direction: 'rtl', htmlLang: 'fa', }); expect(getDefaultLocaleConfig('fa-IR')).toEqual({ - label: canComputeLabel ? 'فارسی (ایران)' : 'fa-IR', + // cSpell:ignore ایران فارسیا + label: 'فارسی (ایران)', direction: 'rtl', htmlLang: 'fa-IR', }); @@ -127,7 +127,7 @@ describe('loadI18n', () => { }); }); - it('loads I18n for multi-locale config with some xcustom locale configs', async () => { + it('loads I18n for multi-locale config with some custom locale configs', async () => { await expect( loadI18nTest( { diff --git a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts index ccf6865980c7..90d547952a50 100644 --- a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts +++ b/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts @@ -108,9 +108,9 @@ describe('htmlTagObjectToString', () => { it('invalid html tag object', () => { expect(() => - htmlTagObjectToString('fooofofoofo'), + htmlTagObjectToString('foo'), ).toThrowErrorMatchingInlineSnapshot( - `"\\"fooofofoofo\\" is not a valid HTML tag object."`, + `"\\"foo\\" is not a valid HTML tag object."`, ); expect(() => diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index 1f899ac34ab9..869175c1799f 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -621,7 +621,7 @@ export default function MyComponent() { ); // This one should not be found! On purpose! - const plugin1File3 = path.join(plugin1Dir, 'unscannedFolder', 'file3.jsx'); + const plugin1File3 = path.join(plugin1Dir, 'ignoredFolder', 'file3.jsx'); await fs.outputFile( plugin1File3, ` diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts index 72dc95d9da12..55482b3c2ce3 100644 --- a/packages/docusaurus/src/webpack/__tests__/base.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts @@ -60,7 +60,7 @@ describe('babel transpilation exclude logic', () => { '/website/node_modules/react-trend/index.js', '/docusaurus/website/node_modules/react-super.js', '/docusaurus/website/node_modules/@docusaurus/core/node_modules/core-js/modules/_descriptors.js', - 'node_modules/docusaurus-theme-classic/node_modules/react-daypicker/index.js', + 'node_modules/docusaurus-theme-classic/node_modules/react-slick/index.js', ]; moduleFiles.forEach((file) => { expect(excludeJS(file)).toBe(true); diff --git a/project-words.txt b/project-words.txt index f3b7bb87e312..9e125c666550 100644 --- a/project-words.txt +++ b/project-words.txt @@ -5,6 +5,7 @@ alexey algoliasearch anonymized anshul +août apfs apos appinstalled @@ -12,6 +13,7 @@ applanga architecting astro atrule +autoconverted autogen autogenerating backport @@ -39,8 +41,8 @@ cheng clément clsx codeql -codespaces codesandbox +codespaces contravariance corejs crawlable @@ -50,10 +52,12 @@ customizability daishi datagit datas +décembre dedup deduplicated déja deps +devspace devto dmitry docgen @@ -65,6 +69,7 @@ docz doesn dogfood dogfooding +dojocat dyte easyops endi @@ -78,6 +83,7 @@ evaluable externalwaiting failfast fbid +février fienny flac formik @@ -91,7 +97,9 @@ globby goss goyal gtag +hahaha héctor +héllô heuristical hideable hola @@ -107,8 +115,10 @@ intelli interpolatable jakepartusch jamstack +janvier javadoc jmarcey +joshcena jscodeshift jssdk kaszubowski @@ -184,6 +194,7 @@ peaceiris philpl photoshop picocolors +picomatch pluggable plushie pnpm @@ -214,6 +225,7 @@ quddus quddús quotify ramón +reactjs rearchitecture recrawl redirections @@ -241,30 +253,38 @@ setaf sida simen slorber +spâce stackblitz stackblitzrc +strikethrough strikethroughs stylelint stylelintrc +subdir sublabel sublicensable sublist -subsubsection subpage subroute subroutes subsetting +subsubcategory +subsubfolder +subsubsection +subsubsubfolder sucipto supabase svgr swizzlable teik templating +thanos toolset toplevel transifex transpiles treeified +treeifies treeify treosh triaging @@ -280,6 +300,7 @@ unprefixed unswizzle unversioned upvotes +urlset userland vannicatte vercel diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index 8d9b4aa35a99..ab8ddf593b8c 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -70,6 +70,7 @@ describe('users data', () => { }), }).unknown(false), ); + // cSpell:ignore opensource if (user.tags.includes('opensource') && user.source === null) { throw new Error( "You can't add the 'opensource' tag to a site that does not have a link to source code. Please add your source code, or remove this tag.", From d85cee576d919741cbf8d6256fe4df18f87cadd7 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 12 Mar 2022 23:15:45 +0800 Subject: [PATCH 006/405] test: improve test coverage; properly test core client APIs (#6905) * test: improve test coverage * fix --- jest.config.mjs | 8 +- .../__tests__/__fixtures__/just-content.md | 2 + .../__snapshots__/index.test.ts.snap | 4 + .../src/remark/utils/index.ts | 3 +- .../src/normalizePluginOptions.ts | 2 +- .../__snapshots__/globalData.test.ts.snap | 43 + .../src/__tests__/globalData.test.ts | 100 ++ .../src/__tests__/slug.test.ts | 21 + .../src/__tests__/versions.test.ts | 1248 +++++++++-------- .../src/docFrontMatter.ts | 2 +- .../src/docs.ts | 26 +- .../src/globalData.ts | 9 +- .../src/plugin-content-docs.d.ts | 6 + .../src/sidebars/__tests__/utils.test.ts | 4 +- .../src/sidebars/utils.ts | 11 +- .../src/slug.ts | 7 +- .../src/translations.ts | 5 +- .../src/versions.ts | 4 +- .../DocsPreferredVersionProvider.tsx | 4 +- .../src/theme/SearchPage/index.tsx | 2 +- .../src/__tests__/markdownParser.test.ts | 2 +- .../__tests__/normalizeLocation.test.ts | 12 +- .../src/client/exports/Interpolate.tsx | 4 +- .../src/client/exports/Translate.tsx | 6 +- .../exports/__tests__/BrowserOnly.test.tsx | 75 +- .../exports/__tests__/Interpolate.test.tsx | 52 +- .../exports/__tests__/Translate.test.tsx | 59 +- .../__snapshots__/Interpolate.test.tsx.snap | 18 +- .../exports/__tests__/browserContext.test.tsx | 30 + .../__tests__/docusaurusContext.test.tsx | 41 + .../exports/__tests__/useGlobalData.test.tsx | 122 ++ .../src/client/normalizeLocation.ts | 8 +- packages/docusaurus/src/server/config.ts | 2 +- packages/docusaurus/src/server/index.ts | 2 +- .../webpack/__tests__/__fixtures__/host.crt | 24 + .../webpack/__tests__/__fixtures__/host.key | 27 + .../__tests__/__fixtures__/invalid.crt | 1 + .../__tests__/__fixtures__/invalid.key | 1 + .../src/webpack/__tests__/server.test.ts | 4 +- .../src/webpack/__tests__/utils.test.ts | 63 + website/src/utils/jsUtils.ts | 5 - 41 files changed, 1358 insertions(+), 711 deletions(-) create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts create mode 100644 packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx create mode 100644 packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx create mode 100644 packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx create mode 100644 packages/docusaurus/src/webpack/__tests__/__fixtures__/host.crt create mode 100644 packages/docusaurus/src/webpack/__tests__/__fixtures__/host.key create mode 100644 packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.crt create mode 100644 packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.key diff --git a/jest.config.mjs b/jest.config.mjs index 4c21dede96f7..2b0342501b6c 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -36,18 +36,18 @@ export default { // Jest can't resolve CSS or asset imports '^.+\\.(css|jpe?g|png|svg)$': '/jest/emptyModule.js', - // TODO we need to allow Jest to resolve core Webpack aliases automatically + // Using src instead of lib, so we always get fresh source '@docusaurus/(browserContext|BrowserOnly|ComponentCreator|constants|docusaurusContext|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)': - '@docusaurus/core/lib/client/exports/$1', + '@docusaurus/core/src/client/exports/$1', // Maybe point to a fixture? '@generated/.*': '/jest/emptyModule.js', // TODO use "projects" + multiple configs if we work on another theme? '@theme/(.*)': '@docusaurus/theme-classic/src/theme/$1', '@site/(.*)': 'website/$1', - // TODO why Jest can't figure node package entry points? + // Using src instead of lib, so we always get fresh source '@docusaurus/plugin-content-docs/client': - '@docusaurus/plugin-content-docs/lib/client/index.js', + '@docusaurus/plugin-content-docs/src/client/index.ts', }, globals: { window: { diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/just-content.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/just-content.md index 982f2df6563a..7f9152f5b851 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/just-content.md +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/just-content.md @@ -13,3 +13,5 @@ Lorem ipsum Some content here ## I ♥ unicode. + +export const c = 1; diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap index bb2f9b07233a..fbd3fcc125c8 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap @@ -114,6 +114,8 @@ Lorem ipsum Some content here ## I ♥ unicode. + +export const c = 1; " `; @@ -241,5 +243,7 @@ Lorem ipsum Some content here ## I ♥ unicode. + +export const c = 1; " `; diff --git a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts index e735eea28e33..b0314d7a2349 100644 --- a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts @@ -31,7 +31,6 @@ export function toValue(node: PhrasingContent | Heading): string { case 'link': return stringifyContent(node); default: + return toString(node); } - - return toString(node); } diff --git a/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts b/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts index f3d2cfb82a55..b838746e1efd 100644 --- a/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts +++ b/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts @@ -31,7 +31,7 @@ const RedirectPluginOptionValidation = Joi.object({ const isString = Joi.string().required().not(null); const UserOptionsSchema = Joi.object({ - id: Joi.string().optional(), // TODO remove once validation migrated to new system + id: Joi.string().optional(), // TODO remove once validation migrated to new system fromExtensions: Joi.array().items(isString), toExtensions: Joi.array().items(isString), redirects: Joi.array().items(RedirectPluginOptionValidation), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap new file mode 100644 index 000000000000..95ed78b3ff31 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`toGlobalDataVersion generates the right docs, sidebars, and metadata 1`] = ` +Object { + "docs": Array [ + Object { + "id": "main", + "path": "/current/main", + "sidebar": "tutorial", + }, + Object { + "id": "doc", + "path": "/current/doc", + "sidebar": "tutorial", + }, + Object { + "id": "/current/generated", + "path": "/current/generated", + "sidebar": "tutorial", + }, + ], + "isLast": true, + "label": "Label", + "mainDocId": "main", + "name": "current", + "path": "/current", + "sidebars": Object { + "another": Object { + "link": Object { + "label": "Generated", + "path": "/current/generated", + }, + }, + "links": Object {}, + "tutorial": Object { + "link": Object { + "label": "main", + "path": "/current/main", + }, + }, + }, +} +`; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts new file mode 100644 index 000000000000..4c1cac6ecdcc --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts @@ -0,0 +1,100 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {toGlobalDataVersion} from '../globalData'; + +describe('toGlobalDataVersion', () => { + it('generates the right docs, sidebars, and metadata', () => { + expect( + toGlobalDataVersion({ + versionName: 'current', + versionLabel: 'Label', + isLast: true, + versionPath: '/current', + mainDocId: 'main', + docs: [ + { + unversionedId: 'main', + permalink: '/current/main', + sidebar: 'tutorial', + }, + { + unversionedId: 'doc', + permalink: '/current/doc', + sidebar: 'tutorial', + }, + ], + sidebars: { + another: [ + { + type: 'category', + label: 'Generated', + link: { + type: 'generated-index', + permalink: '/current/generated', + }, + items: [ + { + type: 'doc', + id: 'doc', + }, + ], + }, + ], + tutorial: [ + { + type: 'doc', + id: 'main', + }, + { + type: 'category', + label: 'Generated', + link: { + type: 'generated-index', + permalink: '/current/generated', + }, + items: [ + { + type: 'doc', + id: 'doc', + }, + ], + }, + ], + links: [ + { + type: 'link', + href: 'foo', + label: 'Foo', + }, + { + type: 'link', + href: 'bar', + label: 'Bar', + }, + ], + }, + categoryGeneratedIndices: [ + { + title: 'Generated', + slug: '/current/generated', + permalink: '/current/generated', + sidebar: 'tutorial', + }, + ], + versionBanner: 'unreleased', + versionBadge: true, + versionClassName: 'current-cls', + tagsPath: '/current/tags', + contentPath: '', + contentPathLocalized: '', + sidebarFilePath: '', + routePriority: 0.5, + }), + ).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts index f9f774b693ae..25ee077dad10 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts @@ -111,6 +111,27 @@ describe('getSlug', () => { ).toBe('/dir with spâce/hey $hello/my dôc'); }); + it('throws for invalid routes', () => { + expect(() => + getSlug({ + baseID: 'my dôc', + source: '@site/docs/dir with spâce/hey $hello/doc.md', + sourceDirName: '/dir with spâce/hey $hello', + frontMatterSlug: '//', + }), + ).toThrowErrorMatchingInlineSnapshot(` + "We couldn't compute a valid slug for document with ID \\"my dôc\\" in \\"/dir with spâce/hey $hello\\" directory. + The slug we computed looks invalid: //. + Maybe your slug front matter is incorrect or there are special characters in the file path? + By using front matter to set a custom slug, you should be able to fix this error: + + --- + slug: /my/customDocPath + --- + " + `); + }); + it('handles current dir', () => { expect( getSlug({baseID: 'doc', source: '@site/docs/doc.md', sourceDirName: '.'}), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index 9a4aacb873ae..9e5f2e483160 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -26,8 +26,8 @@ const DefaultI18N: I18n = { localeConfigs: {}, }; -describe('version paths', () => { - it('getVersionsFilePath', () => { +describe('getVersionsFilePath', () => { + it('works', () => { expect(getVersionsFilePath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versions.json`, ); @@ -35,8 +35,10 @@ describe('version paths', () => { `otherSite${path.sep}dir${path.sep}pluginId_versions.json`, ); }); +}); - it('getVersionedDocsDirPath', () => { +describe('getVersionedDocsDirPath', () => { + it('works', () => { expect(getVersionedDocsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versioned_docs`, ); @@ -44,8 +46,10 @@ describe('version paths', () => { `otherSite${path.sep}dir${path.sep}pluginId_versioned_docs`, ); }); +}); - it('getVersionedSidebarsDirPath', () => { +describe('getVersionedSidebarsDirPath', () => { + it('works', () => { expect(getVersionedSidebarsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe( `someSiteDir${path.sep}versioned_sidebars`, ); @@ -55,692 +59,722 @@ describe('version paths', () => { }); }); -describe('simple site', () => { - async function loadSite() { - const simpleSiteDir = path.resolve( - path.join(__dirname, '__fixtures__', 'simple-site'), - ); - const defaultOptions: PluginOptions = { - id: DEFAULT_PLUGIN_ID, - ...DEFAULT_OPTIONS, - }; - const defaultContext = { - siteDir: simpleSiteDir, - baseUrl: '/', - i18n: DefaultI18N, - }; - - const vCurrent: VersionMetadata = { - contentPath: path.join(simpleSiteDir, 'docs'), - contentPathLocalized: path.join( - simpleSiteDir, - 'i18n/en/docusaurus-plugin-content-docs/current', - ), - isLast: true, - routePriority: -1, - sidebarFilePath: undefined, - tagsPath: '/docs/tags', - versionLabel: 'Next', - versionName: 'current', - versionPath: '/docs', - versionBanner: null, - versionBadge: false, - versionClassName: 'docs-version-current', - }; - return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; - } - - it('readVersionsMetadata simple site', async () => { - const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: defaultOptions, - context: defaultContext, - }); +describe('readVersionsMetadata', () => { + describe('simple site', () => { + async function loadSite() { + const simpleSiteDir = path.resolve( + path.join(__dirname, '__fixtures__', 'simple-site'), + ); + const defaultOptions: PluginOptions = { + id: DEFAULT_PLUGIN_ID, + ...DEFAULT_OPTIONS, + }; + const defaultContext = { + siteDir: simpleSiteDir, + baseUrl: '/', + i18n: DefaultI18N, + }; + + const vCurrent: VersionMetadata = { + contentPath: path.join(simpleSiteDir, 'docs'), + contentPathLocalized: path.join( + simpleSiteDir, + 'i18n/en/docusaurus-plugin-content-docs/current', + ), + isLast: true, + routePriority: -1, + sidebarFilePath: undefined, + tagsPath: '/docs/tags', + versionLabel: 'Next', + versionName: 'current', + versionPath: '/docs', + versionBanner: null, + versionBadge: false, + versionClassName: 'docs-version-current', + }; + return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; + } - expect(versionsMetadata).toEqual([vCurrent]); - }); + it('works', async () => { + const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - it('readVersionsMetadata simple site with base url', async () => { - const {defaultOptions, defaultContext, vCurrent} = await loadSite(); + const versionsMetadata = await readVersionsMetadata({ + options: defaultOptions, + context: defaultContext, + }); - const versionsMetadata = await readVersionsMetadata({ - options: defaultOptions, - context: { - ...defaultContext, - baseUrl: '/myBaseUrl', - }, + expect(versionsMetadata).toEqual([vCurrent]); }); - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - versionPath: '/myBaseUrl/docs', - tagsPath: '/myBaseUrl/docs/tags', - }, - ]); - }); + it('works with base url', async () => { + const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - it('readVersionsMetadata simple site with current version config', async () => { - const {defaultOptions, defaultContext, vCurrent} = await loadSite(); + const versionsMetadata = await readVersionsMetadata({ + options: defaultOptions, + context: { + ...defaultContext, + baseUrl: '/myBaseUrl', + }, + }); - const versionsMetadata = await readVersionsMetadata({ - options: { - ...defaultOptions, - versions: { - current: { - label: 'current-label', - path: 'current-path', - }, + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + versionPath: '/myBaseUrl/docs', + tagsPath: '/myBaseUrl/docs/tags', }, - }, - context: { - ...defaultContext, - baseUrl: '/myBaseUrl', - }, + ]); }); - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - versionPath: '/myBaseUrl/docs/current-path', - versionLabel: 'current-label', - routePriority: undefined, - sidebarFilePath: undefined, - tagsPath: '/myBaseUrl/docs/current-path/tags', - versionEditUrl: undefined, - versionEditUrlLocalized: undefined, - }, - ]); - }); + it('works with current version config', async () => { + const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - it('readVersionsMetadata simple site with unknown lastVersion should throw', async () => { - const {defaultOptions, defaultContext} = await loadSite(); - - await expect( - readVersionsMetadata({ - options: {...defaultOptions, lastVersion: 'unknownVersionName'}, - context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Docs option lastVersion: unknownVersionName is invalid. Available version names are: current"`, - ); - }); - - it('readVersionsMetadata simple site with unknown version configurations should throw', async () => { - const {defaultOptions, defaultContext} = await loadSite(); - - await expect( - readVersionsMetadata({ + const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, versions: { - current: {label: 'current'}, - unknownVersionName1: {label: 'unknownVersionName1'}, - unknownVersionName2: {label: 'unknownVersionName2'}, + current: { + label: 'current-label', + path: 'current-path', + }, }, }, - context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"versions\\": unknown versions (unknownVersionName1,unknownVersionName2) found. Available version names are: current"`, - ); - }); - - it('readVersionsMetadata simple site with disableVersioning while single version should throw', async () => { - const {defaultOptions, defaultContext} = await loadSite(); - - await expect( - readVersionsMetadata({ - options: {...defaultOptions, disableVersioning: true}, - context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Docs: using \\"disableVersioning: true\\" option on a non-versioned site does not make sense."`, - ); - }); - - it('readVersionsMetadata simple site without including current version should throw', async () => { - const {defaultOptions, defaultContext} = await loadSite(); - - await expect( - readVersionsMetadata({ - options: {...defaultOptions, includeCurrentVersion: false}, - context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: false\\"."`, - ); - }); -}); - -describe('versioned site, pluginId=default', () => { - async function loadSite() { - const versionedSiteDir = path.resolve( - path.join(__dirname, '__fixtures__', 'versioned-site'), - ); - const defaultOptions: PluginOptions = { - id: DEFAULT_PLUGIN_ID, - ...DEFAULT_OPTIONS, - sidebarPath: 'sidebars.json', - }; - const defaultContext = { - siteDir: versionedSiteDir, - baseUrl: '/', - i18n: DefaultI18N, - }; - - const vCurrent: VersionMetadata = { - contentPath: path.join(versionedSiteDir, 'docs'), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs/current', - ), - isLast: false, - routePriority: undefined, - sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), - tagsPath: '/docs/next/tags', - versionLabel: 'Next', - versionName: 'current', - versionPath: '/docs/next', - versionBanner: 'unreleased', - versionBadge: true, - versionClassName: 'docs-version-current', - }; - - const v101: VersionMetadata = { - contentPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs/version-1.0.1', - ), - isLast: true, - routePriority: -1, - sidebarFilePath: path.join( - versionedSiteDir, - 'versioned_sidebars/version-1.0.1-sidebars.json', - ), - tagsPath: '/docs/tags', - versionLabel: '1.0.1', - versionName: '1.0.1', - versionPath: '/docs', - versionBanner: null, - versionBadge: true, - versionClassName: 'docs-version-1.0.1', - }; - - const v100: VersionMetadata = { - contentPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs/version-1.0.0', - ), - isLast: false, - routePriority: undefined, - sidebarFilePath: path.join( - versionedSiteDir, - 'versioned_sidebars/version-1.0.0-sidebars.json', - ), - tagsPath: '/docs/1.0.0/tags', - versionLabel: '1.0.0', - versionName: '1.0.0', - versionPath: '/docs/1.0.0', - versionBanner: 'unmaintained', - versionBadge: true, - versionClassName: 'docs-version-1.0.0', - }; - - const vWithSlugs: VersionMetadata = { - contentPath: path.join( - versionedSiteDir, - 'versioned_docs/version-withSlugs', - ), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs/version-withSlugs', - ), - isLast: false, - routePriority: undefined, - sidebarFilePath: path.join( - versionedSiteDir, - 'versioned_sidebars/version-withSlugs-sidebars.json', - ), - tagsPath: '/docs/withSlugs/tags', - versionLabel: 'withSlugs', - versionName: 'withSlugs', - versionPath: '/docs/withSlugs', - versionBanner: 'unmaintained', - versionBadge: true, - versionClassName: 'docs-version-withSlugs', - }; - - return { - versionedSiteDir, - defaultOptions, - defaultContext, - vCurrent, - v101, - v100, - vWithSlugs, - }; - } - - it('readVersionsMetadata versioned site', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = - await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: defaultOptions, - context: defaultContext, + context: { + ...defaultContext, + baseUrl: '/myBaseUrl', + }, + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + versionPath: '/myBaseUrl/docs/current-path', + versionLabel: 'current-label', + routePriority: undefined, + sidebarFilePath: undefined, + tagsPath: '/myBaseUrl/docs/current-path/tags', + versionEditUrl: undefined, + versionEditUrlLocalized: undefined, + }, + ]); }); - expect(versionsMetadata).toEqual([vCurrent, v101, v100, vWithSlugs]); - }); - - it('readVersionsMetadata versioned site with includeCurrentVersion=false', async () => { - const {defaultOptions, defaultContext, v101, v100, vWithSlugs} = - await loadSite(); + it('throws with unknown lastVersion', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: {...defaultOptions, lastVersion: 'unknownVersionName'}, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Docs option lastVersion: unknownVersionName is invalid. Available version names are: current"`, + ); + }); - const versionsMetadata = await readVersionsMetadata({ - options: {...defaultOptions, includeCurrentVersion: false}, - context: defaultContext, + it('throws with unknown version configurations', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + versions: { + current: {label: 'current'}, + unknownVersionName1: {label: 'unknownVersionName1'}, + unknownVersionName2: {label: 'unknownVersionName2'}, + }, + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid docs option \\"versions\\": unknown versions (unknownVersionName1,unknownVersionName2) found. Available version names are: current"`, + ); }); - expect(versionsMetadata).toEqual([ - // vCurrent removed - v101, - v100, - vWithSlugs, - ]); - }); + it('throws with disableVersioning while single version', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: {...defaultOptions, disableVersioning: true}, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Docs: using \\"disableVersioning: true\\" option on a non-versioned site does not make sense."`, + ); + }); - it('readVersionsMetadata versioned site with version options', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = - await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: { - ...defaultOptions, - lastVersion: '1.0.0', - versions: { - current: { - path: 'current-path', - banner: 'unmaintained', - badge: false, - className: 'custom-current-className', - }, - '1.0.0': { - label: '1.0.0-label', - banner: 'unreleased', - }, - }, - }, - context: defaultContext, + it('throws without including current version', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: {...defaultOptions, includeCurrentVersion: false}, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: false\\"."`, + ); }); + }); - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - tagsPath: '/docs/current-path/tags', - versionPath: '/docs/current-path', - versionBanner: 'unmaintained', - versionBadge: false, - versionClassName: 'custom-current-className', - }, - { - ...v101, + describe('versioned site, pluginId=default', () => { + async function loadSite() { + const versionedSiteDir = path.resolve( + path.join(__dirname, '__fixtures__', 'versioned-site'), + ); + const defaultOptions: PluginOptions = { + id: DEFAULT_PLUGIN_ID, + ...DEFAULT_OPTIONS, + sidebarPath: 'sidebars.json', + }; + const defaultContext = { + siteDir: versionedSiteDir, + baseUrl: '/', + i18n: DefaultI18N, + }; + + const vCurrent: VersionMetadata = { + contentPath: path.join(versionedSiteDir, 'docs'), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs/current', + ), isLast: false, routePriority: undefined, - tagsPath: '/docs/1.0.1/tags', - versionPath: '/docs/1.0.1', + sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), + tagsPath: '/docs/next/tags', + versionLabel: 'Next', + versionName: 'current', + versionPath: '/docs/next', versionBanner: 'unreleased', - }, - { - ...v100, + versionBadge: true, + versionClassName: 'docs-version-current', + }; + + const v101: VersionMetadata = { + contentPath: path.join( + versionedSiteDir, + 'versioned_docs/version-1.0.1', + ), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs/version-1.0.1', + ), isLast: true, routePriority: -1, + sidebarFilePath: path.join( + versionedSiteDir, + 'versioned_sidebars/version-1.0.1-sidebars.json', + ), tagsPath: '/docs/tags', - versionLabel: '1.0.0-label', + versionLabel: '1.0.1', + versionName: '1.0.1', versionPath: '/docs', - versionBanner: 'unreleased', - }, - vWithSlugs, - ]); - }); - - it('readVersionsMetadata versioned site with editUrl', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = - await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: { - ...defaultOptions, - editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/', - }, - context: defaultContext, - }); - - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', - }, - { - ...v101, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1', - }, - { - ...v100, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0', - }, - { - ...vWithSlugs, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs', - }, - ]); - }); - - it('readVersionsMetadata versioned site with editUrl and editCurrentVersion=true', async () => { - const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = - await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: { - ...defaultOptions, - editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/', - editCurrentVersion: true, - }, - context: defaultContext, - }); - - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', - }, - { - ...v101, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', - }, - { - ...v100, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', - }, - { - ...vWithSlugs, - versionEditUrl: - 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: - 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', - }, - ]); - }); + versionBanner: null, + versionBadge: true, + versionClassName: 'docs-version-1.0.1', + }; + + const v100: VersionMetadata = { + contentPath: path.join( + versionedSiteDir, + 'versioned_docs/version-1.0.0', + ), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs/version-1.0.0', + ), + isLast: false, + routePriority: undefined, + sidebarFilePath: path.join( + versionedSiteDir, + 'versioned_sidebars/version-1.0.0-sidebars.json', + ), + tagsPath: '/docs/1.0.0/tags', + versionLabel: '1.0.0', + versionName: '1.0.0', + versionPath: '/docs/1.0.0', + versionBanner: 'unmaintained', + versionBadge: true, + versionClassName: 'docs-version-1.0.0', + }; + + const vWithSlugs: VersionMetadata = { + contentPath: path.join( + versionedSiteDir, + 'versioned_docs/version-withSlugs', + ), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs/version-withSlugs', + ), + isLast: false, + routePriority: undefined, + sidebarFilePath: path.join( + versionedSiteDir, + 'versioned_sidebars/version-withSlugs-sidebars.json', + ), + tagsPath: '/docs/withSlugs/tags', + versionLabel: 'withSlugs', + versionName: 'withSlugs', + versionPath: '/docs/withSlugs', + versionBanner: 'unmaintained', + versionBadge: true, + versionClassName: 'docs-version-withSlugs', + }; - it('readVersionsMetadata versioned site with onlyIncludeVersions option', async () => { - const {defaultOptions, defaultContext, v101, vWithSlugs} = await loadSite(); + return { + versionedSiteDir, + defaultOptions, + defaultContext, + vCurrent, + v101, + v100, + vWithSlugs, + }; + } + + it('works', async () => { + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = + await loadSite(); + + const versionsMetadata = await readVersionsMetadata({ + options: defaultOptions, + context: defaultContext, + }); - const versionsMetadata = await readVersionsMetadata({ - options: { - ...defaultOptions, - // Order reversed on purpose: should not have any impact - onlyIncludeVersions: [vWithSlugs.versionName, v101.versionName], - }, - context: defaultContext, + expect(versionsMetadata).toEqual([vCurrent, v101, v100, vWithSlugs]); }); - expect(versionsMetadata).toEqual([v101, vWithSlugs]); - }); + it('works with includeCurrentVersion=false', async () => { + const {defaultOptions, defaultContext, v101, v100, vWithSlugs} = + await loadSite(); - it('readVersionsMetadata versioned site with disableVersioning', async () => { - const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: {...defaultOptions, disableVersioning: true}, - context: defaultContext, + const versionsMetadata = await readVersionsMetadata({ + options: {...defaultOptions, includeCurrentVersion: false}, + context: defaultContext, + }); + + expect(versionsMetadata).toEqual([ + // vCurrent removed + v101, + v100, + vWithSlugs, + ]); }); - expect(versionsMetadata).toEqual([ - { - ...vCurrent, - isLast: true, - routePriority: -1, - tagsPath: '/docs/tags', - versionPath: '/docs', - versionBanner: null, - versionBadge: false, - }, - ]); - }); - - it('readVersionsMetadata versioned site with all versions disabled', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + it('works with version options', async () => { + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = + await loadSite(); - await expect( - readVersionsMetadata({ + const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, - includeCurrentVersion: false, - disableVersioning: true, + lastVersion: '1.0.0', + versions: { + current: { + path: 'current-path', + banner: 'unmaintained', + badge: false, + className: 'custom-current-className', + }, + '1.0.0': { + label: '1.0.0-label', + banner: 'unreleased', + }, + }, }, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, - ); - }); + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + tagsPath: '/docs/current-path/tags', + versionPath: '/docs/current-path', + versionBanner: 'unmaintained', + versionBadge: false, + versionClassName: 'custom-current-className', + }, + { + ...v101, + isLast: false, + routePriority: undefined, + tagsPath: '/docs/1.0.1/tags', + versionPath: '/docs/1.0.1', + versionBanner: 'unreleased', + }, + { + ...v100, + isLast: true, + routePriority: -1, + tagsPath: '/docs/tags', + versionLabel: '1.0.0-label', + versionPath: '/docs', + versionBanner: 'unreleased', + }, + vWithSlugs, + ]); + }); - it('readVersionsMetadata versioned site with empty onlyIncludeVersions', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + it('works with editUrl', async () => { + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = + await loadSite(); - await expect( - readVersionsMetadata({ + const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, - onlyIncludeVersions: [], + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/', }, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"onlyIncludeVersions\\": an empty array is not allowed, at least one version is needed."`, - ); - }); + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/docs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', + }, + { + ...v101, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1', + }, + { + ...v100, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0', + }, + { + ...vWithSlugs, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs', + }, + ]); + }); - it('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + it('works with editUrl and editCurrentVersion=true', async () => { + const {defaultOptions, defaultContext, vCurrent, v101, v100, vWithSlugs} = + await loadSite(); - await expect( - readVersionsMetadata({ + const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, - onlyIncludeVersions: ['unknownVersion1', 'unknownVersion2'], + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/', + editCurrentVersion: true, }, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"onlyIncludeVersions\\": unknown versions (unknownVersion1,unknownVersion2) found. Available version names are: current, 1.0.1, 1.0.0, withSlugs"`, - ); - }); + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/docs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', + }, + { + ...v101, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/docs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', + }, + { + ...v100, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/docs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', + }, + { + ...vWithSlugs, + versionEditUrl: + 'https://github.com/facebook/docusaurus/edit/main/website/docs', + versionEditUrlLocalized: + 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', + }, + ]); + }); - it('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + it('works with onlyIncludeVersions option', async () => { + const {defaultOptions, defaultContext, v101, vWithSlugs} = + await loadSite(); - await expect( - readVersionsMetadata({ + const versionsMetadata = await readVersionsMetadata({ options: { ...defaultOptions, - lastVersion: '1.0.1', - onlyIncludeVersions: ['current', '1.0.0'], + // Order reversed on purpose: should not have any impact + onlyIncludeVersions: [vWithSlugs.versionName, v101.versionName], }, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"lastVersion\\": if you use both the \\"onlyIncludeVersions\\" and \\"lastVersion\\" options, then \\"lastVersion\\" must be present in the provided \\"onlyIncludeVersions\\" array."`, - ); - }); + }); - it('readVersionsMetadata versioned site with invalid versions.json file', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + expect(versionsMetadata).toEqual([v101, vWithSlugs]); + }); - const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => ({ - invalid: 'json', - })); + it('works with disableVersioning', async () => { + const {defaultOptions, defaultContext, vCurrent} = await loadSite(); - await expect( - readVersionsMetadata({ - options: defaultOptions, + const versionsMetadata = await readVersionsMetadata({ + options: {...defaultOptions, disableVersioning: true}, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"The versions file should contain an array of versions! Found content: {\\"invalid\\":\\"json\\"}"`, - ); - mock.mockRestore(); - }); -}); + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + isLast: true, + routePriority: -1, + tagsPath: '/docs/tags', + versionPath: '/docs', + versionBanner: null, + versionBadge: false, + }, + ]); + }); -describe('versioned site, pluginId=community', () => { - async function loadSite() { - const versionedSiteDir = path.resolve( - path.join(__dirname, '__fixtures__', 'versioned-site'), - ); - const defaultOptions: PluginOptions = { - ...DEFAULT_OPTIONS, - id: 'community', - path: 'community', - routeBasePath: 'communityBasePath', - sidebarPath: 'sidebars.json', - }; - const defaultContext = { - siteDir: versionedSiteDir, - baseUrl: '/', - i18n: DefaultI18N, - }; - - const vCurrent: VersionMetadata = { - contentPath: path.join(versionedSiteDir, 'community'), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs-community/current', - ), - isLast: false, - routePriority: undefined, - sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), - tagsPath: '/communityBasePath/next/tags', - versionLabel: 'Next', - versionName: 'current', - versionPath: '/communityBasePath/next', - versionBanner: 'unreleased', - versionBadge: true, - versionClassName: 'docs-version-current', - }; - - const v100: VersionMetadata = { - contentPath: path.join( - versionedSiteDir, - 'community_versioned_docs/version-1.0.0', - ), - contentPathLocalized: path.join( - versionedSiteDir, - 'i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0', - ), - isLast: true, - routePriority: -1, - sidebarFilePath: path.join( - versionedSiteDir, - 'community_versioned_sidebars/version-1.0.0-sidebars.json', - ), - tagsPath: '/communityBasePath/tags', - versionLabel: '1.0.0', - versionName: '1.0.0', - versionPath: '/communityBasePath', - versionBanner: null, - versionBadge: true, - versionClassName: 'docs-version-1.0.0', - }; - - return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100}; - } - - it('readVersionsMetadata versioned site (community)', async () => { - const {defaultOptions, defaultContext, vCurrent, v100} = await loadSite(); - - const versionsMetadata = await readVersionsMetadata({ - options: defaultOptions, - context: defaultContext, + it('throws with all versions disabled', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + includeCurrentVersion: false, + disableVersioning: true, + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, + ); }); - expect(versionsMetadata).toEqual([vCurrent, v100]); - }); + it('throws with empty onlyIncludeVersions', async () => { + const {defaultOptions, defaultContext} = await loadSite(); - it('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', async () => { - const {defaultOptions, defaultContext, v100} = await loadSite(); + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + onlyIncludeVersions: [], + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid docs option \\"onlyIncludeVersions\\": an empty array is not allowed, at least one version is needed."`, + ); + }); - const versionsMetadata = await readVersionsMetadata({ - options: {...defaultOptions, includeCurrentVersion: false}, - context: defaultContext, + it('throws with unknown versions in onlyIncludeVersions', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + onlyIncludeVersions: ['unknownVersion1', 'unknownVersion2'], + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid docs option \\"onlyIncludeVersions\\": unknown versions (unknownVersion1,unknownVersion2) found. Available version names are: current, 1.0.1, 1.0.0, withSlugs"`, + ); }); - expect(versionsMetadata).toEqual([ - // vCurrent removed - {...v100, versionBadge: false}, - ]); - }); + it('throws with lastVersion not in onlyIncludeVersions', async () => { + const {defaultOptions, defaultContext} = await loadSite(); - it('readVersionsMetadata versioned site (community) with disableVersioning', async () => { - const {defaultOptions, defaultContext, vCurrent} = await loadSite(); + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + lastVersion: '1.0.1', + onlyIncludeVersions: ['current', '1.0.0'], + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid docs option \\"lastVersion\\": if you use both the \\"onlyIncludeVersions\\" and \\"lastVersion\\" options, then \\"lastVersion\\" must be present in the provided \\"onlyIncludeVersions\\" array."`, + ); + }); - const versionsMetadata = await readVersionsMetadata({ - options: {...defaultOptions, disableVersioning: true}, - context: defaultContext, + it('throws with invalid versions.json file', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + const jsonMock = jest.spyOn(JSON, 'parse'); + jsonMock.mockImplementationOnce(() => ({ + invalid: 'json', + })); + + await expect( + readVersionsMetadata({ + options: defaultOptions, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"The versions file should contain an array of version names! Found content: {\\"invalid\\":\\"json\\"}"`, + ); + jsonMock.mockImplementationOnce(() => [1.1]); + + await expect( + readVersionsMetadata({ + options: defaultOptions, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Versions should be strings. Found type \\"number\\" for version \\"1.1\\"."`, + ); + jsonMock.mockImplementationOnce(() => [' ']); + + await expect( + readVersionsMetadata({ + options: defaultOptions, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid version \\" \\"."`, + ); + jsonMock.mockRestore(); }); + }); - expect(versionsMetadata).toEqual([ - { - ...vCurrent, + describe('versioned site, pluginId=community', () => { + async function loadSite() { + const versionedSiteDir = path.resolve( + path.join(__dirname, '__fixtures__', 'versioned-site'), + ); + const defaultOptions: PluginOptions = { + ...DEFAULT_OPTIONS, + id: 'community', + path: 'community', + routeBasePath: 'communityBasePath', + sidebarPath: 'sidebars.json', + }; + const defaultContext = { + siteDir: versionedSiteDir, + baseUrl: '/', + i18n: DefaultI18N, + }; + + const vCurrent: VersionMetadata = { + contentPath: path.join(versionedSiteDir, 'community'), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs-community/current', + ), + isLast: false, + routePriority: undefined, + sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), + tagsPath: '/communityBasePath/next/tags', + versionLabel: 'Next', + versionName: 'current', + versionPath: '/communityBasePath/next', + versionBanner: 'unreleased', + versionBadge: true, + versionClassName: 'docs-version-current', + }; + + const v100: VersionMetadata = { + contentPath: path.join( + versionedSiteDir, + 'community_versioned_docs/version-1.0.0', + ), + contentPathLocalized: path.join( + versionedSiteDir, + 'i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0', + ), isLast: true, routePriority: -1, + sidebarFilePath: path.join( + versionedSiteDir, + 'community_versioned_sidebars/version-1.0.0-sidebars.json', + ), tagsPath: '/communityBasePath/tags', + versionLabel: '1.0.0', + versionName: '1.0.0', versionPath: '/communityBasePath', versionBanner: null, - versionBadge: false, - }, - ]); - }); + versionBadge: true, + versionClassName: 'docs-version-1.0.0', + }; - it('readVersionsMetadata versioned site (community) with all versions disabled', async () => { - const {defaultOptions, defaultContext} = await loadSite(); + return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100}; + } - await expect( - readVersionsMetadata({ - options: { - ...defaultOptions, - includeCurrentVersion: false, - disableVersioning: true, - }, + it('works', async () => { + const {defaultOptions, defaultContext, vCurrent, v100} = await loadSite(); + + const versionsMetadata = await readVersionsMetadata({ + options: defaultOptions, context: defaultContext, - }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, - ); + }); + + expect(versionsMetadata).toEqual([vCurrent, v100]); + }); + + it('works with includeCurrentVersion=false', async () => { + const {defaultOptions, defaultContext, v100} = await loadSite(); + + const versionsMetadata = await readVersionsMetadata({ + options: {...defaultOptions, includeCurrentVersion: false}, + context: defaultContext, + }); + + expect(versionsMetadata).toEqual([ + // vCurrent removed + {...v100, versionBadge: false}, + ]); + }); + + it('works with disableVersioning', async () => { + const {defaultOptions, defaultContext, vCurrent} = await loadSite(); + + const versionsMetadata = await readVersionsMetadata({ + options: {...defaultOptions, disableVersioning: true}, + context: defaultContext, + }); + + expect(versionsMetadata).toEqual([ + { + ...vCurrent, + isLast: true, + routePriority: -1, + tagsPath: '/communityBasePath/tags', + versionPath: '/communityBasePath', + versionBanner: null, + versionBadge: false, + }, + ]); + }); + + it('throws with all versions disabled', async () => { + const {defaultOptions, defaultContext} = await loadSite(); + + await expect( + readVersionsMetadata({ + options: { + ...defaultOptions, + includeCurrentVersion: false, + disableVersioning: true, + }, + context: defaultContext, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, + ); + }); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts b/packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts index 72e085b070f9..da4b86ca3723 100644 --- a/packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts +++ b/packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts @@ -25,7 +25,7 @@ const DocFrontMatterSchema = Joi.object({ hide_table_of_contents: Joi.boolean(), keywords: Joi.array().items(Joi.string().required()), image: URISchema, - description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 + description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 slug: Joi.string(), sidebar_label: Joi.string(), sidebar_position: Joi.number(), diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index b58c4c235378..9fcfa8ee324f 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -391,6 +391,10 @@ export const isCategoryIndex: CategoryIndexMatcher = ({ return eligibleDocIndexNames.includes(fileName.toLowerCase()); }; +/** + * `guides/sidebar/autogenerated.md` -> + * `'autogenerated', '.md', ['sidebar', 'guides']` + */ export function toCategoryIndexMatcherParam({ source, sourceDirName, @@ -406,28 +410,6 @@ export function toCategoryIndexMatcherParam({ }; } -/** - * `guides/sidebar/autogenerated.md` -> - * `'autogenerated', '.md', ['sidebar', 'guides']` - */ -export function splitPath(str: string): { - /** - * The list of directories, from lowest level to highest. - * If there's no dir name, directories is ['.'] - */ - directories: string[]; - /** The file name, without extension */ - fileName: string; - /** The extension, with a leading dot */ - extension: string; -} { - return { - fileName: path.parse(str).name, - extension: path.parse(str).ext, - directories: path.dirname(str).split(path.sep).reverse(), - }; -} - // Return both doc ids // TODO legacy retro-compatibility due to old versioned sidebars using // versioned doc ids ("id" should be removed & "versionedId" should be renamed diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index 9939fb7fca90..bc974d527c87 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -6,7 +6,6 @@ */ import _ from 'lodash'; -import {normalizeUrl} from '@docusaurus/utils'; import type {Sidebars} from './sidebars/types'; import {createSidebarsUtils} from './sidebars/utils'; import type { @@ -20,7 +19,7 @@ import type { GlobalDoc, } from '@docusaurus/plugin-content-docs/client'; -export function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { +function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { return { id: doc.unversionedId, path: doc.permalink, @@ -28,7 +27,7 @@ export function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { }; } -export function toGlobalDataGeneratedIndex( +function toGlobalDataGeneratedIndex( doc: CategoryGeneratedIndexMetadata, ): GlobalDoc { return { @@ -38,7 +37,7 @@ export function toGlobalDataGeneratedIndex( }; } -export function toGlobalSidebars( +function toGlobalSidebars( sidebars: Sidebars, version: LoadedVersion, ): Record { @@ -52,7 +51,7 @@ export function toGlobalSidebars( link: { path: firstLink.type === 'generated-index' - ? normalizeUrl([version.versionPath, firstLink.slug]) + ? firstLink.permalink : version.docs.find( (doc) => doc.id === firstLink.id || doc.unversionedId === firstLink.id, diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 95ec7b3635a3..f14be0f462a8 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -18,8 +18,14 @@ declare module '@docusaurus/plugin-content-docs' { }; export type CategoryIndexMatcherParam = { + /** The file name, without extension */ fileName: string; + /** + * The list of directories, from lowest level to highest. + * If there's no dir name, directories is ['.'] + */ directories: string[]; + /** The extension, with a leading dot */ extension: string; }; export type CategoryIndexMatcher = ( diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index c6a740fb84e3..1b75e8e65ee0 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -111,7 +111,7 @@ describe('createSidebarsUtils', () => { link: { type: 'generated-index', slug: '/s4-category-slug', - permalink: '/s4-category-permalink', + permalink: '/s4-category-slug', }, items: [ {type: 'doc', id: 'doc8'}, @@ -291,7 +291,7 @@ describe('createSidebarsUtils', () => { }); expect(getFirstLink('sidebar4')).toEqual({ type: 'generated-index', - slug: '/s4-category-slug', + permalink: '/s4-category-slug', label: 'S4 Category', }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index 20013e52085a..da095918d5cb 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -139,6 +139,11 @@ export type SidebarsUtils = { getCategoryGeneratedIndexNavigation: ( categoryGeneratedIndexPermalink: string, ) => SidebarNavigation; + /** + * This function may return undefined. This is usually a user mistake, because + * it means this sidebar will never be displayed; however, we can still use + * `displayed_sidebar` to make it displayed. Pretty weird but valid use-case + */ getFirstLink: (sidebarId: string) => | { type: 'doc'; @@ -147,7 +152,7 @@ export type SidebarsUtils = { } | { type: 'generated-index'; - slug: string; + permalink: string; label: string; } | undefined; @@ -295,7 +300,7 @@ Available document ids are: } | { type: 'generated-index'; - slug: string; + permalink: string; label: string; } | undefined { @@ -316,7 +321,7 @@ Available document ids are: } else if (item.link?.type === 'generated-index') { return { type: 'generated-index', - slug: item.link.slug, + permalink: item.link.permalink, label: item.label, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/slug.ts b/packages/docusaurus-plugin-content-docs/src/slug.ts index 14c99925dc14..9de48aa13f28 100644 --- a/packages/docusaurus-plugin-content-docs/src/slug.ts +++ b/packages/docusaurus-plugin-content-docs/src/slug.ts @@ -63,12 +63,11 @@ export default function getSlug({ function ensureValidSlug(slug: string): string { if (!isValidPathname(slug)) { throw new Error( - `We couldn't compute a valid slug for document with id "${baseID}" in "${sourceDirName}" directory. + `We couldn't compute a valid slug for document with ID "${baseID}" in "${sourceDirName}" directory. The slug we computed looks invalid: ${slug}. -Maybe your slug front matter is incorrect or you use weird chars in the file path? -By using the slug front matter, you should be able to fix this error, by using the slug of your choice: +Maybe your slug front matter is incorrect or there are special characters in the file path? +By using front matter to set a custom slug, you should be able to fix this error: -Example => --- slug: /my/customDocPath --- diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index 49681b01ea71..c6929f795ebf 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -274,10 +274,7 @@ function translateVersion( translationFiles: Record, ): LoadedVersion { const versionTranslations = - translationFiles[getVersionFileName(version.versionName)]?.content; - if (!versionTranslations) { - return version; - } + translationFiles[getVersionFileName(version.versionName)]!.content; return { ...version, versionLabel: diff --git a/packages/docusaurus-plugin-content-docs/src/versions.ts b/packages/docusaurus-plugin-content-docs/src/versions.ts index 08dbb0a79611..664118498155 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions.ts @@ -74,9 +74,9 @@ function ensureValidVersionString(version: unknown): asserts version is string { function ensureValidVersionArray( versionArray: unknown, ): asserts versionArray is string[] { - if (!(versionArray instanceof Array)) { + if (!Array.isArray(versionArray)) { throw new Error( - `The versions file should contain an array of versions! Found content: ${JSON.stringify( + `The versions file should contain an array of version names! Found content: ${JSON.stringify( versionArray, )}`, ); diff --git a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx index 49c74aa7b09c..e425d86d533f 100644 --- a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx @@ -92,13 +92,13 @@ function useVersionPersistence(): DocsVersionPersistence { return useThemeConfig().docs.versionPersistence; } -// Value that will be accessible through context: [state,api] +// Value that will be accessible through context: [state,api] function useContextValue() { const allDocsData = useAllDocsData(); const versionPersistence = useVersionPersistence(); const pluginIds = useMemo(() => Object.keys(allDocsData), [allDocsData]); - // Initial state is empty, as we can't read browser storage in node/SSR + // Initial state is empty, as we can't read browser storage in node/SSR const [state, setState] = useState(() => getInitialState(pluginIds)); // On mount, we set the state read from browser storage diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx index 61daf2266cc9..a9227bdff42d 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx @@ -218,7 +218,7 @@ export default function SearchPage(): JSX.Element { algoliaHelper.on( 'result', ({results: {query, hits, page, nbHits, nbPages}}) => { - if (query === '' || !(hits instanceof Array)) { + if (query === '' || !Array.isArray(hits)) { searchResultStateDispatcher({type: 'reset'}); return; } diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts index bc565f7550a9..01999c82c768 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts @@ -250,7 +250,7 @@ Lorem Ipsum }); }); - it('parses markdown h1 title at the top followed by h2 title', () => { + it('parses markdown h1 title at the top followed by h2 title', () => { const markdown = dedent` # Markdown Title diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts index df6294b60c15..9517a5b0f15d 100644 --- a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts +++ b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.ts @@ -9,7 +9,15 @@ import {jest} from '@jest/globals'; import normalizeLocation from '../normalizeLocation'; describe('normalizeLocation', () => { - it('rewrite locations with index.html', () => { + it('rewrites locations with index.html', () => { + expect( + normalizeLocation({ + pathname: '/index.html', + }), + ).toEqual({ + pathname: '/', + }); + expect( normalizeLocation({ pathname: '/docs/introduction/index.html', @@ -35,7 +43,7 @@ describe('normalizeLocation', () => { }); }); - it('untouched pathnames', () => { + it('leaves pathnames untouched', () => { const replaceMock = jest.spyOn(String.prototype, 'replace'); expect( diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx index 8b894f7032f7..5b290d605421 100644 --- a/packages/docusaurus/src/client/exports/Interpolate.tsx +++ b/packages/docusaurus/src/client/exports/Interpolate.tsx @@ -89,12 +89,12 @@ export function interpolate( export default function Interpolate({ children, values, -}: InterpolateProps): ReactNode { +}: InterpolateProps): JSX.Element { if (typeof children !== 'string') { console.warn('Illegal children', children); throw new Error( 'The Docusaurus component only accept simple string values', ); } - return interpolate(children, values); + return <>{interpolate(children, values)}; } diff --git a/packages/docusaurus/src/client/exports/Translate.tsx b/packages/docusaurus/src/client/exports/Translate.tsx index 8e9c0f8fccdc..5cfbef7edb5c 100644 --- a/packages/docusaurus/src/client/exports/Translate.tsx +++ b/packages/docusaurus/src/client/exports/Translate.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {ReactNode} from 'react'; +import React from 'react'; import {interpolate, type InterpolateValues} from '@docusaurus/Interpolate'; import type {TranslateParam, TranslateProps} from '@docusaurus/Translate'; @@ -46,7 +46,7 @@ export default function Translate({ children, id, values, -}: TranslateProps): ReactNode { +}: TranslateProps): JSX.Element { if (children && typeof children !== 'string') { console.warn('Illegal children', children); throw new Error( @@ -55,5 +55,5 @@ export default function Translate({ } const localizedMessage: string = getLocalizedMessage({message: children, id}); - return interpolate(localizedMessage, values); + return <>{interpolate(localizedMessage, values)}; } diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index 0de095ad048e..7ab1c09720e5 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -5,46 +5,55 @@ * LICENSE file in the root directory of this source tree. */ -import {jest} from '@jest/globals'; import React from 'react'; import renderer from 'react-test-renderer'; import BrowserOnly from '../BrowserOnly'; +import {Context} from '../browserContext'; -jest.mock('@docusaurus/useIsBrowser', () => () => true); - -describe('BrowserOnly', () => { +describe('', () => { it('rejects react element children', () => { process.env.NODE_ENV = 'development'; - expect(() => { - renderer.create( - - {/* @ts-expect-error test */} - {window.location.href} - , - ); - }).toThrowErrorMatchingInlineSnapshot(` + expect(() => + renderer + .create( + + + {/* @ts-expect-error test */} + {window.location.href} + + , + ) + .toJSON(), + ).toThrowErrorMatchingInlineSnapshot(` "Docusaurus error: The children of must be a \\"render function\\", e.g. {() => {window.location.href}}. Current type: React element" `); }); + it('rejects string children', () => { + process.env.NODE_ENV = 'development'; expect(() => { renderer.create( - // @ts-expect-error test - , + + {/* @ts-expect-error test */} + + , ); }).toThrowErrorMatchingInlineSnapshot(` "Docusaurus error: The children of must be a \\"render function\\", e.g. {() => {window.location.href}}. Current type: string" `); }); + it('accepts valid children', () => { expect( renderer .create( - Loading}> - {() => {window.location.href}} - , + + Loading}> + {() => {window.location.href}} + + , ) .toJSON(), ).toMatchInlineSnapshot(` @@ -53,4 +62,36 @@ describe('BrowserOnly', () => { `); }); + + it('returns fallback when not in browser', () => { + expect( + renderer + .create( + + Loading}> + {() => {window.location.href}} + + , + ) + .toJSON(), + ).toMatchInlineSnapshot(` + + Loading + + `); + }); + + it('gracefully falls back', () => { + expect( + renderer + .create( + + + {() => {window.location.href}} + + , + ) + .toJSON(), + ).toMatchInlineSnapshot(`null`); + }); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx index 7cd315572283..fdf1033103de 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx @@ -6,9 +6,10 @@ */ import React from 'react'; -import {interpolate} from '../Interpolate'; +import renderer from 'react-test-renderer'; +import Interpolate, {interpolate} from '../Interpolate'; -describe('Interpolate', () => { +describe('interpolate', () => { it('without placeholders', () => { const text = 'Hello how are you?'; expect(interpolate(text)).toEqual(text); @@ -86,3 +87,50 @@ describe('Interpolate', () => { expect(interpolate(text, values)).toMatchSnapshot(); }); }); + +describe('', () => { + it('without placeholders', () => { + const text = 'Hello how are you?'; + expect(renderer.create({text}).toJSON()).toEqual( + text, + ); + }); + + it('placeholders with string values', () => { + const text = 'Hello {name} how are you {day}?'; + const values = {name: 'Sébastien', day: 'today'}; + expect( + renderer + .create({text}) + .toJSON(), + ).toMatchInlineSnapshot(`"Hello Sébastien how are you today?"`); + }); + + it('acceptance test', () => { + const text = 'Hello {name} how are you {day}? Another {unprovidedValue}!'; + const values = { + name: 'Sébastien', + day: today, + extraUselessValue1:
    test
    , + extraUselessValue2: 'hi', + }; + expect( + renderer + .create({text}) + .toJSON(), + ).toMatchSnapshot(); + }); + + it('rejects when children is not string', () => { + expect(() => + renderer.create( + + {/* @ts-expect-error: for test */} + aaa + , + ), + ).toThrowErrorMatchingInlineSnapshot( + `"The Docusaurus component only accept simple string values"`, + ); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx index b1e8efb76ac3..28a8f90fe672 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Translate.test.tsx @@ -5,28 +5,75 @@ * LICENSE file in the root directory of this source tree. */ -import {translate} from '../Translate'; +import React from 'react'; +import renderer from 'react-test-renderer'; +import Translate, {translate} from '../Translate'; describe('translate', () => { - it('accept id and use it as fallback', () => { + it('accepts id and uses it as fallback', () => { expect(translate({id: 'some-id'})).toBe('some-id'); }); - it('accept message and use it as fallback', () => { + it('accepts message and uses it as fallback', () => { expect(translate({message: 'some-message'})).toBe('some-message'); }); - it('accept id+message and use message as fallback', () => { + it('accepts id+message and uses message as fallback', () => { expect(translate({id: 'some-id', message: 'some-message'})).toBe( 'some-message', ); }); - it('reject when no id or message', () => { - // TODO tests are not resolving type defs correctly + it('rejects when no id or message', () => { + // TODO tests are not resolving type defs correctly. We need to include test + // files in a tsconfig file // @ts-expect-error: TS should protect when both id/message are missing expect(() => translate({})).toThrowErrorMatchingInlineSnapshot( `"Docusaurus translation declarations must have at least a translation id or a default translation message"`, ); }); }); + +describe('', () => { + it('accepts id and uses it as fallback', () => { + expect(renderer.create().toJSON()).toBe( + 'some-id', + ); + }); + + it('accepts message and uses it as fallback', () => { + expect(renderer.create(some-message).toJSON()).toBe( + 'some-message', + ); + }); + + it('accepts id+message and uses message as fallback', () => { + expect( + renderer + .create(some-message) + .toJSON(), + ).toBe('some-message'); + }); + + it('rejects when no id or message', () => { + expect(() => + // @ts-expect-error: TS should protect when both id/message are missing + renderer.create(), + ).toThrowErrorMatchingInlineSnapshot( + `"Docusaurus translation declarations must have at least a translation id or a default translation message"`, + ); + }); + + it('rejects when children is not a string', () => { + expect(() => + renderer.create( + + {/* @ts-expect-error: for test */} + aaa + , + ), + ).toThrowErrorMatchingInlineSnapshot( + `"The Docusaurus component only accept simple string values"`, + ); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap index a42c4388ab6e..09d0dcadd9b0 100644 --- a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap +++ b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap @@ -1,6 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Interpolate acceptance test 1`] = ` +exports[` acceptance test 1`] = ` +Array [ + "Hello ", + "Sébastien", + " how are you ", + + today + , + "? Another {unprovidedValue}!", +] +`; + +exports[`interpolate acceptance test 1`] = ` Array [ Hello @@ -18,7 +30,7 @@ Array [ ] `; -exports[`Interpolate placeholders with JSX values 1`] = ` +exports[`interpolate placeholders with JSX values 1`] = ` Array [ Hello @@ -38,7 +50,7 @@ Array [ ] `; -exports[`Interpolate placeholders with mixed vales 1`] = ` +exports[`interpolate placeholders with mixed vales 1`] = ` Array [ Hello diff --git a/packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx b/packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx new file mode 100644 index 000000000000..2802f91532f1 --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx @@ -0,0 +1,30 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment jsdom + */ + +// Jest doesn't allow pragma below other comments. https://github.com/facebook/jest/issues/12573 +// eslint-disable-next-line header/header +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks/server'; +import {BrowserContextProvider} from '../browserContext'; +import useIsBrowser from '../useIsBrowser'; + +describe('BrowserContextProvider', () => { + const {result, hydrate} = renderHook(() => useIsBrowser(), { + wrapper: ({children}) => ( + {children} + ), + }); + it('has value false on first render', () => { + expect(result.current).toBe(false); + }); + it('has value true on hydration', () => { + hydrate(); + expect(result.current).toBe(true); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx b/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx new file mode 100644 index 000000000000..062591f3b426 --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @jest-environment jsdom + */ + +// Jest doesn't allow pragma below other comments. https://github.com/facebook/jest/issues/12573 +// eslint-disable-next-line header/header +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks/server'; +import {DocusaurusContextProvider} from '../docusaurusContext'; +import useDocusaurusContext from '../useDocusaurusContext'; + +// This test currently isn't quite useful because the @generated aliases point +// to the empty modules. Maybe we can point that to fixtures in the future. +describe('DocusaurusContextProvider', () => { + const {result, hydrate} = renderHook(() => useDocusaurusContext(), { + wrapper: ({children}) => ( + {children} + ), + }); + const value = result.current; + it('returns right value', () => { + expect(value).toMatchInlineSnapshot(` + Object { + "codeTranslations": Object {}, + "globalData": Object {}, + "i18n": Object {}, + "siteConfig": Object {}, + "siteMetadata": Object {}, + } + `); + }); + it('has reference-equal value on hydration', () => { + hydrate(); + expect(result.current).toBe(value); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx new file mode 100644 index 000000000000..670a7e3bcc8f --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks'; +import useGlobalData, { + useAllPluginInstancesData, + usePluginData, +} from '../useGlobalData'; +import {Context} from '../docusaurusContext'; + +describe('useGlobalData', () => { + it('returns global data from context', () => { + expect( + renderHook(() => useGlobalData(), { + wrapper: ({children}) => ( + // eslint-disable-next-line react/jsx-no-constructed-context-values + + {children} + + ), + }).result.current, + ).toEqual({foo: 'bar'}); + }); + + it('throws when global data not found', () => { + // Can it actually happen? + expect( + () => + renderHook(() => useGlobalData(), { + wrapper: ({children}) => ( + // eslint-disable-next-line react/jsx-no-constructed-context-values + {children} + ), + }).result.current, + ).toThrowErrorMatchingInlineSnapshot(`"Docusaurus global data not found."`); + }); +}); + +describe('useAllPluginInstancesData', () => { + it('returns plugin data namespace', () => { + expect( + renderHook(() => useAllPluginInstancesData('foo'), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toEqual({default: 'default', bar: 'bar'}); + }); + + it('throws when plugin data not found', () => { + expect( + () => + renderHook(() => useAllPluginInstancesData('bar'), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Docusaurus plugin global data not found for \\"bar\\" plugin."`, + ); + }); +}); + +describe('usePluginData', () => { + it('returns plugin instance data', () => { + expect( + renderHook(() => usePluginData('foo', 'bar'), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toBe('bar'); + }); + + it('defaults to default ID', () => { + expect( + renderHook(() => usePluginData('foo'), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toBe('default'); + }); + + it('throws when plugin instance data not found', () => { + expect( + () => + renderHook(() => usePluginData('foo', 'baz'), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Docusaurus plugin global data not found for \\"foo\\" plugin with id \\"baz\\"."`, + ); + }); +}); diff --git a/packages/docusaurus/src/client/normalizeLocation.ts b/packages/docusaurus/src/client/normalizeLocation.ts index 18b408c33b45..6d443c316ec0 100644 --- a/packages/docusaurus/src/client/normalizeLocation.ts +++ b/packages/docusaurus/src/client/normalizeLocation.ts @@ -18,12 +18,8 @@ export default function normalizeLocation(location: T): T { }; } - let pathname = location.pathname || '/'; - pathname = pathname.trim().replace(/\/index\.html$/, ''); - - if (pathname === '') { - pathname = '/'; - } + const pathname = + location.pathname.trim().replace(/\/index\.html$/, '') || '/'; pathnames[location.pathname] = pathname; diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 5f6d0ef01f9c..94e8656acfdc 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -24,7 +24,7 @@ export default async function loadConfig( | (() => Promise>); const loadedConfig = - importedConfig instanceof Function + typeof importedConfig === 'function' ? await importedConfig() : await importedConfig; diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 414125b41663..d603c46c2d56 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -464,7 +464,7 @@ ${Object.entries(registry) return props; } -// We want all @docusaurus/* packages to have the exact same version! +// We want all @docusaurus/* packages to have the exact same version! // See https://github.com/facebook/docusaurus/issues/3371 // See https://github.com/facebook/docusaurus/pull/3386 function checkDocusaurusPackagesVersion(siteMetadata: DocusaurusSiteMetadata) { diff --git a/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.crt b/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.crt new file mode 100644 index 000000000000..81a7dc73bb76 --- /dev/null +++ b/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID8zCCAtugAwIBAgIUK1U7Oje+GjLlzxNryMDUT72qJZ0wDQYJKoZIhvcNAQEL +BQAwgYgxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hhaTERMA8GA1UEBwwI +U2hhbmdoYWkxGDAWBgNVBAoMD0NvbXB1dGVyaXphdGlvbjESMBAGA1UEAwwJSm9z +aC1DZW5hMSUwIwYJKoZIhvcNAQkBFhZzaWRhY2hlbjIwMDNAZ21haWwuY29tMB4X +DTIyMDMxMjE0MzI0N1oXDTIzMDMxMjE0MzI0N1owgYgxCzAJBgNVBAYTAkNOMREw +DwYDVQQIDAhTaGFuZ2hhaTERMA8GA1UEBwwIU2hhbmdoYWkxGDAWBgNVBAoMD0Nv +bXB1dGVyaXphdGlvbjESMBAGA1UEAwwJSm9zaC1DZW5hMSUwIwYJKoZIhvcNAQkB +FhZzaWRhY2hlbjIwMDNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA7Cq2QW6rcZAm6MMo97aqkFi9dkXx97fW6vPEt2bgS9O6E+M/wXBI +q1Dh3ud8sGP+CiEWa+7uIEwX9pRGyQo0Lkr7qZWSbsDh+RmdkiKUCiIUUTBopBjM +jo7XF9KBM609GYoGlKYxv4adPbOMJcK/9VdJPz3NprIA1PHEqInJNnuKMMjBMhNu +1MZ7JwING/LYBOJ/Mve08XKAcyDdWBVPe2TOfcKhEmtBTKhnOuUicuAdVtDkN34Z +e4ZlifLo7wlQU7NNh7YDOYZz3JXB5QotuqtWkUgfpMSCWG90p4P4LExLzS+2sb7O +C/jO0qYcKjaKAKjrA9IIyClF6VP1yFRZywIDAQABo1MwUTAdBgNVHQ4EFgQUNy2X ++cLPh17QdR6raPKeoKLIm2QwHwYDVR0jBBgwFoAUNy2X+cLPh17QdR6raPKeoKLI +m2QwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAzvyP1QxKR8Ik +k7v3dzRl1gKdu6BtRL1zoFXeOjFOCVX9ORxcpCJItuTM4kEbJLhC0uFxn+zQ/Urs +JAc56gic4fCIcxlTNPr4VtAEUQKhfGG7XTRs8Cl2Rm7E7FwNiGjdLuiPI+G+ZZbl +TYmB5ILGzvI8LAOii17s5wFX84PehZ9gYgcgEvVBaU7lWF3WakR53Msf2bHkjk/r +NfaINeBltOwijhzb8pWf0XG2z4olJjg1qTOgr1gNseyTwMAFwFmeXQAoidoZfKya +DD+hY1/IgiUXi2pdmO+sMHtRBG5JdOi2cjSOcTx1xkWyb60PpW4uxKhduQPAiZRO +266P7J962Q== +-----END CERTIFICATE----- diff --git a/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.key b/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.key new file mode 100644 index 000000000000..1b47cc35e4c0 --- /dev/null +++ b/packages/docusaurus/src/webpack/__tests__/__fixtures__/host.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA7Cq2QW6rcZAm6MMo97aqkFi9dkXx97fW6vPEt2bgS9O6E+M/ +wXBIq1Dh3ud8sGP+CiEWa+7uIEwX9pRGyQo0Lkr7qZWSbsDh+RmdkiKUCiIUUTBo +pBjMjo7XF9KBM609GYoGlKYxv4adPbOMJcK/9VdJPz3NprIA1PHEqInJNnuKMMjB +MhNu1MZ7JwING/LYBOJ/Mve08XKAcyDdWBVPe2TOfcKhEmtBTKhnOuUicuAdVtDk +N34Ze4ZlifLo7wlQU7NNh7YDOYZz3JXB5QotuqtWkUgfpMSCWG90p4P4LExLzS+2 +sb7OC/jO0qYcKjaKAKjrA9IIyClF6VP1yFRZywIDAQABAoIBAHiHR+LW/2qC3ki2 +qWba8+udTnxZMCdzzJy2cjQDrf8k/Hd/6B7qFjxQmCXx0GIZdiJnRpEpLKCRFT3D +6Ohba8wgepXO/x/FEs7VsuRM/264e9P/t7ff7C3pWn8O8N+Vz3QETF17ADK2GfPO +eX0gCmXE+V3sRdOITwJerTYys904bo5CQsDQQENpcuYbZU2IYt9dw9XrTexaFwP1 +3ssOXCwpaW4kS95a6WQlwCqNTq49zqf3VGA3QG3JEdPPWhG+jEG2L4RxSosvo4wt +MYFqeXcS5sz7WOH1gtleGL2i6WKYuLl7Bo/CLokn1tgrXjGvNpeBFvZucC+L246f +e7iG+gkCgYEA+CcISFav/uwKNv3Sdp87kVpBAno8cZTiYvB15zAGaXuLyI/OuJNh +lcJBhtZSN94T/mgj+gXDafjmRr4i7Q4Pu+KG95JTk1FfWv/974NxbRNrrp+4PFKb +wxcM1cHuqq88mUPUX+k0eKPqDcuY6vHBPAV4ji1Wl+VXpREDvhKgAEUCgYEA86Kl +xnOf3TWbEaQRJx2mMnRYLyrEEPqEMgHWlzXdWl2E9LJDGGmOEbZLv6uNcx1uWJVP +AaoitmQNTl+rSsJY0TwqooX5zvT8po9MXUt8FvButJyYUOJZFTuLtLxFJqAzFipz +SaiYTrEBC76uqe/87AVm0wCdJN4ajcptyibaus8CgYEAnXSm3L+kjKxZDuufT4VZ +1rDd7ySAldFSlFTfewIOD4BFAc297YAWu1+3FEeJg8l2BkcuDMb7Z5J3Cww6PRBf +C2iBGzXNsfw/9Q3ZotBUeFGKUhMmY6BHFVLa4gdb2RG38cgISZM/qAzZxkcZkHo1 +klAmXpCGEXuEUUiqh0BqJcECgYEAv42Gt0QbUeoetL0BO3blP9AXsWX3Z73/h+3I +EXUpRy42JcmuVRhQuf5RCi7QdMyUAJPL3WwuBKcfixpO6+VnvYKHpuadZSlbJ32N +NeDufH6nG9vvKdD852O80OohmF/mKqxPnn8u2Nf0EY7ndvcYLV2F3aoi42S5Dfg1 +X/YyjSMCgYAg2fEisapxje98KZ4TPvOffJRF5PRG4H6UBQvxaWw9oUjVkGM6t10U +D6uOCYPkb+l3wBFTNAfScr22EnpW33Q5JOAfHBeE1oEoWGdMgp1C1V9ZQTIkjXyj +YE+lrsTFVoyY+dnLcZ4U7syVkzINk10GaAKjGXD0gtrqC+cQy8z1XQ== +-----END RSA PRIVATE KEY----- diff --git a/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.crt b/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.crt new file mode 100644 index 000000000000..bc56c4d89448 --- /dev/null +++ b/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.crt @@ -0,0 +1 @@ +Foo diff --git a/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.key b/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.key new file mode 100644 index 000000000000..bc56c4d89448 --- /dev/null +++ b/packages/docusaurus/src/webpack/__tests__/__fixtures__/invalid.key @@ -0,0 +1 @@ +Foo diff --git a/packages/docusaurus/src/webpack/__tests__/server.test.ts b/packages/docusaurus/src/webpack/__tests__/server.test.ts index fd4254258fb7..b722f46f7dd0 100644 --- a/packages/docusaurus/src/webpack/__tests__/server.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/server.test.ts @@ -13,7 +13,7 @@ import loadSetup from '../../server/__tests__/testUtils'; describe('webpack production config', () => { it('simple', async () => { - jest.spyOn(console, 'log').mockImplementation(); + jest.spyOn(console, 'log').mockImplementation(() => {}); const props = await loadSetup('simple'); const config = await createServerConfig({props}); const errors = webpack.validate(config); @@ -21,7 +21,7 @@ describe('webpack production config', () => { }); it('custom', async () => { - jest.spyOn(console, 'log').mockImplementation(); + jest.spyOn(console, 'log').mockImplementation(() => {}); const props = await loadSetup('custom'); const config = await createServerConfig({props}); const errors = webpack.validate(config); diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index 2b29331dbdea..3b58b57d22e6 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -12,6 +12,7 @@ import { getCustomizableJSLoader, applyConfigureWebpack, applyConfigurePostCss, + getHttpsConfig, } from '../utils'; import type { ConfigureWebpackFn, @@ -297,3 +298,65 @@ describe('extending PostCSS', () => { ]); }); }); + +describe('getHttpsConfig', () => { + const originalEnv = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = {...originalEnv}; + }); + + afterAll(() => { + process.env = originalEnv; + }); + + it('returns true for HTTPS not env', async () => { + await expect(getHttpsConfig()).resolves.toBe(false); + }); + + it('returns true for HTTPS in env', async () => { + process.env.HTTPS = 'true'; + await expect(getHttpsConfig()).resolves.toBe(true); + }); + + it('returns custom certs if they are in env', async () => { + process.env.HTTPS = 'true'; + process.env.SSL_CRT_FILE = path.join(__dirname, '__fixtures__/host.crt'); + process.env.SSL_KEY_FILE = path.join(__dirname, '__fixtures__/host.key'); + await expect(getHttpsConfig()).resolves.toEqual({ + key: expect.any(Buffer), + cert: expect.any(Buffer), + }); + }); + + it("throws if file doesn't exist", async () => { + process.env.HTTPS = 'true'; + process.env.SSL_CRT_FILE = path.join( + __dirname, + '__fixtures__/nonexistent.crt', + ); + process.env.SSL_KEY_FILE = path.join(__dirname, '__fixtures__/host.key'); + await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( + `"You specified SSL_CRT_FILE in your env, but the file \\"/packages/docusaurus/src/webpack/__tests__/__fixtures__/nonexistent.crt\\" can't be found."`, + ); + }); + + it('throws for invalid key', async () => { + process.env.HTTPS = 'true'; + process.env.SSL_CRT_FILE = path.join(__dirname, '__fixtures__/host.crt'); + process.env.SSL_KEY_FILE = path.join(__dirname, '__fixtures__/invalid.key'); + await expect(getHttpsConfig()).rejects.toThrowError( + /The certificate key .*[/\\]__fixtures__[/\\]invalid\.key is invalid/, + ); + }); + + it('throws for invalid cert', async () => { + process.env.HTTPS = 'true'; + process.env.SSL_CRT_FILE = path.join(__dirname, '__fixtures__/invalid.crt'); + process.env.SSL_KEY_FILE = path.join(__dirname, '__fixtures__/host.key'); + await expect(getHttpsConfig()).rejects.toThrowError( + /The certificate .*[/\\]__fixtures__[/\\]invalid\.crt is invalid/, + ); + }); +}); diff --git a/website/src/utils/jsUtils.ts b/website/src/utils/jsUtils.ts index c389b4e397ad..868a32d06167 100644 --- a/website/src/utils/jsUtils.ts +++ b/website/src/utils/jsUtils.ts @@ -5,11 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -// Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_difference -export function difference(...arrays: T[][]): T[] { - return arrays.reduce((a, b) => a.filter((c) => !b.includes(c))); -} - // Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_sortby-and-_orderby export function sortBy( array: T[], From 127183e70e61eb66e861e6892084b87246d33c1d Mon Sep 17 00:00:00 2001 From: Nayan Patel <79650289+PatelN123@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:50:56 +0000 Subject: [PATCH 007/405] docs: update image for digital support services (#6904) * Delete digitalsupportservices.png * add new image * Delete digitalsupportservices.png * Compressed version * Delete digitalsupportservices.png * add image correct res * optimize image Co-authored-by: Joshua Chen --- .../data/showcase/digitalsupportservices.png | Bin 26567 -> 11875 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/website/src/data/showcase/digitalsupportservices.png b/website/src/data/showcase/digitalsupportservices.png index 77e6cb01102f12522b7deec1934923042a2c31ff..1378475a9a34448bbd34b63e53fa1ba92df8868e 100644 GIT binary patch literal 11875 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�k%%>4(tgM!3&I$TV;DO8c%>0@=OqDfR|5pLu? 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 literal 26567 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 From 3a4b9b4c3065452c44bd6c3e0d82c30c598e8020 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 13 Mar 2022 18:32:17 +0800 Subject: [PATCH 008/405] refactor: install eslint-plugin-regexp (#6906) * refactor: install eslint-plugin-regexp * simplify * simplify * fix --- .eslintrc.js | 3 +- jest/snapshotPathNormalizer.js | 2 +- package.json | 1 + .../docusaurus-migrate/src/frontMatter.ts | 4 +- packages/docusaurus-migrate/src/index.ts | 2 +- .../src/__tests__/cli.test.ts | 6 +- .../docusaurus-plugin-content-docs/src/cli.ts | 2 +- .../src/numberPrefix.ts | 46 ++++++-------- .../src/sidebars/__tests__/generator.test.ts | 2 +- .../src/sidebars/__tests__/index.test.ts | 4 +- .../src/utils/codeBlockUtils.ts | 2 +- .../src/validationSchemas.ts | 2 +- .../src/__tests__/jsUtils.test.ts | 8 ++- .../src/__tests__/markdownParser.test.ts | 6 +- .../docusaurus-utils/src/markdownLinks.ts | 2 +- .../docusaurus-utils/src/markdownParser.ts | 61 +++++++++++-------- packages/docusaurus-utils/src/urlUtils.ts | 4 +- .../src/client/exports/Interpolate.tsx | 2 +- packages/docusaurus/src/commands/deploy.ts | 2 +- website/src/plugins/changelog/index.js | 4 +- website/src/remark/configTabs.mjs | 4 +- website/src/utils/colorUtils.ts | 2 +- yarn.lock | 61 +++++++++++++++++++ 23 files changed, 147 insertions(+), 85 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d82bb95342cf..d0be97ad6995 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { 'plugin:jest/recommended', 'airbnb', 'plugin:@typescript-eslint/recommended', + 'plugin:regexp/recommended', 'prettier', ], settings: { @@ -40,7 +41,7 @@ module.exports = { }, }, reportUnusedDisableDirectives: true, - plugins: ['react-hooks', 'header', 'jest', '@typescript-eslint'], + plugins: ['react-hooks', 'header', 'jest', '@typescript-eslint', 'regexp'], rules: { 'array-callback-return': WARNING, camelcase: WARNING, diff --git a/jest/snapshotPathNormalizer.js b/jest/snapshotPathNormalizer.js index 1db7669d01f3..7d3fcd7d2666 100644 --- a/jest/snapshotPathNormalizer.js +++ b/jest/snapshotPathNormalizer.js @@ -146,7 +146,7 @@ function normalizePaths(value) { // Convert win32 backslash's to forward slashes, \ -> /; // ignore some that look like escape sequences. - (val) => val.replace(/\\(?!["])/g, '/'), + (val) => val.replace(/\\(?!")/g, '/'), ]; let result = value; diff --git a/package.json b/package.json index 50530105b82e..a687ac54c40f 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.3", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-regexp": "^1.5.1", "husky": "^7.0.4", "image-size": "^1.0.1", "jest": "^27.5.1", diff --git a/packages/docusaurus-migrate/src/frontMatter.ts b/packages/docusaurus-migrate/src/frontMatter.ts index 4905863cf5c0..2d03fb0e40e5 100644 --- a/packages/docusaurus-migrate/src/frontMatter.ts +++ b/packages/docusaurus-migrate/src/frontMatter.ts @@ -69,7 +69,7 @@ export function shouldQuotifyFrontMatter([key, value]: [ // TODO this is not ideal to have to maintain such a list of allowed chars // maybe we should quotify if gray-matter throws instead? return !String(value).match( - // cSpell:ignore sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ - /^[\w .\-sàáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+_?'`&#()[\]§%€$]+$/, + // cSpell:ignore àáâãäåçèéêëìíîïðòóôõöùúûüýÿ + /^[\w .\-àáâãäåçèéêëìíîïðòóôõöùúûüýÿ!;,=+?'`&#()[\]§%€$]+$/, ); } diff --git a/packages/docusaurus-migrate/src/index.ts b/packages/docusaurus-migrate/src/index.ts index 6d527e44db31..30c20e826994 100644 --- a/packages/docusaurus-migrate/src/index.ts +++ b/packages/docusaurus-migrate/src/index.ts @@ -451,7 +451,7 @@ async function handleVersioning(context: MigrationContext) { path.join(newDir, 'versions.json'), ); const versions = loadedVersions.reverse(); - const versionRegex = new RegExp(`version-(${versions.join('|')})-`, 'mgi'); + const versionRegex = new RegExp(`version-(${versions.join('|')})-`, 'gim'); await migrateVersionedSidebar(context, versions, versionRegex); await fs.mkdirp(path.join(newDir, 'versioned_docs')); await migrateVersionedDocs(context, versions, versionRegex); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 21d6faa7c0fe..8ca46aeb8195 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -231,7 +231,7 @@ describe('docsVersion', () => { expect(versions).toEqual(['1.0.0']); expect(consoleMock).toHaveBeenCalledWith( expect.stringMatching( - /.*\[SUCCESS\].* .*\[docs\].*: version .*1\.0\.0.* created!.*/, + /.*\[SUCCESS\].*\[docs\].*: version .*1\.0\.0.* created!.*/, ), ); @@ -286,7 +286,7 @@ describe('docsVersion', () => { expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']); expect(consoleMock).toHaveBeenCalledWith( expect.stringMatching( - /.*\[SUCCESS\].* .*\[docs\].*: version .*2\.0\.0.* created!.*/, + /.*\[SUCCESS\].*\[docs\].*: version .*2\.0\.0.* created!.*/, ), ); @@ -339,7 +339,7 @@ describe('docsVersion', () => { expect(versions).toEqual(['2.0.0', '1.0.0']); expect(consoleMock).toHaveBeenCalledWith( expect.stringMatching( - /.*\[SUCCESS\].* .*\[community\].*: version .*2.0.0.* created!.*/, + /.*\[SUCCESS\].*\[community\].*: version .*2.0.0.* created!.*/, ), ); diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index ecb5ab0e596e..2aaceff79b2d 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -88,7 +88,7 @@ export async function cliDocsVersionCommand( // Since we are going to create `version-${version}` folder, we need to make // sure it's a valid pathname. // eslint-disable-next-line no-control-regex - if (/[<>:"|?*\x00-\x1F]/g.test(version)) { + if (/[<>:"|?*\x00-\x1F]/.test(version)) { throw new Error( `${pluginIdLogPrefix}: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0.`, ); diff --git a/packages/docusaurus-plugin-content-docs/src/numberPrefix.ts b/packages/docusaurus-plugin-content-docs/src/numberPrefix.ts index b91fc6d35b7d..a838d7667d7b 100644 --- a/packages/docusaurus-plugin-content-docs/src/numberPrefix.ts +++ b/packages/docusaurus-plugin-content-docs/src/numberPrefix.ts @@ -8,43 +8,33 @@ import type {NumberPrefixParser} from '@docusaurus/plugin-content-docs'; // Best-effort to avoid parsing some patterns as number prefix -const IgnoredPrefixPatterns = (() => { - // ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640 - const DateLikePrefixRegex = - /^(?:\d{2}|\d{4})[-_.]\d{2}(?:[-_.](?:\d{2}|\d{4}))?.*$/; - - // ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653 - // note: we could try to parse float numbers in filenames but that is - // probably not worth it as a version such as "8.0" can be interpreted as both - // a version and a float. User can configure her own NumberPrefixParser if - // she wants 8.0 to be interpreted as a float - const VersionLikePrefixRegex = /^\d+[-_.]\d+.*$/; - - return new RegExp( - `${DateLikePrefixRegex.source}|${VersionLikePrefixRegex.source}`, - ); -})(); - -const NumberPrefixRegex = - /^(?\d+)(?\s*[-_.]+\s*)(?.*)$/; +// ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640 +// ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653 +// Both of them would look like 7.0-foo or 2021-11-foo +// note: we could try to parse float numbers in filenames, but that is probably +// not worth it, as a version such as "8.0" can be interpreted as either a +// version or a float. User can configure her own NumberPrefixParser if she +// wants 8.0 to be interpreted as a float +const ignoredPrefixPattern = /^\d+[-_.]\d+/; + +const numberPrefixPattern = + /^(?\d+)\s*[-_.]+\s*(?[^-_.\s].*)$/; // 0-myDoc => {filename: myDoc, numberPrefix: 0} // 003 - myDoc => {filename: myDoc, numberPrefix: 3} export const DefaultNumberPrefixParser: NumberPrefixParser = ( filename: string, ) => { - if (IgnoredPrefixPatterns.exec(filename)) { + if (ignoredPrefixPattern.test(filename)) { + return {filename, numberPrefix: undefined}; + } + const match = numberPrefixPattern.exec(filename); + if (!match) { return {filename, numberPrefix: undefined}; } - const match = NumberPrefixRegex.exec(filename); - const cleanFileName = match?.groups?.suffix ?? filename; - const numberPrefixString = match?.groups?.numberPrefix; - const numberPrefix = numberPrefixString - ? parseInt(numberPrefixString, 10) - : undefined; return { - filename: cleanFileName, - numberPrefix, + filename: match.groups!.suffix!, + numberPrefix: parseInt(match.groups!.numberPrefix!, 10), }; }; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts index a80aee0433c8..501774ef600e 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts @@ -44,7 +44,7 @@ describe('DefaultSidebarItemsGenerator', () => { expect(sidebarSlice).toEqual([]); expect(consoleWarn).toHaveBeenCalledWith( expect.stringMatching( - /.*\[WARNING\].* No docs found in .*\..*: can't auto-generate a sidebar\..*/, + /.*\[WARNING\].* No docs found in [^.]*\..*: can't auto-generate a sidebar\..*/, ), ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts index b57a044bae38..ec19a5c4fb69 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts @@ -134,12 +134,12 @@ describe('loadSidebars', () => { ).rejects.toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" is not allowed"`); expect(consoleWarnMock).toBeCalledWith( expect.stringMatching( - /.*\[WARNING].* There are more than one category metadata files for .*foo.*: foo\/_category_.json, foo\/_category_.yml. The behavior is undetermined./, + /.*\[WARNING\].* There are more than one category metadata files for .*foo.*: foo\/_category_.json, foo\/_category_.yml. The behavior is undetermined./, ), ); expect(consoleErrorMock).toBeCalledWith( expect.stringMatching( - /.*\[ERROR].* The docs sidebar category metadata file .*foo\/_category_.json.* looks invalid!/, + /.*\[ERROR\].* The docs sidebar category metadata file .*foo\/_category_.json.* looks invalid!/, ), ); }); diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index 1734ae5beba3..3f4b2d7a2e93 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -8,7 +8,7 @@ import rangeParser from 'parse-numeric-range'; const codeBlockTitleRegex = /title=(?["'])(?.*?)\1/; -const highlightLinesRangeRegex = /{(?<range>[\d,-]+)}/; +const highlightLinesRangeRegex = /\{(?<range>[\d,-]+)\}/; const commentTypes = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const; type CommentType = typeof commentTypes[number]; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index d89f65da8085..d7b23b7cc895 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -11,7 +11,7 @@ import type {Tag} from '@docusaurus/utils'; import {JoiFrontMatter} from './JoiFrontMatter'; export const PluginIdSchema = Joi.string() - .regex(/^[a-zA-Z0-9_-]+$/) + .regex(/^[\w-]+$/) .message( 'Illegal plugin ID value "{#value}": it should only contain alphanumerics, underscores, and dashes.', ) diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index 1092e85ff716..6e7e4c99e349 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -169,14 +169,16 @@ describe('reportMessage', () => { `"Unexpected \\"reportingSeverity\\" value: foo."`, ); expect(consoleLog).toBeCalledTimes(1); - expect(consoleLog).toBeCalledWith(expect.stringMatching(/.*\[INFO].* hey/)); + expect(consoleLog).toBeCalledWith( + expect.stringMatching(/.*\[INFO\].* hey/), + ); expect(consoleWarn).toBeCalledTimes(1); expect(consoleWarn).toBeCalledWith( - expect.stringMatching(/.*\[WARNING].* hey/), + expect.stringMatching(/.*\[WARNING\].* hey/), ); expect(consoleError).toBeCalledTimes(1); expect(consoleError).toBeCalledWith( - expect.stringMatching(/.*\[ERROR].* hey/), + expect.stringMatching(/.*\[ERROR\].* hey/), ); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts index 01999c82c768..a3de77298715 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts @@ -404,7 +404,7 @@ Lorem Ipsum expect( parseMarkdownContentTitle(markdown, {removeContentTitle: true}), ).toEqual({ - content: markdown.trim().replace('# Markdown Title', ''), + content: markdown.trim().replace('# Markdown Title\n', ''), contentTitle: 'Markdown Title', }); }); @@ -444,7 +444,7 @@ Lorem Ipsum expect( parseMarkdownContentTitle(markdown, {removeContentTitle: true}), ).toEqual({ - content: markdown.replace('Markdown Title\n==============\n\n', ''), + content: markdown.replace('Markdown Title\n==============\n', ''), contentTitle: 'Markdown Title', }); }); @@ -547,7 +547,7 @@ Lorem Ipsum expect( parseMarkdownContentTitle(markdown, {removeContentTitle: true}), ).toEqual({ - content: markdown.replace('# Markdown Title', ''), + content: markdown.replace('# Markdown Title\n', ''), contentTitle: 'Markdown Title', }); }); diff --git a/packages/docusaurus-utils/src/markdownLinks.ts b/packages/docusaurus-utils/src/markdownLinks.ts index e9eed1a7e66f..afbd7170cebc 100644 --- a/packages/docusaurus-utils/src/markdownLinks.ts +++ b/packages/docusaurus-utils/src/markdownLinks.ts @@ -68,7 +68,7 @@ export function replaceMarkdownLinks<T extends ContentPaths>({ // ink // [doc1]: doc1.md -> we replace this doc1.md with correct link const mdRegex = - /(?:(?:\]\()|(?:\]:\s*))(?!https?:\/\/|@site\/)(?<filename>[^'")\]\s>]+\.mdx?)/g; + /(?:\]\(|\]:\s*)(?!https?:\/\/|@site\/)(?<filename>[^'")\]\s>]+\.mdx?)/g; let mdMatch = mdRegex.exec(modifiedLine); while (mdMatch !== null) { // Replace it to correct html link. diff --git a/packages/docusaurus-utils/src/markdownParser.ts b/packages/docusaurus-utils/src/markdownParser.ts index 108300c107f8..354461b41473 100644 --- a/packages/docusaurus-utils/src/markdownParser.ts +++ b/packages/docusaurus-utils/src/markdownParser.ts @@ -14,11 +14,11 @@ export function parseMarkdownHeadingId(heading: string): { text: string; id?: string; } { - const customHeadingIdRegex = /^(?<text>.*?)\s*\{#(?<id>[\w-]+)\}$/; + const customHeadingIdRegex = /\s*\{#(?<id>[\w-]+)\}$/; const matches = customHeadingIdRegex.exec(heading); if (matches) { return { - text: matches.groups!.text!, + text: heading.replace(matches[0]!, ''), id: matches.groups!.id!, }; } @@ -69,9 +69,9 @@ export function createExcerpt(fileString: string): string | undefined { // Remove HTML tags. .replace(/<[^>]*>/g, '') // Remove Title headers - .replace(/^#\s*[^#]*\s*#?/gm, '') + .replace(/^#[^#]+#?/gm, '') // Remove Markdown + ATX-style headers - .replace(/^#{1,6}\s*(?<text>[^#]*)\s*(?:#{1,6})?/gm, '$1') + .replace(/^#{1,6}\s*(?<text>[^#]*)\s*#{0,6}/gm, '$1') // Remove emphasis. .replace(/(?<opening>[*_]{1,3})(?<text>.*?)\1/g, '$2') // Remove strikethroughs. @@ -79,7 +79,7 @@ export function createExcerpt(fileString: string): string | undefined { // Remove images. .replace(/!\[(?<alt>.*?)\][[(].*?[\])]/g, '$1') // Remove footnotes. - .replace(/\[\^.+?\](?:: .*?$)?/g, '') + .replace(/\[\^.+?\](?:: .*$)?/g, '') // Remove inline links. .replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1') // Remove inline code. @@ -91,7 +91,7 @@ export function createExcerpt(fileString: string): string | undefined { // Remove Emoji names within colons include preceding whitespace. .replace(/\s?:(?:::|[^:\n])+:/g, '') // Remove custom Markdown heading id. - .replace(/{#*[\w-]+}/, '') + .replace(/\{#*[\w-]+\}/, '') .trim(); if (cleanedLine) { @@ -132,35 +132,42 @@ export function parseMarkdownContentTitle( const removeContentTitleOption = options?.removeContentTitle ?? false; const content = contentUntrimmed.trim(); - - const IMPORT_STATEMENT = - /import\s+(?:[\w*{}\s\n,]+from\s+)?["'\s][@\w/_.-]+["'\s];?|\n/.source; - const REGULAR_TITLE = - /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>(?:{#*[\w-]+})|#)?\n*?)/ - .source; - const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source; - - const regularTitleMatch = new RegExp( - `^(?:${IMPORT_STATEMENT})*?${REGULAR_TITLE}`, - 'g', - ).exec(content); - const alternateTitleMatch = new RegExp( - `^(?:${IMPORT_STATEMENT})*?${ALTERNATE_TITLE}`, - 'g', - ).exec(content); + // We only need to detect import statements that will be parsed by MDX as + // `import` nodes, as broken syntax can't render anyways. That means any block + // that has `import` at the very beginning and surrounded by empty lines. + const contentWithoutImport = content + .replace(/^(?:import\s(?:.|\n(?!\n))*\n{2,})*/, '') + .trim(); + + const regularTitleMatch = /^#[ \t]+(?<title>[^ \t].*)(?:\n|$)/.exec( + contentWithoutImport, + ); + const alternateTitleMatch = /^(?<title>.*)\n=+(?:\n|$)/.exec( + contentWithoutImport, + ); const titleMatch = regularTitleMatch ?? alternateTitleMatch; - const {pattern, title} = titleMatch?.groups ?? {}; - - if (!pattern || !title) { + if (!titleMatch) { return {content, contentTitle: undefined}; } const newContent = removeContentTitleOption - ? content.replace(pattern, '') + ? content.replace(titleMatch[0]!, '') : content; + if (regularTitleMatch) { + return { + content: newContent.trim(), + contentTitle: toTextContentTitle( + regularTitleMatch + .groups!.title!.trim() + .replace(/\s*(?:\{#*[\w-]+\}|#+)$/, ''), + ).trim(), + }; + } return { content: newContent.trim(), - contentTitle: toTextContentTitle(title.trim()).trim(), + contentTitle: toTextContentTitle( + alternateTitleMatch!.groups!.title!.trim().replace(/\s*=+$/, ''), + ).trim(), }; } diff --git a/packages/docusaurus-utils/src/urlUtils.ts b/packages/docusaurus-utils/src/urlUtils.ts index 0f1d24f540ea..a083a330b8d2 100644 --- a/packages/docusaurus-utils/src/urlUtils.ts +++ b/packages/docusaurus-utils/src/urlUtils.ts @@ -58,7 +58,7 @@ export function normalizeUrl(rawUrls: string[]): string { if (i > 0) { // Removing the starting slashes for each component but the first. component = component.replace( - /^[/]+/, + /^\/+/, // Special case where the first element of rawUrls is empty // ["", "/hello"] => /hello component[0] === '/' && !hasStartingSlash ? '/' : '', @@ -68,7 +68,7 @@ export function normalizeUrl(rawUrls: string[]): string { hasEndingSlash = component[component.length - 1] === '/'; // Removing the ending slashes for each component but the last. For the // last component we will combine multiple slashes to a single one. - component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/'); + component = component.replace(/\/+$/, i < urls.length - 1 ? '' : '/'); } hasStartingSlash = true; diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx index 5b290d605421..076c7b1abc1b 100644 --- a/packages/docusaurus/src/client/exports/Interpolate.tsx +++ b/packages/docusaurus/src/client/exports/Interpolate.tsx @@ -18,7 +18,7 @@ We don't ship a markdown parser nor a feature-complete i18n library on purpose. More details here: https://github.com/facebook/docusaurus/pull/4295 */ -const ValueRegexp = /{\w+}/g; +const ValueRegexp = /\{\w+\}/g; const ValueFoundMarker = '{}'; // does not care much // If all the values are plain strings, then interpolate returns a simple string diff --git a/packages/docusaurus/src/commands/deploy.ts b/packages/docusaurus/src/commands/deploy.ts index fdd28ef0b299..6270eb3d29be 100644 --- a/packages/docusaurus/src/commands/deploy.ts +++ b/packages/docusaurus/src/commands/deploy.ts @@ -66,7 +66,7 @@ export function hasSSHProtocol(sourceRepoUrl: string): boolean { return false; } catch { // Fails when there isn't a protocol - return /^(?:[\w-]+@)?[\w.-]+:[\w./_-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git + return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git } } diff --git a/website/src/plugins/changelog/index.js b/website/src/plugins/changelog/index.js index 58a7bb2f6522..310b1ebc3647 100644 --- a/website/src/plugins/changelog/index.js +++ b/website/src/plugins/changelog/index.js @@ -37,7 +37,7 @@ function processSection(section) { .trim() .replace('running_woman', 'running'); - let authors = content.match(/## Committers: \d+.*/ms); + let authors = content.match(/## Committers: \d.*/s); if (authors) { authors = authors[0] .match(/- .*/g) @@ -105,7 +105,7 @@ async function ChangelogPlugin(context, options) { async loadContent() { const fileContent = await fs.readFile(changelogPath, 'utf-8'); const sections = fileContent - .split(/(?=\n## )/ms) + .split(/(?=\n## )/) .map(processSection) .filter(Boolean); await Promise.all( diff --git a/website/src/remark/configTabs.mjs b/website/src/remark/configTabs.mjs index ec4e8de8ce72..3da56b4ba85b 100644 --- a/website/src/remark/configTabs.mjs +++ b/website/src/remark/configTabs.mjs @@ -30,7 +30,7 @@ export default function plugin() { const { groups: {presetOptionName, presetOptionText}, } = presetMeta.match( - /\/\/(?<presetOptionText>.*?): (?<presetOptionName>[A-Za-z]+)/i, + /\/\/(?<presetOptionText>.*?): (?<presetOptionName>[A-Z]+)/i, ) ?? { groups: { presetOptionName: '[translation failure]', @@ -40,7 +40,7 @@ export default function plugin() { const { groups: {pluginName, pluginText}, } = pluginMeta.match( - /\/\/(?<pluginText>.*?): (?<pluginName>[A-Za-z@/-]+)/i, + /\/\/(?<pluginText>.*?): (?<pluginName>[A-Z@/-]+)/i, ) ?? { groups: { pluginName: '[translation failure]', diff --git a/website/src/utils/colorUtils.ts b/website/src/utils/colorUtils.ts index 431b23396082..78c4895c4b24 100644 --- a/website/src/utils/colorUtils.ts +++ b/website/src/utils/colorUtils.ts @@ -100,7 +100,7 @@ export function updateDOMColors( isDarkTheme: boolean, ): void { const styleSheet = Array.from(document.styleSheets).find((item) => - item.href?.match(/styles(?:\.[0-9a-f]+)?\.css/), + item.href?.match(/styles(?:\.[\da-f]+)?\.css/), )!; const rules = Array.from(styleSheet.cssRules) as CSSStyleRule[]; // The rule that looks the most like definition for custom theme colors diff --git a/yarn.lock b/yarn.lock index d09778ac0c04..fdb25727eb5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6559,6 +6559,11 @@ comment-json@^4.2.2: has-own-prop "^2.0.0" repeat-string "^1.6.1" +comment-parser@^1.1.2: + version "1.3.0" + resolved "https://registry.npmmirror.com/comment-parser/-/comment-parser-1.3.0.tgz#68beb7dbe0849295309b376406730cd16c719c44" + integrity sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA== + common-path-prefix@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" @@ -8452,6 +8457,20 @@ eslint-plugin-react@^7.29.3: semver "^6.3.0" string.prototype.matchall "^4.0.6" +eslint-plugin-regexp@^1.5.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/eslint-plugin-regexp/-/eslint-plugin-regexp-1.5.1.tgz#982ea8936283035897d6bb1ba32c0ea5d9a4dee0" + integrity sha512-5v0rQIi54m2KycQHqmOAHrZhvI56GHmI2acr6zEffAqfeifTtobAEapv9Uf4o8//lGvwVkHKyjLoSbBNEFcfOA== + dependencies: + comment-parser "^1.1.2" + eslint-utils "^3.0.0" + grapheme-splitter "^1.0.4" + jsdoctypeparser "^9.0.0" + refa "^0.9.0" + regexp-ast-analysis "^0.3.0" + regexpp "^3.2.0" + scslre "^0.1.6" + eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -9889,6 +9908,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1. resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + graphql@16.0.0: version "16.0.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.0.0.tgz#5724f2767aefa543418e83671372117c39408c8f" @@ -11869,6 +11893,11 @@ jscodeshift@^0.13.0: temp "^0.8.4" write-file-atomic "^2.3.0" +jsdoctypeparser@^9.0.0: + version "9.0.0" + resolved "https://registry.npmmirror.com/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz#8c97e2fb69315eb274b0f01377eaa5c940bd7b26" + integrity sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw== + jsdom@^16.6.0: version "16.7.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" @@ -16204,6 +16233,13 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +refa@^0.9.0: + version "0.9.1" + resolved "https://registry.npmmirror.com/refa/-/refa-0.9.1.tgz#12731fce378d235731b1f73182b20083c8a75ca8" + integrity sha512-egU8LgFq2VXlAfUi8Jcbr5X38wEOadMFf8tCbshgcpVCYlE7k84pJOSlnvXF+muDB4igkdVMq7Z/kiNPqDT9TA== + dependencies: + regexpp "^3.2.0" + regenerate-unicode-properties@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" @@ -16243,6 +16279,22 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp-ast-analysis@^0.2.3: + version "0.2.4" + resolved "https://registry.npmmirror.com/regexp-ast-analysis/-/regexp-ast-analysis-0.2.4.tgz#a497a7c8bfbba51438693821e4b0e3ed43e20f1b" + integrity sha512-8L7kOZQaKPxKKAwGuUZxTQtlO3WZ+tiXy4s6G6PKL6trbOXcZoumwC3AOHHFtI/xoSbNxt7jgLvCnP1UADLWqg== + dependencies: + refa "^0.9.0" + regexpp "^3.2.0" + +regexp-ast-analysis@^0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/regexp-ast-analysis/-/regexp-ast-analysis-0.3.0.tgz#386f177dfe5abc5ac58b51eb5962beac64e898ce" + integrity sha512-11PlbBSUxwWpdj6BdZUKfhDdV9g+cveqHB+BqBQDBD7ZermDBVgtyowUaXTvT0dO3tZYo2bDIr/GoED6X1aYSA== + dependencies: + refa "^0.9.0" + regexpp "^3.2.0" + regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: version "1.4.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" @@ -16868,6 +16920,15 @@ screenfull@^5.1.0: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== +scslre@^0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/scslre/-/scslre-0.1.6.tgz#71a2832e4bf3a9254973a04fbed90aec94f75757" + integrity sha512-JORxVRlQTfjvlOAaiQKebgFElyAm5/W8b50lgaZ0OkEnKnagJW2ufDh3xRfU75UD9z3FGIu1gL1IyR3Poa6Qmw== + dependencies: + refa "^0.9.0" + regexp-ast-analysis "^0.2.3" + regexpp "^3.2.0" + section-matter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" From 8c1e518ba231b779654893ec2acaa7a8e854dcfb Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sun, 13 Mar 2022 19:34:50 +0800 Subject: [PATCH 009/405] chore: do not print prototype in jest snapshot (#6908) --- jest.config.mjs | 11 +- .../__snapshots__/index.test.ts.snap | 40 +- .../__snapshots__/index.test.ts.snap | 298 ++--- .../__snapshots__/index.test.ts.snap | 68 +- .../writeRedirectFiles.test.ts.snap | 10 +- .../__tests__/__snapshots__/feed.test.ts.snap | 6 +- .../__snapshots__/index.test.ts.snap | 58 +- .../__snapshots__/translations.test.ts.snap | 52 +- .../src/__tests__/index.test.ts | 5 +- .../__tests__/__snapshots__/cli.test.ts.snap | 36 +- .../__tests__/__snapshots__/docs.test.ts.snap | 128 +- .../__snapshots__/globalData.test.ts.snap | 22 +- .../__snapshots__/index.test.ts.snap | 1074 ++++++++--------- .../__snapshots__/translations.test.ts.snap | 168 +-- .../__snapshots__/generator.test.ts.snap | 122 +- .../__snapshots__/index.test.ts.snap | 128 +- .../__snapshots__/normalization.test.ts.snap | 54 +- .../__snapshots__/postProcessor.test.ts.snap | 38 +- .../__snapshots__/index.test.ts.snap | 44 +- .../__snapshots__/translations.test.ts.snap | 98 +- .../__snapshots__/codeBlockUtils.test.ts.snap | 44 +- .../__snapshots__/tocUtils.test.ts.snap | 22 +- .../__snapshots__/markdownLinks.test.ts.snap | 44 +- .../__snapshots__/markdownParser.test.ts.snap | 64 +- .../exports/__tests__/BrowserOnly.test.tsx | 17 +- .../__snapshots__/Interpolate.test.tsx.snap | 8 +- .../__tests__/docusaurusContext.test.tsx | 12 +- .../__snapshots__/config.test.ts.snap | 12 +- .../swizzle/__tests__/components.test.ts | 12 +- .../__snapshots__/config.test.ts.snap | 108 +- .../__snapshots__/routes.test.ts.snap | 64 +- .../client-modules/__tests__/index.test.ts | 12 +- .../server/html-tags/__tests__/index.test.ts | 12 +- .../__tests__/__snapshots__/init.test.ts.snap | 54 +- .../__snapshots__/index.test.ts.snap | 100 +- .../server/presets/__tests__/index.test.ts | 6 +- .../__tests__/__snapshots__/base.test.ts.snap | 4 +- 37 files changed, 1536 insertions(+), 1519 deletions(-) diff --git a/jest.config.mjs b/jest.config.mjs index 2b0342501b6c..c469fed92fea 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -25,13 +25,14 @@ const ignorePatterns = [ export default { rootDir: fileURLToPath(new URL('.', import.meta.url)), verbose: true, - testURL: 'http://localhost/', + testURL: 'https://docusaurus.io/', testEnvironment: 'node', testPathIgnorePatterns: ignorePatterns, coveragePathIgnorePatterns: ignorePatterns, transform: { '^.+\\.[jt]sx?$': 'babel-jest', }, + errorOnDeprecated: true, moduleNameMapper: { // Jest can't resolve CSS or asset imports '^.+\\.(css|jpe?g|png|svg)$': '<rootDir>/jest/emptyModule.js', @@ -49,10 +50,8 @@ export default { '@docusaurus/plugin-content-docs/client': '@docusaurus/plugin-content-docs/src/client/index.ts', }, - globals: { - window: { - location: {href: 'https://docusaurus.io'}, - }, - }, snapshotSerializers: ['<rootDir>/jest/snapshotPathNormalizer.js'], + snapshotFormat: { + printBasicPrototype: false, + }, }; diff --git a/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap index 27685bfd371a..cf55c3083aea 100644 --- a/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,68 +1,68 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`error prints objects 1`] = ` -Array [ - Array [ +[ + [ "[ERROR] {\\"a\\":1}", ], - Array [ + [ "[ERROR] undefined", ], - Array [ + [ "[ERROR] 1,2,3", ], - Array [ + [ "[ERROR] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; exports[`info prints objects 1`] = ` -Array [ - Array [ +[ + [ "[INFO] {\\"a\\":1}", ], - Array [ + [ "[INFO] undefined", ], - Array [ + [ "[INFO] 1,2,3", ], - Array [ + [ "[INFO] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; exports[`success prints objects 1`] = ` -Array [ - Array [ +[ + [ "[SUCCESS] {\\"a\\":1}", ], - Array [ + [ "[SUCCESS] undefined", ], - Array [ + [ "[SUCCESS] 1,2,3", ], - Array [ + [ "[SUCCESS] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; exports[`warn prints objects 1`] = ` -Array [ - Array [ +[ + [ "[WARNING] {\\"a\\":1}", ], - Array [ + [ "[WARNING] undefined", ], - Array [ + [ "[WARNING] 1,2,3", ], - Array [ + [ "[WARNING] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap index d7b84a935097..35011f30c986 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap @@ -96,19 +96,19 @@ cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' `; exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = ` -Object { - "children": Array [ - Object { - "children": Array [ - Object { +{ + "children": [ + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 32, "line": 1, "offset": 31, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 3, "line": 1, "offset": 2, @@ -120,13 +120,13 @@ Object { ], "depth": 1, "position": Position { - "end": Object { + "end": { "column": 32, "line": 1, "offset": 31, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 1, "offset": 0, @@ -134,17 +134,17 @@ Object { }, "type": "heading", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 23, "line": 3, "offset": 55, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 4, "line": 3, "offset": 36, @@ -156,13 +156,13 @@ Object { ], "depth": 2, "position": Position { - "end": Object { + "end": { "column": 23, "line": 3, "offset": 55, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 3, "offset": 33, @@ -170,17 +170,17 @@ Object { }, "type": "heading", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 5, "line": 5, "offset": 61, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 5, "offset": 57, @@ -191,13 +191,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 5, "line": 5, "offset": 61, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 5, "offset": 57, @@ -205,19 +205,19 @@ Object { }, "type": "paragraph", }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { + { + "children": [ + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 6, "line": 7, "offset": 68, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 2, "line": 7, "offset": 64, @@ -228,13 +228,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 29, "line": 7, "offset": 91, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 7, "offset": 63, @@ -246,13 +246,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 29, "line": 7, "offset": 91, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 7, "offset": 63, @@ -260,19 +260,19 @@ Object { }, "type": "paragraph", }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { + { + "children": [ + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 7, "line": 9, "offset": 99, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 3, "line": 9, "offset": 95, @@ -283,13 +283,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 9, "line": 9, "offset": 101, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 9, "offset": 93, @@ -299,13 +299,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 9, "line": 9, "offset": 101, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 9, "offset": 93, @@ -313,18 +313,18 @@ Object { }, "type": "paragraph", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "alt": "image", "position": Position { - "end": Object { + "end": { "column": 43, "line": 11, "offset": 145, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 11, "offset": 103, @@ -336,13 +336,13 @@ Object { }, ], "position": Position { - "end": Object { + "end": { "column": 43, "line": 11, "offset": 145, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 11, "offset": 103, @@ -350,17 +350,17 @@ Object { }, "type": "paragraph", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 18, "line": 13, "offset": 164, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 4, "line": 13, "offset": 150, @@ -372,13 +372,13 @@ Object { ], "depth": 2, "position": Position { - "end": Object { + "end": { "column": 18, "line": 13, "offset": 164, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 13, "offset": 147, @@ -386,15 +386,15 @@ Object { }, "type": "heading", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 23, "line": 15, "offset": 188, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 15, "offset": 166, @@ -403,18 +403,18 @@ Object { "type": "import", "value": "import XYZ from 'xyz';", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 7, "line": 19, "offset": 287, }, - "indent": Array [ + "indent": [ 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 17, "offset": 190, @@ -425,17 +425,17 @@ Object { <span>Test</span> </XYZ>", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 29, "line": 21, "offset": 317, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 4, "line": 21, "offset": 292, @@ -447,13 +447,13 @@ Object { ], "depth": 2, "position": Position { - "end": Object { + "end": { "column": 29, "line": 21, "offset": 317, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 21, "offset": 289, @@ -461,16 +461,16 @@ Object { }, "type": "heading", }, - Object { + { "lang": "mdx-code-block", "meta": null, "position": Position { - "end": Object { + "end": { "column": 4, "line": 29, "offset": 442, }, - "indent": Array [ + "indent": [ 1, 1, 1, @@ -478,7 +478,7 @@ Object { 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 23, "offset": 319, @@ -491,17 +491,17 @@ Object { <div>Sebastien Lorber</div> </Avatar>", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 44, "line": 31, "offset": 487, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 4, "line": 31, "offset": 447, @@ -513,13 +513,13 @@ Object { ], "depth": 2, "position": Position { - "end": Object { + "end": { "column": 44, "line": 31, "offset": 487, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 31, "offset": 444, @@ -527,14 +527,14 @@ Object { }, "type": "heading", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 25, "line": 40, "offset": 688, }, - "indent": Array [ + "indent": [ 1, 1, 1, @@ -543,7 +543,7 @@ Object { 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 33, "offset": 489, @@ -559,20 +559,20 @@ Object { ]}> <TabItem value=\\"bash\\">", }, - Object { + { "lang": "bash", "meta": null, "position": Position { - "end": Object { + "end": { "column": 4, "line": 44, "offset": 740, }, - "indent": Array [ + "indent": [ 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 42, "offset": 690, @@ -581,17 +581,17 @@ Object { "type": "code", "value": "GIT_USER=<GITHUB_USERNAME> yarn deploy", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 28, "line": 47, "offset": 782, }, - "indent": Array [ + "indent": [ 1, ], - "start": Object { + "start": { "column": 1, "line": 46, "offset": 742, @@ -601,20 +601,20 @@ Object { "value": " </TabItem> <TabItem value=\\"windows\\">", }, - Object { + { "lang": null, "meta": null, "position": Position { - "end": Object { + "end": { "column": 8, "line": 51, "offset": 865, }, - "indent": Array [ + "indent": [ 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 49, "offset": 784, @@ -625,17 +625,17 @@ Object { cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" \`\`\`", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 31, "line": 54, "offset": 910, }, - "indent": Array [ + "indent": [ 1, ], - "start": Object { + "start": { "column": 1, "line": 53, "offset": 867, @@ -645,20 +645,20 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" "value": " </TabItem> <TabItem value=\\"powershell\\">", }, - Object { + { "lang": "powershell", "meta": null, "position": Position { - "end": Object { + "end": { "column": 4, "line": 58, "offset": 986, }, - "indent": Array [ + "indent": [ 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 56, "offset": 912, @@ -667,17 +667,17 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" "type": "code", "value": "cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy'", }, - Object { + { "position": Position { - "end": Object { + "end": { "column": 8, "line": 61, "offset": 1008, }, - "indent": Array [ + "indent": [ 1, ], - "start": Object { + "start": { "column": 1, "line": 60, "offset": 988, @@ -687,17 +687,17 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" "value": " </TabItem> </Tabs>", }, - Object { - "children": Array [ - Object { + { + "children": [ + { "position": Position { - "end": Object { + "end": { "column": 55, "line": 63, "offset": 1064, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 4, "line": 63, "offset": 1013, @@ -709,13 +709,13 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" ], "depth": 2, "position": Position { - "end": Object { + "end": { "column": 55, "line": 63, "offset": 1064, }, - "indent": Array [], - "start": Object { + "indent": [], + "start": { "column": 1, "line": 63, "offset": 1010, @@ -723,16 +723,16 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" }, "type": "heading", }, - Object { + { "lang": "mdx-code-block", "meta": null, "position": Position { - "end": Object { + "end": { "column": 5, "line": 95, "offset": 1585, }, - "indent": Array [ + "indent": [ 1, 1, 1, @@ -764,7 +764,7 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" 1, 1, ], - "start": Object { + "start": { "column": 1, "line": 65, "offset": 1066, @@ -802,13 +802,13 @@ cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' </Tabs>", }, ], - "position": Object { - "end": Object { + "position": { + "end": { "column": 1, "line": 96, "offset": 1586, }, - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, diff --git a/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap index 750f8e7e9537..6bb29e50da09 100644 --- a/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,16 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`migration CLI migrates complex website: copy 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/blog", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/blog", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/pages/en", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/static", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/static", ], @@ -18,18 +18,18 @@ Array [ `; exports[`migration CLI migrates complex website: mkdirp 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages", ], ] `; -exports[`migration CLI migrates complex website: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates complex website: mkdirs 1`] = `[]`; exports[`migration CLI migrates complex website: write 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/docusaurus.config.js", "module.exports={ \\"title\\": \\"Docusaurus\\", @@ -138,7 +138,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/package.json", "{ \\"name\\": \\"docusaurus-1-website\\", @@ -167,7 +167,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/css/customTheme.css", ":root{ --ifm-color-primary-lightest: #3CAD6E; @@ -184,16 +184,16 @@ Array [ `; exports[`migration CLI migrates missing versions: copy 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/blog", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/blog", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/pages/en", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/static", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/static", ], @@ -201,18 +201,18 @@ Array [ `; exports[`migration CLI migrates missing versions: mkdirp 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages", ], ] `; -exports[`migration CLI migrates missing versions: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates missing versions: mkdirs 1`] = `[]`; exports[`migration CLI migrates missing versions: write 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/docusaurus.config.js", "module.exports={ \\"title\\": \\"Docusaurus\\", @@ -321,7 +321,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/package.json", "{ \\"name\\": \\"docusaurus-1-website\\", @@ -350,7 +350,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/css/customTheme.css", ":root{ --ifm-color-primary-lightest: #3CAD6E; @@ -367,12 +367,12 @@ Array [ `; exports[`migration CLI migrates simple website: copy 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/website/pages/en", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/website/static", "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/static", ], @@ -380,18 +380,18 @@ Array [ `; exports[`migration CLI migrates simple website: mkdirp 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages", ], ] `; -exports[`migration CLI migrates simple website: mkdirs 1`] = `Array []`; +exports[`migration CLI migrates simple website: mkdirs 1`] = `[]`; exports[`migration CLI migrates simple website: write 1`] = ` -Array [ - Array [ +[ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/docusaurus.config.js", "module.exports={ \\"title\\": \\"Docusaurus\\", @@ -501,7 +501,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/package.json", "{ \\"name\\": \\"docusaurus-1-website\\", @@ -530,7 +530,7 @@ Array [ } }", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/css/customTheme.css", ":root{ --ifm-color-primary-lightest: #3CAD6E; @@ -543,7 +543,7 @@ Array [ } ", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/docs/api-commands.md", "--- id: commands @@ -552,7 +552,7 @@ title: CLI Commands ## Doc ", ], - Array [ + [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/docs/api-doc-markdown.md", "--- id: doc-markdown diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap index acdc68104ebd..fa9472e3b172 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`toRedirectFilesMetadata creates appropriate metadata for empty baseUrl: fileContent baseUrl=empty 1`] = ` -Array [ +[ "<!DOCTYPE html> <html> <head> @@ -17,7 +17,7 @@ Array [ `; exports[`toRedirectFilesMetadata creates appropriate metadata for root baseUrl: fileContent baseUrl=/ 1`] = ` -Array [ +[ "<!DOCTYPE html> <html> <head> @@ -33,7 +33,7 @@ Array [ `; exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=false: fileContent 1`] = ` -Array [ +[ "<!DOCTYPE html> <html> <head> @@ -71,7 +71,7 @@ Array [ `; exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=true: fileContent 1`] = ` -Array [ +[ "<!DOCTYPE html> <html> <head> @@ -109,7 +109,7 @@ Array [ `; exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=undefined: fileContent 1`] = ` -Array [ +[ "<!DOCTYPE html> <html> <head> diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index f44f9a71052d..ec932459f47a 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`atom has feed item for each post 1`] = ` -Array [ +[ "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?> <feed xmlns=\\"http://www.w3.org/2005/Atom\\"> <id>https://docusaurus.io/myBaseUrl/blog</id> @@ -85,7 +85,7 @@ Array [ `; exports[`json has feed item for each post 1`] = ` -Array [ +[ "{ \\"version\\": \\"https://jsonfeed.org/version/1\\", \\"title\\": \\"Hello Blog\\", @@ -172,7 +172,7 @@ Array [ `; exports[`rss has feed item for each post 1`] = ` -Array [ +[ "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?> <rss version=\\"2.0\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:content=\\"http://purl.org/rss/1.0/modules/content/\\"> <channel> diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap index 37ba6bf0d0f6..473ed4d5bdc3 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,22 +1,22 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`blog plugin works on blog tags without pagination 1`] = ` -Object { - "/blog/tags/tag-1": Object { - "items": Array [ +{ + "/blog/tags/tag-1": { + "items": [ "/simple/slug/another", "/another/tags", "/another/tags2", ], "name": "tag1", - "pages": Array [ - Object { - "items": Array [ + "pages": [ + { + "items": [ "/simple/slug/another", "/another/tags", "/another/tags2", ], - "metadata": Object { + "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", "nextPage": null, @@ -31,19 +31,19 @@ Object { ], "permalink": "/blog/tags/tag-1", }, - "/blog/tags/tag-2": Object { - "items": Array [ + "/blog/tags/tag-2": { + "items": [ "/another/tags", "/another/tags2", ], "name": "tag2", - "pages": Array [ - Object { - "items": Array [ + "pages": [ + { + "items": [ "/another/tags", "/another/tags2", ], - "metadata": Object { + "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", "nextPage": null, @@ -62,21 +62,21 @@ Object { `; exports[`blog plugin works with blog tags 1`] = ` -Object { - "/blog/tags/tag-1": Object { - "items": Array [ +{ + "/blog/tags/tag-1": { + "items": [ "/simple/slug/another", "/another/tags", "/another/tags2", ], "name": "tag1", - "pages": Array [ - Object { - "items": Array [ + "pages": [ + { + "items": [ "/simple/slug/another", "/another/tags", ], - "metadata": Object { + "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", "nextPage": "/blog/tags/tag-1/page/2", @@ -88,11 +88,11 @@ Object { "totalPages": 2, }, }, - Object { - "items": Array [ + { + "items": [ "/another/tags2", ], - "metadata": Object { + "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", "nextPage": null, @@ -107,19 +107,19 @@ Object { ], "permalink": "/blog/tags/tag-1", }, - "/blog/tags/tag-2": Object { - "items": Array [ + "/blog/tags/tag-2": { + "items": [ "/another/tags", "/another/tags2", ], "name": "tag2", - "pages": Array [ - Object { - "items": Array [ + "pages": [ + { + "items": [ "/another/tags", "/another/tags2", ], - "metadata": Object { + "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", "nextPage": null, diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap index 9e97fbbe8347..e07e327f88f7 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,18 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`getContentTranslationFiles returns translation files matching snapshot 1`] = ` -Array [ - Object { - "content": Object { - "description": Object { +[ + { + "content": { + "description": { "description": "The description for the blog used in SEO", "message": "Someone's random blog", }, - "sidebar.title": Object { + "sidebar.title": { "description": "The label for the left sidebar", "message": "All my posts", }, - "title": Object { + "title": { "description": "The title for the blog used in SEO", "message": "My blog", }, @@ -23,13 +23,13 @@ Array [ `; exports[`translateContent falls back when translation is incomplete 1`] = ` -Object { - "blogListPaginated": Array [ - Object { - "items": Array [ +{ + "blogListPaginated": [ + { + "items": [ "hello", ], - "metadata": Object { + "metadata": { "blogDescription": "Someone's random blog", "blogTitle": "My blog", "nextPage": null, @@ -42,35 +42,35 @@ Object { }, }, ], - "blogPosts": Array [ - Object { + "blogPosts": [ + { "id": "hello", - "metadata": Object { + "metadata": { "date": 2021-07-19T00:00:00.000Z, "description": "/blog/2021/06/19/hello", "formattedDate": "June 19, 2021", "permalink": "/blog/2021/06/19/hello", "source": "/blog/2021/06/19/hello", - "tags": Array [], + "tags": [], "title": "Hello", "truncated": true, }, }, ], "blogSidebarTitle": "All my posts", - "blogTags": Object {}, + "blogTags": {}, "blogTagsListPath": "/tags", } `; exports[`translateContent returns translated loaded 1`] = ` -Object { - "blogListPaginated": Array [ - Object { - "items": Array [ +{ + "blogListPaginated": [ + { + "items": [ "hello", ], - "metadata": Object { + "metadata": { "blogDescription": "Someone's random blog (translated)", "blogTitle": "My blog (translated)", "nextPage": null, @@ -83,23 +83,23 @@ Object { }, }, ], - "blogPosts": Array [ - Object { + "blogPosts": [ + { "id": "hello", - "metadata": Object { + "metadata": { "date": 2021-07-19T00:00:00.000Z, "description": "/blog/2021/06/19/hello", "formattedDate": "June 19, 2021", "permalink": "/blog/2021/06/19/hello", "source": "/blog/2021/06/19/hello", - "tags": Array [], + "tags": [], "title": "Hello", "truncated": true, }, }, ], "blogSidebarTitle": "All my posts (translated)", - "blogTags": Object {}, + "blogTags": {}, "blogTagsListPath": "/tags", } `; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 0dca4dfbb4f5..2a6d9d24f745 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -411,11 +411,14 @@ describe('blog plugin', () => { }); it('excludes draft blog post from production build', async () => { - process.env.NODE_ENV = 'production'; + const originalEnv = process.env; + jest.resetModules(); + process.env = {...originalEnv, NODE_ENV: 'production'}; const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPosts = await getBlogPosts(siteDir); expect(blogPosts.find((v) => v.metadata.title === 'draft')).toBeUndefined(); + process.env = originalEnv; }); it('creates blog post without date', async () => { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap index 5536e5ca09c8..2f4d4e94fa34 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap @@ -1,43 +1,43 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`docsVersion first time versioning 1`] = ` -Object { - "docs": Object { - "Guides": Array [ +{ + "docs": { + "Guides": [ "hello", ], - "Test": Array [ - Object { - "items": Array [ + "Test": [ + { + "items": [ "foo/bar", "foo/baz", ], "label": "foo", "type": "category", }, - Object { - "items": Array [ + { + "items": [ "rootAbsoluteSlug", "rootRelativeSlug", "rootResolvedSlug", "rootTryToEscapeSlug", ], "label": "Slugs", - "link": Object { + "link": { "type": "generated-index", }, "type": "category", }, - Object { + { "id": "headingAsTitle", "type": "doc", }, - Object { + { "href": "https://github.com", "label": "Github", "type": "link", }, - Object { + { "id": "hello", "type": "ref", }, @@ -47,12 +47,12 @@ Object { `; exports[`docsVersion not the first time versioning 1`] = ` -Object { - "docs": Object { - "Guides": Array [ +{ + "docs": { + "Guides": [ "hello", ], - "Test": Array [ + "Test": [ "foo/bar", ], }, @@ -60,8 +60,8 @@ Object { `; exports[`docsVersion second docs instance versioning 1`] = ` -Object { - "community": Array [ +{ + "community": [ "team", ], } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap index b66f4a4929c5..eaed1c90bbbb 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap @@ -1,177 +1,177 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`simple site custom pagination 1`] = ` -Object { - "pagination": Array [ - Object { +{ + "pagination": [ + { "id": "doc with space", - "next": Object { + "next": { "permalink": "/docs/foo/bar", "title": "Bar", }, "prev": undefined, }, - Object { + { "id": "foo/bar", "next": undefined, "prev": undefined, }, - Object { + { "id": "foo/baz", - "next": Object { + "next": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bar", "title": "Bar", }, }, - Object { + { "id": "headingAsTitle", - "next": Object { + "next": { "permalink": "/docs/", "title": "Hello sidebar_label", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bazSlug.html", "title": "baz pagination_label", }, }, - Object { + { "id": "hello", - "next": Object { + "next": { "permalink": "/docs/ipsum", "title": "ipsum", }, - "prev": Object { + "prev": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, }, - Object { + { "id": "ipsum", - "next": Object { + "next": { "permalink": "/docs/lorem", "title": "lorem", }, - "prev": Object { + "prev": { "permalink": "/docs/", "title": "Hello sidebar_label", }, }, - Object { + { "id": "lorem", - "next": Object { + "next": { "permalink": "/docs/rootAbsoluteSlug", "title": "rootAbsoluteSlug", }, - "prev": Object { + "prev": { "permalink": "/docs/ipsum", "title": "ipsum", }, }, - Object { + { "id": "rootAbsoluteSlug", - "next": Object { + "next": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bazSlug.html", "title": "baz pagination_label", }, }, - Object { + { "id": "rootRelativeSlug", - "next": Object { + "next": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bazSlug.html", "title": "baz pagination_label", }, }, - Object { + { "id": "rootResolvedSlug", - "next": Object { + "next": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bazSlug.html", "title": "baz pagination_label", }, }, - Object { + { "id": "rootTryToEscapeSlug", - "next": Object { + "next": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, - "prev": Object { + "prev": { "permalink": "/docs/foo/bazSlug.html", "title": "baz pagination_label", }, }, - Object { + { "id": "slugs/absoluteSlug", - "next": Object { + "next": { "permalink": "/docs/slugs/relativeSlug", "title": "relativeSlug", }, - "prev": Object { + "prev": { "permalink": "/docs/rootTryToEscapeSlug", "title": "rootTryToEscapeSlug", }, }, - Object { + { "id": "slugs/relativeSlug", - "next": Object { + "next": { "permalink": "/docs/slugs/hey/resolvedSlug", "title": "resolvedSlug", }, - "prev": Object { + "prev": { "permalink": "/docs/absoluteSlug", "title": "absoluteSlug", }, }, - Object { + { "id": "slugs/resolvedSlug", - "next": Object { + "next": { "permalink": "/docs/tryToEscapeSlug", "title": "tryToEscapeSlug", }, - "prev": Object { + "prev": { "permalink": "/docs/slugs/relativeSlug", "title": "relativeSlug", }, }, - Object { + { "id": "slugs/tryToEscapeSlug", "next": undefined, - "prev": Object { + "prev": { "permalink": "/docs/slugs/hey/resolvedSlug", "title": "resolvedSlug", }, }, ], - "sidebars": Object { - "defaultSidebar": Array [ - Object { + "sidebars": { + "defaultSidebar": [ + { "id": "doc with space", "type": "doc", }, - Object { + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "foo/bar", "type": "doc", }, - Object { + { "id": "foo/baz", "type": "doc", }, @@ -180,56 +180,56 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "headingAsTitle", "type": "doc", }, - Object { + { "id": "hello", "label": "Hello sidebar_label", "type": "doc", }, - Object { + { "id": "ipsum", "type": "doc", }, - Object { + { "id": "lorem", "type": "doc", }, - Object { + { "id": "rootAbsoluteSlug", "type": "doc", }, - Object { + { "id": "rootRelativeSlug", "type": "doc", }, - Object { + { "id": "rootResolvedSlug", "type": "doc", }, - Object { + { "id": "rootTryToEscapeSlug", "type": "doc", }, - Object { + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "slugs/absoluteSlug", "type": "doc", }, - Object { + { "id": "slugs/relativeSlug", "type": "doc", }, - Object { + { "id": "slugs/resolvedSlug", "type": "doc", }, - Object { + { "id": "slugs/tryToEscapeSlug", "type": "doc", }, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap index 95ed78b3ff31..a646e0241e43 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`toGlobalDataVersion generates the right docs, sidebars, and metadata 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "id": "main", "path": "/current/main", "sidebar": "tutorial", }, - Object { + { "id": "doc", "path": "/current/doc", "sidebar": "tutorial", }, - Object { + { "id": "/current/generated", "path": "/current/generated", "sidebar": "tutorial", @@ -24,16 +24,16 @@ Object { "mainDocId": "main", "name": "current", "path": "/current", - "sidebars": Object { - "another": Object { - "link": Object { + "sidebars": { + "another": { + "link": { "label": "Generated", "path": "/current/generated", }, }, - "links": Object {}, - "tutorial": Object { - "link": Object { + "links": {}, + "tutorial": { + "link": { "label": "main", "path": "/current/main", }, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 11e6478de794..b65e9956e345 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`sidebar site with undefined sidebar 1`] = ` -Object { - "defaultSidebar": Array [ - Object { +{ + "defaultSidebar": [ + { "id": "hello-1", "type": "doc", }, - Object { + { "id": "hello-2", "label": "Hello 2 From Doc", "type": "doc", @@ -40,18 +40,18 @@ Available document ids are: `; exports[`simple website content 1`] = ` -Object { +{ "description": "Images", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "baz", "pagination_label": "baz pagination_label", "slug": "bazSlug.html", - "tags": Array [ + "tags": [ "tag 1", "tag-1", - Object { + { "label": "tag 2", "permalink": "tag2-custom-permalink", }, @@ -61,12 +61,12 @@ Object { "id": "foo/baz", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/category/slugs", "title": "Slugs", }, "permalink": "/docs/foo/bazSlug.html", - "previous": Object { + "previous": { "permalink": "/docs/foo/bar", "title": "Bar", }, @@ -75,12 +75,12 @@ Object { "slug": "/foo/bazSlug.html", "source": "@site/docs/foo/baz.md", "sourceDirName": "foo", - "tags": Array [ - Object { + "tags": [ + { "label": "tag 1", "permalink": "/docs/tags/tag-1", }, - Object { + { "label": "tag 2", "permalink": "/docs/tags/tag2-custom-permalink", }, @@ -92,15 +92,15 @@ Object { `; exports[`simple website content 2`] = ` -Object { +{ "description": "Hi, Endilie here :)", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "hello", "sidebar_label": "Hello sidebar_label", "slug": "/", - "tags": Array [ + "tags": [ "tag-1", "tag 3", ], @@ -111,7 +111,7 @@ Object { "lastUpdatedBy": undefined, "next": undefined, "permalink": "/docs/", - "previous": Object { + "previous": { "permalink": "/docs/headingAsTitle", "title": "My heading as title", }, @@ -120,12 +120,12 @@ Object { "slug": "/", "source": "@site/docs/hello.md", "sourceDirName": ".", - "tags": Array [ - Object { + "tags": [ + { "label": "tag-1", "permalink": "/docs/tags/tag-1", }, - Object { + { "label": "tag 3", "permalink": "/docs/tags/tag-3", }, @@ -137,11 +137,11 @@ Object { `; exports[`simple website content 3`] = ` -Object { +{ "description": "This is custom description", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "description": "This is custom description", "id": "bar", "pagination_next": null, @@ -159,7 +159,7 @@ Object { "slug": "/foo/bar", "source": "@site/docs/foo/bar.md", "sourceDirName": "foo", - "tags": Array [], + "tags": [], "title": "Bar", "unversionedId": "foo/bar", "version": "current", @@ -167,21 +167,21 @@ Object { `; exports[`simple website content 4`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "foo/bar", "type": "doc", }, - Object { + { "id": "foo/baz", "type": "doc", }, @@ -190,45 +190,45 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "rootAbsoluteSlug", "type": "doc", }, - Object { + { "id": "rootRelativeSlug", "type": "doc", }, - Object { + { "id": "rootResolvedSlug", "type": "doc", }, - Object { + { "id": "rootTryToEscapeSlug", "type": "doc", }, ], "label": "Slugs", - "link": Object { + "link": { "permalink": "/docs/category/slugs", "slug": "/category/slugs", "type": "generated-index", }, "type": "category", }, - Object { + { "id": "headingAsTitle", "type": "doc", }, - Object { + { "href": "https://github.com", "label": "Github", "type": "link", }, - Object { + { "id": "hello", "type": "ref", }, @@ -237,11 +237,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "hello", "type": "doc", }, @@ -255,90 +255,90 @@ Object { `; exports[`simple website content 5`] = ` -Object { - "pluginName": Object { - "pluginId": Object { +{ + "pluginName": { + "pluginId": { "breadcrumbs": true, "path": "/docs", - "versions": Array [ - Object { - "docs": Array [ - Object { + "versions": [ + { + "docs": [ + { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, }, - Object { + { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", }, - Object { + { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", }, - Object { + { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", }, - Object { + { "id": "hello", "path": "/docs/", "sidebar": "docs", }, - Object { + { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, }, - Object { + { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, }, - Object { + { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", }, - Object { + { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", }, - Object { + { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", }, - Object { + { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", }, - Object { + { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, }, - Object { + { "id": "/category/slugs", "path": "/docs/category/slugs", "sidebar": "docs", @@ -349,9 +349,9 @@ Object { "mainDocId": "hello", "name": "current", "path": "/docs", - "sidebars": Object { - "docs": Object { - "link": Object { + "sidebars": { + "docs": { + "link": { "label": "foo/bar", "path": "/docs/foo/bar", }, @@ -365,7 +365,7 @@ Object { `; exports[`simple website content: data 1`] = ` -Object { +{ "category-docs-docs-category-slugs-0fe.json": "{ \\"title\\": \\"Slugs\\", \\"slug\\": \\"/category/slugs\\", @@ -969,90 +969,90 @@ Object { `; exports[`simple website content: global data 1`] = ` -Object { - "pluginName": Object { - "pluginId": Object { +{ + "pluginName": { + "pluginId": { "breadcrumbs": true, "path": "/docs", - "versions": Array [ - Object { - "docs": Array [ - Object { + "versions": [ + { + "docs": [ + { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, }, - Object { + { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", }, - Object { + { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", }, - Object { + { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", }, - Object { + { "id": "hello", "path": "/docs/", "sidebar": "docs", }, - Object { + { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, }, - Object { + { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, }, - Object { + { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", }, - Object { + { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", }, - Object { + { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", }, - Object { + { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", }, - Object { + { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, }, - Object { + { "id": "/category/slugs", "path": "/docs/category/slugs", "sidebar": "docs", @@ -1063,9 +1063,9 @@ Object { "mainDocId": "hello", "name": "current", "path": "/docs", - "sidebars": Object { - "docs": Object { - "link": Object { + "sidebars": { + "docs": { + "link": { "label": "foo/bar", "path": "/docs/foo/bar", }, @@ -1079,181 +1079,181 @@ Object { `; exports[`simple website content: route config 1`] = ` -Array [ - Object { +[ + { "component": "@theme/DocTagsListPage", "exact": true, - "modules": Object { + "modules": { "tags": "~docs/tags-list-current-prop-15a.json", }, "path": "/docs/tags", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-tags-tag-1-b3f.json", }, "path": "/docs/tags/tag-1", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-tags-tag-3-ab5.json", }, "path": "/docs/tags/tag-3", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json", }, "path": "/docs/tags/tag2-custom-permalink", }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-current-metadata-prop-751.json", }, "path": "/docs", "priority": -1, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/hello.md", }, "path": "/docs/", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/absoluteSlug.md", }, "path": "/docs/absoluteSlug", }, - Object { + { "component": "@theme/DocCategoryGeneratedIndexPage", "exact": true, - "modules": Object { + "modules": { "categoryGeneratedIndex": "~docs/category-docs-docs-category-slugs-0fe.json", }, "path": "/docs/category/slugs", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/doc with space.md", }, "path": "/docs/doc with space", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/foo/bar.md", }, "path": "/docs/foo/bar", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/foo/baz.md", }, "path": "/docs/foo/bazSlug.html", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/headingAsTitle.md", }, "path": "/docs/headingAsTitle", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/rootResolvedSlug.md", }, "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/ipsum.md", }, "path": "/docs/ipsum", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/lorem.md", }, "path": "/docs/lorem", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/rootAbsoluteSlug.md", }, "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/rootRelativeSlug.md", }, "path": "/docs/rootRelativeSlug", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/rootTryToEscapeSlug.md", }, "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/resolvedSlug.md", }, "path": "/docs/slugs/hey/resolvedSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/relativeSlug.md", }, "path": "/docs/slugs/relativeSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/tryToEscapeSlug.md", }, "path": "/docs/tryToEscapeSlug", @@ -1264,7 +1264,7 @@ Array [ `; exports[`simple website getPathToWatch 1`] = ` -Array [ +[ "sidebars.json", "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", "docs/**/*.{md,mdx}", @@ -1273,13 +1273,13 @@ Array [ `; exports[`site with custom sidebar items generator sidebar is autogenerated according to a custom sidebarItemsGenerator 1`] = ` -Object { - "defaultSidebar": Array [ - Object { +{ + "defaultSidebar": [ + { "id": "API/api-overview", "type": "doc", }, - Object { + { "id": "API/api-end", "type": "doc", }, @@ -1288,25 +1288,25 @@ Object { `; exports[`site with custom sidebar items generator sidebarItemsGenerator can wrap/enhance/sort/reverse the default sidebar generator 1`] = ` -Object { - "defaultSidebar": Array [ - Object { +{ + "defaultSidebar": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/api-end", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Extension APIs/Theme API", "type": "doc", }, - Object { + { "id": "API/Extension APIs/Plugin API", "type": "doc", }, @@ -1315,15 +1315,15 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Core APIs/Server API", "type": "doc", }, - Object { + { "id": "API/Core APIs/Client API", "type": "doc", }, @@ -1332,7 +1332,7 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "API/api-overview", "type": "doc", }, @@ -1341,31 +1341,31 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "Guides/guide5", "type": "doc", }, - Object { + { "id": "Guides/guide4", "type": "doc", }, - Object { + { "id": "Guides/guide3", "type": "doc", }, - Object { + { "id": "Guides/guide2.5", "type": "doc", }, - Object { + { "id": "Guides/guide2", "type": "doc", }, - Object { + { "id": "Guides/guide1", "type": "doc", }, @@ -1374,11 +1374,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "installation", "type": "doc", }, - Object { + { "id": "getting-started", "type": "doc", }, @@ -1387,70 +1387,70 @@ Object { `; exports[`site with custom sidebar items generator sidebarItemsGenerator is called with appropriate data 1`] = ` -Object { - "categoriesMetadata": Object { - "3-API": Object { +{ + "categoriesMetadata": { + "3-API": { "label": "API (label from _category_.json)", }, - "3-API/02_Extension APIs": Object { + "3-API/02_Extension APIs": { "label": "Extension APIs (label from _category_.yml)", }, - "Guides": Object { + "Guides": { "position": 2, }, }, "defaultSidebarItemsGenerator": [Function], - "docs": Array [ - Object { - "frontMatter": Object {}, + "docs": [ + { + "frontMatter": {}, "id": "API/Core APIs/Client API", "sidebarPosition": 0, "source": "@site/docs/3-API/01_Core APIs/0 --- Client API.md", "sourceDirName": "3-API/01_Core APIs", "unversionedId": "API/Core APIs/Client API", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "API/Core APIs/Server API", "sidebarPosition": 1, "source": "@site/docs/3-API/01_Core APIs/1 --- Server API.md", "sourceDirName": "3-API/01_Core APIs", "unversionedId": "API/Core APIs/Server API", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "API/Extension APIs/Plugin API", "sidebarPosition": 0, "source": "@site/docs/3-API/02_Extension APIs/0. Plugin API.md", "sourceDirName": "3-API/02_Extension APIs", "unversionedId": "API/Extension APIs/Plugin API", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "API/Extension APIs/Theme API", "sidebarPosition": 1, "source": "@site/docs/3-API/02_Extension APIs/1. Theme API.md", "sourceDirName": "3-API/02_Extension APIs", "unversionedId": "API/Extension APIs/Theme API", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "API/api-end", "sidebarPosition": 3, "source": "@site/docs/3-API/03_api-end.md", "sourceDirName": "3-API", "unversionedId": "API/api-end", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "API/api-overview", "sidebarPosition": 0, "source": "@site/docs/3-API/00_api-overview.md", "sourceDirName": "3-API", "unversionedId": "API/api-overview", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide1", "sidebar_position": 1, }, @@ -1460,8 +1460,8 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide1", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide2", }, "id": "Guides/guide2", @@ -1470,8 +1470,8 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide2", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide2.5", "sidebar_position": 2.5, }, @@ -1481,8 +1481,8 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide2.5", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide3", "sidebar_position": 3, }, @@ -1492,8 +1492,8 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide3", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide4", }, "id": "Guides/guide4", @@ -1502,8 +1502,8 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide4", }, - Object { - "frontMatter": Object { + { + "frontMatter": { "id": "guide5", }, "id": "Guides/guide5", @@ -1512,16 +1512,16 @@ Object { "sourceDirName": "Guides", "unversionedId": "Guides/guide5", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "getting-started", "sidebarPosition": 0, "source": "@site/docs/0-getting-started.md", "sourceDirName": ".", "unversionedId": "getting-started", }, - Object { - "frontMatter": Object {}, + { + "frontMatter": {}, "id": "installation", "sidebarPosition": 1, "source": "@site/docs/1-installation.md", @@ -1530,16 +1530,16 @@ Object { }, ], "isCategoryIndex": [Function], - "item": Object { + "item": { "dirName": ".", "type": "autogenerated", }, "numberPrefixParser": [Function], - "options": Object { + "options": { "sidebarCollapsed": true, "sidebarCollapsible": true, }, - "version": Object { + "version": { "contentPath": "docs", "versionName": "current", }, @@ -1547,15 +1547,15 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 1`] = ` -Object { +{ "description": "Getting started text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "getting-started", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/installation", "title": "Installation", }, @@ -1566,7 +1566,7 @@ Object { "slug": "/getting-started", "source": "@site/docs/0-getting-started.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "Getting Started", "unversionedId": "getting-started", "version": "current", @@ -1574,20 +1574,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 2`] = ` -Object { +{ "description": "Installation text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "installation", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide1", "title": "Guide 1", }, "permalink": "/docs/installation", - "previous": Object { + "previous": { "permalink": "/docs/getting-started", "title": "Getting Started", }, @@ -1596,7 +1596,7 @@ Object { "slug": "/installation", "source": "@site/docs/1-installation.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "Installation", "unversionedId": "installation", "version": "current", @@ -1604,23 +1604,23 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 3`] = ` -Object { +{ "description": "Guide 1 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide1", "sidebar_position": 1, }, "id": "Guides/guide1", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide2", "title": "Guide 2", }, "permalink": "/docs/Guides/guide1", - "previous": Object { + "previous": { "permalink": "/docs/installation", "title": "Installation", }, @@ -1629,7 +1629,7 @@ Object { "slug": "/Guides/guide1", "source": "@site/docs/Guides/z-guide1.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 1", "unversionedId": "Guides/guide1", "version": "current", @@ -1637,22 +1637,22 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 4`] = ` -Object { +{ "description": "Guide 2 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide2", }, "id": "Guides/guide2", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide2.5", "title": "Guide 2.5", }, "permalink": "/docs/Guides/guide2", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide1", "title": "Guide 1", }, @@ -1661,7 +1661,7 @@ Object { "slug": "/Guides/guide2", "source": "@site/docs/Guides/02-guide2.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 2", "unversionedId": "Guides/guide2", "version": "current", @@ -1669,23 +1669,23 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 5`] = ` -Object { +{ "description": "Guide 2.5 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide2.5", "sidebar_position": 2.5, }, "id": "Guides/guide2.5", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide3", "title": "Guide 3", }, "permalink": "/docs/Guides/guide2.5", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide2", "title": "Guide 2", }, @@ -1694,7 +1694,7 @@ Object { "slug": "/Guides/guide2.5", "source": "@site/docs/Guides/0-guide2.5.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 2.5", "unversionedId": "Guides/guide2.5", "version": "current", @@ -1702,23 +1702,23 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 6`] = ` -Object { +{ "description": "Guide 3 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide3", "sidebar_position": 3, }, "id": "Guides/guide3", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide4", "title": "Guide 4", }, "permalink": "/docs/Guides/guide3", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide2.5", "title": "Guide 2.5", }, @@ -1727,7 +1727,7 @@ Object { "slug": "/Guides/guide3", "source": "@site/docs/Guides/guide3.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 3", "unversionedId": "Guides/guide3", "version": "current", @@ -1735,22 +1735,22 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 7`] = ` -Object { +{ "description": "Guide 4 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide4", }, "id": "Guides/guide4", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/Guides/guide5", "title": "Guide 5", }, "permalink": "/docs/Guides/guide4", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide3", "title": "Guide 3", }, @@ -1759,7 +1759,7 @@ Object { "slug": "/Guides/guide4", "source": "@site/docs/Guides/a-guide4.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 4", "unversionedId": "Guides/guide4", "version": "current", @@ -1767,22 +1767,22 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 8`] = ` -Object { +{ "description": "Guide 5 text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "id": "guide5", }, "id": "Guides/guide5", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/api-overview", "title": "API Overview", }, "permalink": "/docs/Guides/guide5", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide4", "title": "Guide 4", }, @@ -1791,7 +1791,7 @@ Object { "slug": "/Guides/guide5", "source": "@site/docs/Guides/b-guide5.md", "sourceDirName": "Guides", - "tags": Array [], + "tags": [], "title": "Guide 5", "unversionedId": "Guides/guide5", "version": "current", @@ -1799,20 +1799,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 9`] = ` -Object { +{ "description": "API Overview text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/api-overview", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Core APIs/Client API", "title": "Client API", }, "permalink": "/docs/API/api-overview", - "previous": Object { + "previous": { "permalink": "/docs/Guides/guide5", "title": "Guide 5", }, @@ -1821,7 +1821,7 @@ Object { "slug": "/API/api-overview", "source": "@site/docs/3-API/00_api-overview.md", "sourceDirName": "3-API", - "tags": Array [], + "tags": [], "title": "API Overview", "unversionedId": "API/api-overview", "version": "current", @@ -1829,20 +1829,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 10`] = ` -Object { +{ "description": "Client API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Core APIs/Client API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Core APIs/Server API", "title": "Server API", }, "permalink": "/docs/API/Core APIs/Client API", - "previous": Object { + "previous": { "permalink": "/docs/API/api-overview", "title": "API Overview", }, @@ -1851,7 +1851,7 @@ Object { "slug": "/API/Core APIs/Client API", "source": "@site/docs/3-API/01_Core APIs/0 --- Client API.md", "sourceDirName": "3-API/01_Core APIs", - "tags": Array [], + "tags": [], "title": "Client API", "unversionedId": "API/Core APIs/Client API", "version": "current", @@ -1859,20 +1859,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 11`] = ` -Object { +{ "description": "Server API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Core APIs/Server API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Extension APIs/Plugin API", "title": "Plugin API", }, "permalink": "/docs/API/Core APIs/Server API", - "previous": Object { + "previous": { "permalink": "/docs/API/Core APIs/Client API", "title": "Client API", }, @@ -1881,7 +1881,7 @@ Object { "slug": "/API/Core APIs/Server API", "source": "@site/docs/3-API/01_Core APIs/1 --- Server API.md", "sourceDirName": "3-API/01_Core APIs", - "tags": Array [], + "tags": [], "title": "Server API", "unversionedId": "API/Core APIs/Server API", "version": "current", @@ -1889,20 +1889,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 12`] = ` -Object { +{ "description": "Plugin API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Extension APIs/Plugin API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Extension APIs/Theme API", "title": "Theme API", }, "permalink": "/docs/API/Extension APIs/Plugin API", - "previous": Object { + "previous": { "permalink": "/docs/API/Core APIs/Server API", "title": "Server API", }, @@ -1911,7 +1911,7 @@ Object { "slug": "/API/Extension APIs/Plugin API", "source": "@site/docs/3-API/02_Extension APIs/0. Plugin API.md", "sourceDirName": "3-API/02_Extension APIs", - "tags": Array [], + "tags": [], "title": "Plugin API", "unversionedId": "API/Extension APIs/Plugin API", "version": "current", @@ -1919,20 +1919,20 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 13`] = ` -Object { +{ "description": "Theme API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Extension APIs/Theme API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/api-end", "title": "API End", }, "permalink": "/docs/API/Extension APIs/Theme API", - "previous": Object { + "previous": { "permalink": "/docs/API/Extension APIs/Plugin API", "title": "Plugin API", }, @@ -1941,7 +1941,7 @@ Object { "slug": "/API/Extension APIs/Theme API", "source": "@site/docs/3-API/02_Extension APIs/1. Theme API.md", "sourceDirName": "3-API/02_Extension APIs", - "tags": Array [], + "tags": [], "title": "Theme API", "unversionedId": "API/Extension APIs/Theme API", "version": "current", @@ -1949,17 +1949,17 @@ Object { `; exports[`site with full autogenerated sidebar docs in fully generated sidebar have correct metadata 14`] = ` -Object { +{ "description": "API End text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/api-end", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, "next": undefined, "permalink": "/docs/API/api-end", - "previous": Object { + "previous": { "permalink": "/docs/API/Extension APIs/Theme API", "title": "Theme API", }, @@ -1968,7 +1968,7 @@ Object { "slug": "/API/api-end", "source": "@site/docs/3-API/03_api-end.md", "sourceDirName": "3-API", - "tags": Array [], + "tags": [], "title": "API End", "unversionedId": "API/api-end", "version": "current", @@ -1976,41 +1976,41 @@ Object { `; exports[`site with full autogenerated sidebar sidebar is fully autogenerated 1`] = ` -Object { - "defaultSidebar": Array [ - Object { +{ + "defaultSidebar": [ + { "id": "getting-started", "type": "doc", }, - Object { + { "id": "installation", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "Guides/guide1", "type": "doc", }, - Object { + { "id": "Guides/guide2", "type": "doc", }, - Object { + { "id": "Guides/guide2.5", "type": "doc", }, - Object { + { "id": "Guides/guide3", "type": "doc", }, - Object { + { "id": "Guides/guide4", "type": "doc", }, - Object { + { "id": "Guides/guide5", "type": "doc", }, @@ -2019,23 +2019,23 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/api-overview", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Core APIs/Client API", "type": "doc", }, - Object { + { "id": "API/Core APIs/Server API", "type": "doc", }, @@ -2044,15 +2044,15 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Extension APIs/Plugin API", "type": "doc", }, - Object { + { "id": "API/Extension APIs/Theme API", "type": "doc", }, @@ -2061,7 +2061,7 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "API/api-end", "type": "doc", }, @@ -2075,25 +2075,25 @@ Object { `; exports[`site with partial autogenerated sidebars 2 (fix #4638) sidebar is partially autogenerated 1`] = ` -Object { - "someSidebar": Array [ - Object { +{ + "someSidebar": [ + { "id": "API/api-end", "type": "doc", }, - Object { + { "id": "API/api-overview", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Core APIs/Client API", "type": "doc", }, - Object { + { "id": "API/Core APIs/Server API", "type": "doc", }, @@ -2102,15 +2102,15 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/Extension APIs/Plugin API", "type": "doc", }, - Object { + { "id": "API/Extension APIs/Theme API", "type": "doc", }, @@ -2119,7 +2119,7 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "API/api-end", "type": "doc", }, @@ -2128,15 +2128,15 @@ Object { `; exports[`site with partial autogenerated sidebars docs in partially generated sidebar have correct metadata 1`] = ` -Object { +{ "description": "API End text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/api-end", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/api-overview", "title": "API Overview", }, @@ -2147,7 +2147,7 @@ Object { "slug": "/API/api-end", "source": "@site/docs/3-API/03_api-end.md", "sourceDirName": "3-API", - "tags": Array [], + "tags": [], "title": "API End", "unversionedId": "API/api-end", "version": "current", @@ -2155,20 +2155,20 @@ Object { `; exports[`site with partial autogenerated sidebars docs in partially generated sidebar have correct metadata 2`] = ` -Object { +{ "description": "API Overview text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/api-overview", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Extension APIs/Plugin API", "title": "Plugin API", }, "permalink": "/docs/API/api-overview", - "previous": Object { + "previous": { "permalink": "/docs/API/api-end", "title": "API End", }, @@ -2177,7 +2177,7 @@ Object { "slug": "/API/api-overview", "source": "@site/docs/3-API/00_api-overview.md", "sourceDirName": "3-API", - "tags": Array [], + "tags": [], "title": "API Overview", "unversionedId": "API/api-overview", "version": "current", @@ -2185,20 +2185,20 @@ Object { `; exports[`site with partial autogenerated sidebars docs in partially generated sidebar have correct metadata 3`] = ` -Object { +{ "description": "Plugin API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Extension APIs/Plugin API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/API/Extension APIs/Theme API", "title": "Theme API", }, "permalink": "/docs/API/Extension APIs/Plugin API", - "previous": Object { + "previous": { "permalink": "/docs/API/api-overview", "title": "API Overview", }, @@ -2207,7 +2207,7 @@ Object { "slug": "/API/Extension APIs/Plugin API", "source": "@site/docs/3-API/02_Extension APIs/0. Plugin API.md", "sourceDirName": "3-API/02_Extension APIs", - "tags": Array [], + "tags": [], "title": "Plugin API", "unversionedId": "API/Extension APIs/Plugin API", "version": "current", @@ -2215,17 +2215,17 @@ Object { `; exports[`site with partial autogenerated sidebars docs in partially generated sidebar have correct metadata 4`] = ` -Object { +{ "description": "Theme API text", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "API/Extension APIs/Theme API", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, "next": undefined, "permalink": "/docs/API/Extension APIs/Theme API", - "previous": Object { + "previous": { "permalink": "/docs/API/Extension APIs/Plugin API", "title": "Plugin API", }, @@ -2234,7 +2234,7 @@ Object { "slug": "/API/Extension APIs/Theme API", "source": "@site/docs/3-API/02_Extension APIs/1. Theme API.md", "sourceDirName": "3-API/02_Extension APIs", - "tags": Array [], + "tags": [], "title": "Theme API", "unversionedId": "API/Extension APIs/Theme API", "version": "current", @@ -2242,25 +2242,25 @@ Object { `; exports[`site with partial autogenerated sidebars sidebar is partially autogenerated 1`] = ` -Object { - "someSidebar": Array [ - Object { +{ + "someSidebar": [ + { "id": "API/api-end", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "API/api-overview", "type": "doc", }, - Object { + { "id": "API/Extension APIs/Plugin API", "type": "doc", }, - Object { + { "id": "API/Extension APIs/Theme API", "type": "doc", }, @@ -2274,11 +2274,11 @@ Object { `; exports[`versioned website (community) content 1`] = ` -Object { +{ "description": "Team current version (translated)", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "title": "Team title translated", }, "id": "team", @@ -2292,7 +2292,7 @@ Object { "slug": "/team", "source": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "Team title translated", "unversionedId": "team", "version": "current", @@ -2300,11 +2300,11 @@ Object { `; exports[`versioned website (community) content 2`] = ` -Object { +{ "description": "Team 1.0.0", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "version-1.0.0/team", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, @@ -2316,7 +2316,7 @@ Object { "slug": "/team", "source": "@site/community_versioned_docs/version-1.0.0/team.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "team", "unversionedId": "team", "version": "1.0.0", @@ -2324,9 +2324,9 @@ Object { `; exports[`versioned website (community) content: 100 version sidebars 1`] = ` -Object { - "version-1.0.0/community": Array [ - Object { +{ + "version-1.0.0/community": [ + { "id": "version-1.0.0/team", "type": "doc", }, @@ -2335,9 +2335,9 @@ Object { `; exports[`versioned website (community) content: current version sidebars 1`] = ` -Object { - "community": Array [ - Object { +{ + "community": [ + { "id": "team", "type": "doc", }, @@ -2346,7 +2346,7 @@ Object { `; exports[`versioned website (community) content: data 1`] = ` -Object { +{ "site-community-versioned-docs-version-1-0-0-team-md-359.json": "{ \\"unversionedId\\": \\"team\\", \\"id\\": \\"version-1.0.0/team\\", @@ -2435,15 +2435,15 @@ Object { `; exports[`versioned website (community) content: global data 1`] = ` -Object { - "pluginName": Object { - "pluginId": Object { +{ + "pluginName": { + "pluginId": { "breadcrumbs": true, "path": "/community", - "versions": Array [ - Object { - "docs": Array [ - Object { + "versions": [ + { + "docs": [ + { "id": "team", "path": "/community/next/team", "sidebar": "community", @@ -2454,18 +2454,18 @@ Object { "mainDocId": "team", "name": "current", "path": "/community/next", - "sidebars": Object { - "community": Object { - "link": Object { + "sidebars": { + "community": { + "link": { "label": "team", "path": "/community/next/team", }, }, }, }, - Object { - "docs": Array [ - Object { + { + "docs": [ + { "id": "team", "path": "/community/team", "sidebar": "version-1.0.0/community", @@ -2476,9 +2476,9 @@ Object { "mainDocId": "team", "name": "1.0.0", "path": "/community", - "sidebars": Object { - "version-1.0.0/community": Object { - "link": Object { + "sidebars": { + "version-1.0.0/community": { + "link": { "label": "version-1.0.0/team", "path": "/community/team", }, @@ -2492,20 +2492,20 @@ Object { `; exports[`versioned website (community) content: route config 1`] = ` -Array [ - Object { +[ + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-current-metadata-prop-751.json", }, "path": "/community/next", "priority": undefined, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", }, "path": "/community/next/team", @@ -2513,19 +2513,19 @@ Array [ }, ], }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-1-0-0-metadata-prop-608.json", }, "path": "/community", "priority": -1, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/community_versioned_docs/version-1.0.0/team.md", }, "path": "/community/team", @@ -2537,7 +2537,7 @@ Array [ `; exports[`versioned website (community) getPathToWatch 1`] = ` -Array [ +[ "community_sidebars.json", "i18n/en/docusaurus-plugin-content-docs-community/current/**/*.{md,mdx}", "community/**/*.{md,mdx}", @@ -2550,16 +2550,16 @@ Array [ `; exports[`versioned website content 1`] = ` -Object { +{ "description": "This is next version of bar.", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "slug": "barSlug", - "tags": Array [ + "tags": [ "barTag 1", "barTag-2", - Object { + { "label": "barTag 3", "permalink": "barTag-3-permalink", }, @@ -2568,7 +2568,7 @@ Object { "id": "foo/bar", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/next/", "title": "hello", }, @@ -2579,16 +2579,16 @@ Object { "slug": "/foo/barSlug", "source": "@site/docs/foo/bar.md", "sourceDirName": "foo", - "tags": Array [ - Object { + "tags": [ + { "label": "barTag 1", "permalink": "/docs/next/tags/bar-tag-1", }, - Object { + { "label": "barTag-2", "permalink": "/docs/next/tags/bar-tag-2", }, - Object { + { "label": "barTag 3", "permalink": "/docs/next/tags/barTag-3-permalink", }, @@ -2600,15 +2600,15 @@ Object { `; exports[`versioned website content 2`] = ` -Object { +{ "description": "Bar 1.0.1 !", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "version-1.0.1/foo/bar", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/", "title": "hello", }, @@ -2619,7 +2619,7 @@ Object { "slug": "/foo/bar", "source": "@site/versioned_docs/version-1.0.1/foo/bar.md", "sourceDirName": "foo", - "tags": Array [], + "tags": [], "title": "bar", "unversionedId": "foo/bar", "version": "1.0.1", @@ -2627,11 +2627,11 @@ Object { `; exports[`versioned website content 3`] = ` -Object { +{ "description": "Hello next !", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "slug": "/", }, "id": "hello", @@ -2639,7 +2639,7 @@ Object { "lastUpdatedBy": undefined, "next": undefined, "permalink": "/docs/next/", - "previous": Object { + "previous": { "permalink": "/docs/next/foo/barSlug", "title": "bar", }, @@ -2648,7 +2648,7 @@ Object { "slug": "/", "source": "@site/docs/hello.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "hello", "unversionedId": "hello", "version": "current", @@ -2656,11 +2656,11 @@ Object { `; exports[`versioned website content 4`] = ` -Object { +{ "description": "Hello 1.0.1 !", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object { + "frontMatter": { "slug": "/", }, "id": "version-1.0.1/hello", @@ -2668,7 +2668,7 @@ Object { "lastUpdatedBy": undefined, "next": undefined, "permalink": "/docs/", - "previous": Object { + "previous": { "permalink": "/docs/foo/bar", "title": "bar", }, @@ -2677,7 +2677,7 @@ Object { "slug": "/", "source": "@site/versioned_docs/version-1.0.1/hello.md", "sourceDirName": ".", - "tags": Array [], + "tags": [], "title": "hello", "unversionedId": "hello", "version": "1.0.1", @@ -2685,20 +2685,20 @@ Object { `; exports[`versioned website content 5`] = ` -Object { +{ "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", "editUrl": undefined, "formattedLastUpdatedAt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, "id": "version-1.0.0/foo/baz", "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "next": Object { + "next": { "permalink": "/docs/1.0.0/", "title": "hello", }, "permalink": "/docs/1.0.0/foo/baz", - "previous": Object { + "previous": { "permalink": "/docs/1.0.0/foo/barSlug", "title": "bar", }, @@ -2707,7 +2707,7 @@ Object { "slug": "/foo/baz", "source": "@site/versioned_docs/version-1.0.0/foo/baz.md", "sourceDirName": "foo", - "tags": Array [], + "tags": [], "title": "baz", "unversionedId": "foo/baz", "version": "1.0.0", @@ -2715,17 +2715,17 @@ Object { `; exports[`versioned website content: 100 version sidebars 1`] = ` -Object { - "version-1.0.0/docs": Array [ - Object { +{ + "version-1.0.0/docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "version-1.0.0/foo/bar", "type": "doc", }, - Object { + { "id": "version-1.0.0/foo/baz", "type": "doc", }, @@ -2734,11 +2734,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "version-1.0.0/hello", "type": "doc", }, @@ -2752,13 +2752,13 @@ Object { `; exports[`versioned website content: 101 version sidebars 1`] = ` -Object { - "VersionedSideBarNameDoesNotMatter/docs": Array [ - Object { +{ + "VersionedSideBarNameDoesNotMatter/docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "foo/bar", "type": "doc", }, @@ -2767,11 +2767,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "version-1.0.1/hello", "type": "doc", }, @@ -2785,13 +2785,13 @@ Object { `; exports[`versioned website content: current version sidebars 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "foo/bar", "type": "doc", }, @@ -2800,11 +2800,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "hello", "type": "doc", }, @@ -2818,7 +2818,7 @@ Object { `; exports[`versioned website content: data 1`] = ` -Object { +{ "site-docs-foo-bar-md-8c2.json": "{ \\"unversionedId\\": \\"foo/bar\\", \\"id\\": \\"foo/bar\\", @@ -3488,40 +3488,40 @@ Object { `; exports[`versioned website content: global data 1`] = ` -Object { - "pluginName": Object { - "pluginId": Object { +{ + "pluginName": { + "pluginId": { "breadcrumbs": true, "path": "/docs", - "versions": Array [ - Object { - "docs": Array [ - Object { + "versions": [ + { + "docs": [ + { "id": "foo/bar", "path": "/docs/next/foo/barSlug", "sidebar": "docs", }, - Object { + { "id": "hello", "path": "/docs/next/", "sidebar": "docs", }, - Object { + { "id": "slugs/absoluteSlug", "path": "/docs/next/absoluteSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/relativeSlug", "path": "/docs/next/slugs/relativeSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/resolvedSlug", "path": "/docs/next/slugs/hey/resolvedSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/tryToEscapeSlug", "path": "/docs/next/tryToEscapeSlug", "sidebar": undefined, @@ -3532,23 +3532,23 @@ Object { "mainDocId": "hello", "name": "current", "path": "/docs/next", - "sidebars": Object { - "docs": Object { - "link": Object { + "sidebars": { + "docs": { + "link": { "label": "foo/bar", "path": "/docs/next/foo/barSlug", }, }, }, }, - Object { - "docs": Array [ - Object { + { + "docs": [ + { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", }, - Object { + { "id": "hello", "path": "/docs/", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", @@ -3559,28 +3559,28 @@ Object { "mainDocId": "hello", "name": "1.0.1", "path": "/docs", - "sidebars": Object { - "VersionedSideBarNameDoesNotMatter/docs": Object { - "link": Object { + "sidebars": { + "VersionedSideBarNameDoesNotMatter/docs": { + "link": { "label": "foo/bar", "path": "/docs/foo/bar", }, }, }, }, - Object { - "docs": Array [ - Object { + { + "docs": [ + { "id": "foo/bar", "path": "/docs/1.0.0/foo/barSlug", "sidebar": "version-1.0.0/docs", }, - Object { + { "id": "foo/baz", "path": "/docs/1.0.0/foo/baz", "sidebar": "version-1.0.0/docs", }, - Object { + { "id": "hello", "path": "/docs/1.0.0/", "sidebar": "version-1.0.0/docs", @@ -3591,53 +3591,53 @@ Object { "mainDocId": "hello", "name": "1.0.0", "path": "/docs/1.0.0", - "sidebars": Object { - "version-1.0.0/docs": Object { - "link": Object { + "sidebars": { + "version-1.0.0/docs": { + "link": { "label": "version-1.0.0/foo/bar", "path": "/docs/1.0.0/foo/barSlug", }, }, }, }, - Object { - "docs": Array [ - Object { + { + "docs": [ + { "id": "rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug", "sidebar": "version-1.0.1/docs", }, - Object { + { "id": "rootRelativeSlug", "path": "/docs/withSlugs/rootRelativeSlug", "sidebar": undefined, }, - Object { + { "id": "rootResolvedSlug", "path": "/docs/withSlugs/hey/rootResolvedSlug", "sidebar": undefined, }, - Object { + { "id": "rootTryToEscapeSlug", "path": "/docs/withSlugs/rootTryToEscapeSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/absoluteSlug", "path": "/docs/withSlugs/absoluteSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/relativeSlug", "path": "/docs/withSlugs/slugs/relativeSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/resolvedSlug", "path": "/docs/withSlugs/slugs/hey/resolvedSlug", "sidebar": undefined, }, - Object { + { "id": "slugs/tryToEscapeSlug", "path": "/docs/withSlugs/tryToEscapeSlug", "sidebar": undefined, @@ -3648,9 +3648,9 @@ Object { "mainDocId": "rootAbsoluteSlug", "name": "withSlugs", "path": "/docs/withSlugs", - "sidebars": Object { - "version-1.0.1/docs": Object { - "link": Object { + "sidebars": { + "version-1.0.1/docs": { + "link": { "label": "version-withSlugs/rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug", }, @@ -3664,70 +3664,70 @@ Object { `; exports[`versioned website content: route config 1`] = ` -Array [ - Object { +[ + { "component": "@theme/DocTagsListPage", "exact": true, - "modules": Object { + "modules": { "tags": "~docs/tags-list-current-prop-15a.json", }, "path": "/docs/next/tags", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json", }, "path": "/docs/next/tags/bar-tag-1", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json", }, "path": "/docs/next/tags/bar-tag-2", }, - Object { + { "component": "@theme/DocTagDocListPage", "exact": true, - "modules": Object { + "modules": { "tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json", }, "path": "/docs/next/tags/barTag-3-permalink", }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-1-0-0-metadata-prop-608.json", }, "path": "/docs/1.0.0", "priority": undefined, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", }, "path": "/docs/1.0.0/", "sidebar": "version-1.0.0/docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-1.0.0/foo/bar.md", }, "path": "/docs/1.0.0/foo/barSlug", "sidebar": "version-1.0.0/docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-1.0.0/foo/baz.md", }, "path": "/docs/1.0.0/foo/baz", @@ -3735,165 +3735,165 @@ Array [ }, ], }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-current-metadata-prop-751.json", }, "path": "/docs/next", "priority": undefined, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/hello.md", }, "path": "/docs/next/", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/absoluteSlug.md", }, "path": "/docs/next/absoluteSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/foo/bar.md", }, "path": "/docs/next/foo/barSlug", "sidebar": "docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/resolvedSlug.md", }, "path": "/docs/next/slugs/hey/resolvedSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/relativeSlug.md", }, "path": "/docs/next/slugs/relativeSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/docs/slugs/tryToEscapeSlug.md", }, "path": "/docs/next/tryToEscapeSlug", }, ], }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-with-slugs-metadata-prop-2bf.json", }, "path": "/docs/withSlugs", "priority": undefined, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", }, "path": "/docs/withSlugs/absoluteSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", }, "path": "/docs/withSlugs/hey/rootResolvedSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", }, "path": "/docs/withSlugs/rootAbsoluteSlug", "sidebar": "version-1.0.1/docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", }, "path": "/docs/withSlugs/rootRelativeSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", }, "path": "/docs/withSlugs/rootTryToEscapeSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", }, "path": "/docs/withSlugs/slugs/hey/resolvedSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", }, "path": "/docs/withSlugs/slugs/relativeSlug", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", }, "path": "/docs/withSlugs/tryToEscapeSlug", }, ], }, - Object { + { "component": "@theme/DocPage", "exact": false, - "modules": Object { + "modules": { "versionMetadata": "~docs/version-1-0-1-metadata-prop-e87.json", }, "path": "/docs", "priority": -1, - "routes": Array [ - Object { + "routes": [ + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-1.0.1/hello.md", }, "path": "/docs/", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", }, - Object { + { "component": "@theme/DocItem", "exact": true, - "modules": Object { + "modules": { "content": "@site/versioned_docs/version-1.0.1/foo/bar.md", }, "path": "/docs/foo/bar", @@ -3905,13 +3905,13 @@ Array [ `; exports[`versioned website content: withSlugs version sidebars 1`] = ` -Object { - "version-1.0.1/docs": Array [ - Object { +{ + "version-1.0.1/docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "version-withSlugs/rootAbsoluteSlug", "type": "doc", }, @@ -3925,7 +3925,7 @@ Object { `; exports[`versioned website getPathToWatch 1`] = ` -Array [ +[ "sidebars.json", "i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}", "docs/**/*.{md,mdx}", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap index 62fceab793f3..30c85bc511e0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,76 +1,76 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`getLoadedContentTranslationFiles returns translation files 1`] = ` -Array [ - Object { - "content": Object { - "sidebar.docs.category.Getting started": Object { +[ + { + "content": { + "sidebar.docs.category.Getting started": { "description": "The label for category Getting started in sidebar docs", "message": "Getting started", }, - "sidebar.docs.category.Getting started.link.generated-index.description": Object { + "sidebar.docs.category.Getting started.link.generated-index.description": { "description": "The generated-index page description for category Getting started in sidebar docs", "message": "Getting started index description", }, - "sidebar.docs.category.Getting started.link.generated-index.title": Object { + "sidebar.docs.category.Getting started.link.generated-index.title": { "description": "The generated-index page title for category Getting started in sidebar docs", "message": "Getting started index title", }, - "sidebar.docs.link.Link label": Object { + "sidebar.docs.link.Link label": { "description": "The label for link Link label in sidebar docs, linking to https://facebook.com", "message": "Link label", }, - "version.label": Object { + "version.label": { "description": "The label for version current", "message": "current label", }, }, "path": "current", }, - Object { - "content": Object { - "sidebar.docs.category.Getting started": Object { + { + "content": { + "sidebar.docs.category.Getting started": { "description": "The label for category Getting started in sidebar docs", "message": "Getting started", }, - "sidebar.docs.category.Getting started.link.generated-index.description": Object { + "sidebar.docs.category.Getting started.link.generated-index.description": { "description": "The generated-index page description for category Getting started in sidebar docs", "message": "Getting started index description", }, - "sidebar.docs.category.Getting started.link.generated-index.title": Object { + "sidebar.docs.category.Getting started.link.generated-index.title": { "description": "The generated-index page title for category Getting started in sidebar docs", "message": "Getting started index title", }, - "sidebar.docs.link.Link label": Object { + "sidebar.docs.link.Link label": { "description": "The label for link Link label in sidebar docs, linking to https://facebook.com", "message": "Link label", }, - "version.label": Object { + "version.label": { "description": "The label for version 2.0.0", "message": "2.0.0 label", }, }, "path": "version-2.0.0", }, - Object { - "content": Object { - "sidebar.docs.category.Getting started": Object { + { + "content": { + "sidebar.docs.category.Getting started": { "description": "The label for category Getting started in sidebar docs", "message": "Getting started", }, - "sidebar.docs.category.Getting started.link.generated-index.description": Object { + "sidebar.docs.category.Getting started.link.generated-index.description": { "description": "The generated-index page description for category Getting started in sidebar docs", "message": "Getting started index description", }, - "sidebar.docs.category.Getting started.link.generated-index.title": Object { + "sidebar.docs.category.Getting started.link.generated-index.title": { "description": "The generated-index page title for category Getting started in sidebar docs", "message": "Getting started index title", }, - "sidebar.docs.link.Link label": Object { + "sidebar.docs.link.Link label": { "description": "The label for link Link label in sidebar docs, linking to https://facebook.com", "message": "Link label", }, - "version.label": Object { + "version.label": { "description": "The label for version 1.0.0", "message": "1.0.0 label", }, @@ -81,13 +81,13 @@ Array [ `; exports[`translateLoadedContent returns translated loaded content 1`] = ` -Object { - "loadedVersions": Array [ - Object { +{ + "loadedVersions": [ + { "contentPath": "any", "contentPathLocalized": "any", - "docs": Array [ - Object { + "docs": [ + { "description": "doc1 description", "editUrl": "any", "id": "doc1", @@ -103,7 +103,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc2 description", "editUrl": "any", "id": "doc2", @@ -119,7 +119,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc3 description", "editUrl": "any", "id": "doc3", @@ -135,7 +135,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc4 description", "editUrl": "any", "id": "doc4", @@ -151,7 +151,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc5 description", "editUrl": "any", "id": "doc5", @@ -172,31 +172,31 @@ Object { "mainDocId": "", "routePriority": undefined, "sidebarFilePath": "any", - "sidebars": Object { - "docs": Array [ - Object { + "sidebars": { + "docs": [ + { "collapsed": false, - "items": Array [ - Object { + "items": [ + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, - Object { + { "href": "https://facebook.com", "label": "Link label (translated)", "type": "link", }, - Object { + { "id": "doc1", "type": "ref", }, ], "label": "Getting started (translated)", - "link": Object { + "link": { "description": "Getting started index description (translated)", "permalink": "/docs/category/getting-started-index-slug", "slug": "/category/getting-started-index-slug", @@ -205,17 +205,17 @@ Object { }, "type": "category", }, - Object { + { "id": "doc3", "type": "doc", }, ], - "otherSidebar": Array [ - Object { + "otherSidebar": [ + { "id": "doc4", "type": "doc", }, - Object { + { "id": "doc5", "type": "doc", }, @@ -225,11 +225,11 @@ Object { "versionName": "current", "versionPath": "/docs/", }, - Object { + { "contentPath": "any", "contentPathLocalized": "any", - "docs": Array [ - Object { + "docs": [ + { "description": "doc1 description", "editUrl": "any", "id": "doc1", @@ -245,7 +245,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc2 description", "editUrl": "any", "id": "doc2", @@ -261,7 +261,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc3 description", "editUrl": "any", "id": "doc3", @@ -277,7 +277,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc4 description", "editUrl": "any", "id": "doc4", @@ -293,7 +293,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc5 description", "editUrl": "any", "id": "doc5", @@ -314,31 +314,31 @@ Object { "mainDocId": "", "routePriority": undefined, "sidebarFilePath": "any", - "sidebars": Object { - "docs": Array [ - Object { + "sidebars": { + "docs": [ + { "collapsed": false, - "items": Array [ - Object { + "items": [ + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, - Object { + { "href": "https://facebook.com", "label": "Link label (translated)", "type": "link", }, - Object { + { "id": "doc1", "type": "ref", }, ], "label": "Getting started (translated)", - "link": Object { + "link": { "description": "Getting started index description (translated)", "permalink": "/docs/category/getting-started-index-slug", "slug": "/category/getting-started-index-slug", @@ -347,17 +347,17 @@ Object { }, "type": "category", }, - Object { + { "id": "doc3", "type": "doc", }, ], - "otherSidebar": Array [ - Object { + "otherSidebar": [ + { "id": "doc4", "type": "doc", }, - Object { + { "id": "doc5", "type": "doc", }, @@ -367,11 +367,11 @@ Object { "versionName": "2.0.0", "versionPath": "/docs/", }, - Object { + { "contentPath": "any", "contentPathLocalized": "any", - "docs": Array [ - Object { + "docs": [ + { "description": "doc1 description", "editUrl": "any", "id": "doc1", @@ -387,7 +387,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc2 description", "editUrl": "any", "id": "doc2", @@ -403,7 +403,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc3 description", "editUrl": "any", "id": "doc3", @@ -419,7 +419,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc4 description", "editUrl": "any", "id": "doc4", @@ -435,7 +435,7 @@ Object { "unversionedId": "any", "version": "any", }, - Object { + { "description": "doc5 description", "editUrl": "any", "id": "doc5", @@ -456,31 +456,31 @@ Object { "mainDocId": "", "routePriority": undefined, "sidebarFilePath": "any", - "sidebars": Object { - "docs": Array [ - Object { + "sidebars": { + "docs": [ + { "collapsed": false, - "items": Array [ - Object { + "items": [ + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, - Object { + { "href": "https://facebook.com", "label": "Link label (translated)", "type": "link", }, - Object { + { "id": "doc1", "type": "ref", }, ], "label": "Getting started (translated)", - "link": Object { + "link": { "description": "Getting started index description (translated)", "permalink": "/docs/category/getting-started-index-slug", "slug": "/category/getting-started-index-slug", @@ -489,17 +489,17 @@ Object { }, "type": "category", }, - Object { + { "id": "doc3", "type": "doc", }, ], - "otherSidebar": Array [ - Object { + "otherSidebar": [ + { "id": "doc4", "type": "doc", }, - Object { + { "id": "doc5", "type": "doc", }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap index 91902a834a74..3ab94d601021 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap @@ -1,54 +1,54 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DefaultSidebarItemsGenerator generates complex nested sidebar 1`] = ` -Array [ - Object { +[ + { "id": "intro", "type": "doc", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "tutorial1", "type": "doc", }, - Object { + { "id": "tutorial2", "type": "doc", }, ], "label": "Tutorials", - "link": Object { + "link": { "id": "tutorials-index", "type": "doc", }, "type": "category", }, - Object { + { "collapsed": false, "collapsible": undefined, - "customProps": Object { + "customProps": { "description": "foo", }, - "items": Array [ - Object { + "items": [ + { "className": "foo", "id": "guide1", "type": "doc", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "nested-guide", "type": "doc", }, ], "label": "SubGuides (metadata file label)", - "link": Object { + "link": { "description": "subGuides-description", "slug": "subGuides-generated-index-slug", "title": "subGuides-title", @@ -56,19 +56,19 @@ Array [ }, "type": "category", }, - Object { + { "id": "guide2", "type": "doc", }, ], "label": "Guides", - "link": Object { + "link": { "id": "guides-index", "type": "doc", }, "type": "category", }, - Object { + { "id": "end", "type": "doc", }, @@ -76,25 +76,25 @@ Array [ `; exports[`DefaultSidebarItemsGenerator generates simple flat sidebar 1`] = ` -Array [ - Object { +[ + { "id": "doc3", "type": "doc", }, - Object { + { "id": "doc4", "type": "doc", }, - Object { + { "id": "doc1", "label": "doc1 sidebar label", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, - Object { + { "id": "doc5", "type": "doc", }, @@ -102,33 +102,33 @@ Array [ `; exports[`DefaultSidebarItemsGenerator generates subfolder sidebar 1`] = ` -Array [ - Object { +[ + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "doc8", "type": "doc", }, - Object { + { "id": "doc7", "type": "doc", }, ], "label": "subsubsubfolder3 (_category_.json label)", - "link": Object { + "link": { "id": "doc1", "type": "doc", }, "type": "category", }, - Object { + { "className": "bar", "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "doc6", "type": "doc", }, @@ -136,19 +136,19 @@ Array [ "label": "subsubsubfolder2 (_category_.yml label)", "type": "category", }, - Object { + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc4", "type": "doc", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "doc5", "type": "doc", }, @@ -160,45 +160,45 @@ Array [ `; exports[`DefaultSidebarItemsGenerator respects custom isCategoryIndex 1`] = ` -Array [ - Object { +[ + { "id": "intro", "type": "doc", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "tutorial1", "type": "doc", }, - Object { + { "id": "tutorial2", "type": "doc", }, ], "label": "Tutorials", - "link": Object { + "link": { "id": "tutorials-index", "type": "doc", }, "type": "category", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "className": "foo", "id": "guide1", "type": "doc", }, - Object { + { "id": "guide2", "type": "doc", }, - Object { + { "id": "not-guides-index", "type": "doc", }, @@ -210,40 +210,40 @@ Array [ `; exports[`DefaultSidebarItemsGenerator uses explicit link over the index/readme.{md,mdx} naming convention 1`] = ` -Array [ - Object { +[ + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "parent/doc2", "type": "doc", }, - Object { + { "id": "parent/doc1", "type": "doc", }, ], "label": "Category label", - "link": Object { + "link": { "id": "parent/doc3", "type": "doc", }, "type": "category", }, - Object { + { "collapsed": undefined, "collapsible": undefined, - "items": Array [ - Object { + "items": [ + { "id": "parent/doc4", "type": "doc", }, - Object { + { "id": "parent/doc6", "type": "doc", }, - Object { + { "id": "parent/doc5", "type": "doc", }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap index ed1a6911deab..42b1cd180df8 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`loadSidebars sidebars link 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "href": "https://github.com", "label": "category", "type": "link", @@ -22,17 +22,17 @@ Object { `; exports[`loadSidebars sidebars with category.collapsed property 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "doc1", "type": "doc", }, @@ -46,15 +46,15 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "doc2", "type": "doc", }, @@ -73,13 +73,13 @@ Object { `; exports[`loadSidebars sidebars with category.collapsed property at first level 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "doc1", "type": "doc", }, @@ -88,11 +88,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": false, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "doc2", "type": "doc", }, @@ -106,41 +106,41 @@ Object { `; exports[`loadSidebars sidebars with deep level of category 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "a", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "c", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "d", "type": "doc", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "e", "type": "doc", }, @@ -159,7 +159,7 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "f", "type": "doc", }, @@ -178,13 +178,13 @@ Object { `; exports[`loadSidebars sidebars with first level not a category 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "greeting", "type": "doc", }, @@ -193,7 +193,7 @@ Object { "link": undefined, "type": "category", }, - Object { + { "id": "api", "type": "doc", }, @@ -202,26 +202,26 @@ Object { `; exports[`loadSidebars sidebars with known sidebar item type 1`] = ` -Object { - "docs": Array [ - Object { +{ + "docs": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "foo/bar", "type": "doc", }, - Object { + { "id": "foo/baz", "type": "doc", }, - Object { + { "href": "https://github.com", "label": "Github", "type": "link", }, - Object { + { "id": "hello", "type": "ref", }, @@ -230,11 +230,11 @@ Object { "link": undefined, "type": "category", }, - Object { + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "hello", "type": "doc", }, @@ -248,13 +248,13 @@ Object { `; exports[`loadSidebars undefined path 1`] = ` -Object { - "defaultSidebar": Array [ - Object { +{ + "defaultSidebar": [ + { "collapsed": true, "collapsible": true, - "items": Array [ - Object { + "items": [ + { "id": "bar", "type": "doc", }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/normalization.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/normalization.test.ts.snap index 91efc153bbf1..f847163c3050 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/normalization.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/normalization.test.ts.snap @@ -1,15 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`normalization normalizes shorthands 1`] = ` -Object { - "sidebar": Array [ - Object { - "items": Array [ - Object { +{ + "sidebar": [ + { + "items": [ + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, @@ -17,15 +17,15 @@ Object { "label": "Category", "type": "category", }, - Object { - "items": Array [ - Object { - "items": Array [ - Object { + { + "items": [ + { + "items": [ + { "id": "doc3", "type": "doc", }, - Object { + { "id": "doc4", "type": "doc", }, @@ -33,13 +33,13 @@ Object { "label": "Subcategory 1", "type": "category", }, - Object { - "items": Array [ - Object { + { + "items": [ + { "id": "doc5", "type": "doc", }, - Object { + { "id": "doc6", "type": "doc", }, @@ -56,20 +56,20 @@ Object { `; exports[`normalization normalizes shorthands 2`] = ` -Object { - "sidebar": Array [ - Object { +{ + "sidebar": [ + { "href": "https://google.com", "label": "Google", "type": "link", }, - Object { - "items": Array [ - Object { + { + "items": [ + { "id": "doc1", "type": "doc", }, - Object { + { "id": "doc2", "type": "doc", }, @@ -77,13 +77,13 @@ Object { "label": "Category 1", "type": "category", }, - Object { - "items": Array [ - Object { + { + "items": [ + { "id": "doc3", "type": "doc", }, - Object { + { "id": "doc4", "type": "doc", }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap index 6e204eccd703..cb42628261f3 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/postProcessor.test.ts.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`postProcess corrects collapsed state inconsistencies 1`] = ` -Object { - "sidebar": Array [ - Object { +{ + "sidebar": [ + { "collapsed": false, "collapsible": false, - "items": Array [ - Object { + "items": [ + { "id": "foo", "type": "doc", }, @@ -21,13 +21,13 @@ Object { `; exports[`postProcess corrects collapsed state inconsistencies 2`] = ` -Object { - "sidebar": Array [ - Object { +{ + "sidebar": [ + { "collapsed": false, "collapsible": false, - "items": Array [ - Object { + "items": [ + { "id": "foo", "type": "doc", }, @@ -41,13 +41,13 @@ Object { `; exports[`postProcess corrects collapsed state inconsistencies 3`] = ` -Object { - "sidebar": Array [ - Object { +{ + "sidebar": [ + { "collapsed": false, "collapsible": false, - "items": Array [ - Object { + "items": [ + { "id": "foo", "type": "doc", }, @@ -61,14 +61,14 @@ Object { `; exports[`postProcess transforms category without subitems 1`] = ` -Object { - "sidebar": Array [ - Object { +{ + "sidebar": [ + { "href": "version/generated/permalink", "label": "Category", "type": "link", }, - Object { + { "id": "doc ID", "label": "Category 2", "type": "doc", diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap index bc57b3355bd0..818f94da35f5 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap @@ -1,28 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` -Array [ - Object { +[ + { "permalink": "/", "source": "@site/src/pages/index.js", "type": "jsx", }, - Object { + { "permalink": "/typescript", "source": "@site/src/pages/typescript.tsx", "type": "jsx", }, - Object { + { "description": "Markdown index page", - "frontMatter": Object {}, + "frontMatter": {}, "permalink": "/hello/", "source": "@site/src/pages/hello/index.md", "title": "Index", "type": "mdx", }, - Object { + { "description": "my mdx page", - "frontMatter": Object { + "frontMatter": { "description": "my mdx page", "title": "mdx page", }, @@ -31,20 +31,20 @@ Array [ "title": "mdx page", "type": "mdx", }, - Object { + { "permalink": "/hello/translatedJs", "source": "@site/src/pages/hello/translatedJs.js", "type": "jsx", }, - Object { + { "description": "translated markdown page", - "frontMatter": Object {}, + "frontMatter": {}, "permalink": "/hello/translatedMd", "source": "@site/src/pages/hello/translatedMd.md", "title": undefined, "type": "mdx", }, - Object { + { "permalink": "/hello/world", "source": "@site/src/pages/hello/world.js", "type": "jsx", @@ -53,28 +53,28 @@ Array [ `; exports[`docusaurus-plugin-content-pages loads simple pages with french translations 1`] = ` -Array [ - Object { +[ + { "permalink": "/", "source": "@site/src/pages/index.js", "type": "jsx", }, - Object { + { "permalink": "/typescript", "source": "@site/src/pages/typescript.tsx", "type": "jsx", }, - Object { + { "description": "Markdown index page", - "frontMatter": Object {}, + "frontMatter": {}, "permalink": "/hello/", "source": "@site/src/pages/hello/index.md", "title": "Index", "type": "mdx", }, - Object { + { "description": "my mdx page", - "frontMatter": Object { + "frontMatter": { "description": "my mdx page", "title": "mdx page", }, @@ -83,20 +83,20 @@ Array [ "title": "mdx page", "type": "mdx", }, - Object { + { "permalink": "/hello/translatedJs", "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedJs.js", "type": "jsx", }, - Object { + { "description": "translated markdown page (fr)", - "frontMatter": Object {}, + "frontMatter": {}, "permalink": "/hello/translatedMd", "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedMd.md", "title": undefined, "type": "mdx", }, - Object { + { "permalink": "/hello/world", "source": "@site/src/pages/hello/world.js", "type": "jsx", diff --git a/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap index 6d539a18ccd5..084840bf3967 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-theme-classic/src/__tests__/__snapshots__/translations.test.ts.snap @@ -1,51 +1,51 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`getTranslationFiles returns translation files matching snapshot 1`] = ` -Array [ - Object { - "content": Object { - "item.label.Dropdown": Object { +[ + { + "content": { + "item.label.Dropdown": { "description": "Navbar item with label Dropdown", "message": "Dropdown", }, - "item.label.Dropdown item 1": Object { + "item.label.Dropdown item 1": { "description": "Navbar item with label Dropdown item 1", "message": "Dropdown item 1", }, - "item.label.Dropdown item 2": Object { + "item.label.Dropdown item 2": { "description": "Navbar item with label Dropdown item 2", "message": "Dropdown item 2", }, - "title": Object { + "title": { "description": "The title in the navbar", "message": "navbar title", }, }, "path": "navbar", }, - Object { - "content": Object { - "copyright": Object { + { + "content": { + "copyright": { "description": "The footer copyright", "message": "Copyright FB", }, - "link.item.label.Link 1": Object { + "link.item.label.Link 1": { "description": "The label of footer link with label=Link 1 linking to https://facebook.com", "message": "Link 1", }, - "link.item.label.Link 2": Object { + "link.item.label.Link 2": { "description": "The label of footer link with label=Link 2 linking to https://facebook.com", "message": "Link 2", }, - "link.item.label.Link 3": Object { + "link.item.label.Link 3": { "description": "The label of footer link with label=Link 3 linking to https://facebook.com", "message": "Link 3", }, - "link.title.Footer link column 1": Object { + "link.title.Footer link column 1": { "description": "The title of the footer links column with title=Footer link column 1 in the footer", "message": "Footer link column 1", }, - "link.title.Footer link column 2": Object { + "link.title.Footer link column 2": { "description": "The title of the footer links column with title=Footer link column 2 in the footer", "message": "Footer link column 2", }, @@ -56,39 +56,39 @@ Array [ `; exports[`getTranslationFiles returns translation files matching snapshot 2`] = ` -Array [ - Object { - "content": Object { - "item.label.Dropdown": Object { +[ + { + "content": { + "item.label.Dropdown": { "description": "Navbar item with label Dropdown", "message": "Dropdown", }, - "item.label.Dropdown item 1": Object { + "item.label.Dropdown item 1": { "description": "Navbar item with label Dropdown item 1", "message": "Dropdown item 1", }, - "item.label.Dropdown item 2": Object { + "item.label.Dropdown item 2": { "description": "Navbar item with label Dropdown item 2", "message": "Dropdown item 2", }, - "title": Object { + "title": { "description": "The title in the navbar", "message": "navbar title", }, }, "path": "navbar", }, - Object { - "content": Object { - "copyright": Object { + { + "content": { + "copyright": { "description": "The footer copyright", "message": "Copyright FB", }, - "link.item.label.Link 1": Object { + "link.item.label.Link 1": { "description": "The label of footer link with label=Link 1 linking to https://facebook.com", "message": "Link 1", }, - "link.item.label.Link 2": Object { + "link.item.label.Link 2": { "description": "The label of footer link with label=Link 2 linking to https://facebook.com", "message": "Link 2", }, @@ -99,31 +99,31 @@ Array [ `; exports[`translateThemeConfig returns translated themeConfig 1`] = ` -Object { - "announcementBar": Object {}, - "colorMode": Object {}, - "docs": Object { +{ + "announcementBar": {}, + "colorMode": {}, + "docs": { "versionPersistence": "none", }, - "footer": Object { + "footer": { "copyright": "Copyright FB (translated)", - "links": Array [ - Object { - "items": Array [ - Object { + "links": [ + { + "items": [ + { "label": "Link 1 (translated)", "to": "https://facebook.com", }, - Object { + { "label": "Link 2 (translated)", "to": "https://facebook.com", }, ], "title": "Footer link column 1 (translated)", }, - Object { - "items": Array [ - Object { + { + "items": [ + { "label": "Link 3 (translated)", "to": "https://facebook.com", }, @@ -134,17 +134,17 @@ Object { "style": "light", }, "hideableSidebar": true, - "navbar": Object { + "navbar": { "hideOnScroll": false, - "items": Array [ - Object { - "items": Array [ - Object { - "items": Array [], + "items": [ + { + "items": [ + { + "items": [], "label": "Dropdown item 1 (translated)", }, - Object { - "items": Array [], + { + "items": [], "label": "Dropdown item 2 (translated)", }, ], @@ -154,6 +154,6 @@ Object { "style": "dark", "title": "navbar title (translated)", }, - "prism": Object {}, + "prism": {}, } `; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap index 40f7d68143b5..97a8976893e6 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap @@ -1,71 +1,71 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`parseLines does not parse content with metastring 1`] = ` -Object { +{ "code": "aaaaa nnnnn", - "highlightLines": Array [ + "highlightLines": [ 0, ], } `; exports[`parseLines does not parse content with metastring 2`] = ` -Object { +{ "code": "// highlight-next-line aaaaa bbbbb", - "highlightLines": Array [ + "highlightLines": [ 0, ], } `; exports[`parseLines does not parse content with metastring 3`] = ` -Object { +{ "code": "aaaaa bbbbb", - "highlightLines": Array [ + "highlightLines": [ 0, ], } `; exports[`parseLines does not parse content with no language 1`] = ` -Object { +{ "code": "// highlight-next-line aaaaa bbbbb", - "highlightLines": Array [], + "highlightLines": [], } `; exports[`parseLines removes lines correctly 1`] = ` -Object { +{ "code": "aaaaa bbbbb", - "highlightLines": Array [ + "highlightLines": [ 0, ], } `; exports[`parseLines removes lines correctly 2`] = ` -Object { +{ "code": "aaaaa bbbbb", - "highlightLines": Array [ + "highlightLines": [ 0, ], } `; exports[`parseLines removes lines correctly 3`] = ` -Object { +{ "code": "aaaaa bbbbbbb bbbbb", - "highlightLines": Array [ + "highlightLines": [ 0, 2, 0, @@ -75,25 +75,25 @@ bbbbb", `; exports[`parseLines respects language 1`] = ` -Object { +{ "code": "# highlight-next-line aaaaa bbbbb", - "highlightLines": Array [], + "highlightLines": [], } `; exports[`parseLines respects language 2`] = ` -Object { +{ "code": "/* highlight-next-line */ aaaaa bbbbb", - "highlightLines": Array [], + "highlightLines": [], } `; exports[`parseLines respects language 3`] = ` -Object { +{ "code": "// highlight-next-line aaaa /* highlight-next-line */ @@ -101,19 +101,19 @@ bbbbb ccccc <!-- highlight-next-line --> dddd", - "highlightLines": Array [ + "highlightLines": [ 4, ], } `; exports[`parseLines respects language 4`] = ` -Object { +{ "code": "aaaa bbbbb ccccc dddd", - "highlightLines": Array [ + "highlightLines": [ 0, 1, 2, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap index 45df110aa812..2ed8b17ac05b 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/tocUtils.test.ts.snap @@ -1,17 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`useTreeifiedTOC treeifies TOC without filtering 1`] = ` -Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [], +[ + { + "children": [ + { + "children": [ + { + "children": [ + { + "children": [ + { + "children": [], "id": "foxtrot", "level": 6, "value": "Foxtrot", diff --git a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap index 1d0e85e558c7..f8d2b1f78741 100644 --- a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap +++ b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownLinks.test.ts.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`replaceMarkdownLinks does basic replace 1`] = ` -Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { +{ + "brokenMarkdownLinks": [ + { + "contentPaths": { "contentPath": "docs", "contentPathLocalized": "i18n/docs-localized", }, @@ -27,18 +27,18 @@ Object { `; exports[`replaceMarkdownLinks ignores links in HTML comments 1`] = ` -Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { +{ + "brokenMarkdownLinks": [ + { + "contentPaths": { "contentPath": "docs", "contentPathLocalized": "i18n/docs-localized", }, "filePath": "docs/intro.md", "link": "./foo.md", }, - Object { - "contentPaths": Object { + { + "contentPaths": { "contentPath": "docs", "contentPathLocalized": "i18n/docs-localized", }, @@ -56,8 +56,8 @@ Object { `; exports[`replaceMarkdownLinks ignores links in fenced blocks 1`] = ` -Object { - "brokenMarkdownLinks": Array [], +{ + "brokenMarkdownLinks": [], "newContent": " \`\`\` [foo](foo.md) @@ -81,10 +81,10 @@ Object { `; exports[`replaceMarkdownLinks ignores links in inline code 1`] = ` -Object { - "brokenMarkdownLinks": Array [ - Object { - "contentPaths": Object { +{ + "brokenMarkdownLinks": [ + { + "contentPaths": { "contentPath": "docs", "contentPathLocalized": "i18n/docs-localized", }, @@ -99,8 +99,8 @@ Object { `; exports[`replaceMarkdownLinks replaces links with same title as URL 1`] = ` -Object { - "brokenMarkdownLinks": Array [], +{ + "brokenMarkdownLinks": [], "newContent": " [/docs/foo](foo.md) [/docs/foo](./foo.md) @@ -111,8 +111,8 @@ Object { `; exports[`replaceMarkdownLinks replaces multiple links on same line 1`] = ` -Object { - "brokenMarkdownLinks": Array [], +{ + "brokenMarkdownLinks": [], "newContent": " [a](/docs/a), [a](/docs/a), [b](/docs/b), [c](/docs/c) ", @@ -120,8 +120,8 @@ Object { `; exports[`replaceMarkdownLinks replaces reference style Markdown links 1`] = ` -Object { - "brokenMarkdownLinks": Array [], +{ + "brokenMarkdownLinks": [], "newContent": " The following operations are defined for [URI]s: diff --git a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap index 50b866f0b5e2..5a65f0bb828f 100644 --- a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap +++ b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`parseMarkdownString deletes only first heading 1`] = ` -Object { +{ "content": "# Markdown Title test test test # test bar @@ -11,12 +11,12 @@ test test test # test bar ### Markdown Title h3", "contentTitle": "Markdown Title", "excerpt": "test test test # test bar", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString deletes only first heading 2 1`] = ` -Object { +{ "content": "# test test test test test test test @@ -26,25 +26,25 @@ test test test # test bar test3", "contentTitle": "test", "excerpt": "test test test test test test", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString does not warn for duplicate title if markdown title is not at the top 1`] = ` -Object { +{ "content": "foo # Markdown Title", "contentTitle": undefined, "excerpt": "foo", - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } `; exports[`parseMarkdownString handles code blocks 1`] = ` -Object { +{ "content": "\`\`\`js code \`\`\` @@ -52,12 +52,12 @@ code Content", "contentTitle": undefined, "excerpt": "Content", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString handles code blocks 2`] = ` -Object { +{ "content": "\`\`\`\`js Foo \`\`\`diff @@ -69,12 +69,12 @@ Bar Content", "contentTitle": undefined, "excerpt": "Content", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString handles code blocks 3`] = ` -Object { +{ "content": "\`\`\`\`js Foo \`\`\`diff @@ -84,116 +84,116 @@ code Content", "contentTitle": undefined, "excerpt": "Content", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString ignores markdown title if its not a first text 1`] = ` -Object { +{ "content": "foo # test", "contentTitle": undefined, "excerpt": "foo", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString parse markdown with front matter 1`] = ` -Object { +{ "content": "Some text", "contentTitle": undefined, "excerpt": "Some text", - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } `; exports[`parseMarkdownString parses first heading as contentTitle 1`] = ` -Object { +{ "content": "# Markdown Title Some text", "contentTitle": "Markdown Title", "excerpt": "Some text", - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString parses front-matter and ignore h2 1`] = ` -Object { +{ "content": "## test", "contentTitle": undefined, "excerpt": "test", - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } `; exports[`parseMarkdownString parses title only 1`] = ` -Object { +{ "content": "# test", "contentTitle": "test", "excerpt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString parses title only alternate 1`] = ` -Object { +{ "content": "test ===", "contentTitle": "test", "excerpt": undefined, - "frontMatter": Object {}, + "frontMatter": {}, } `; exports[`parseMarkdownString reads front matter only 1`] = ` -Object { +{ "content": "", "contentTitle": undefined, "excerpt": undefined, - "frontMatter": Object { + "frontMatter": { "title": "test", }, } `; exports[`parseMarkdownString warns about duplicate titles (front matter + markdown alternate) 1`] = ` -Object { +{ "content": "Markdown Title alternate ================ Some text", "contentTitle": "Markdown Title alternate", "excerpt": "Some text", - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } `; exports[`parseMarkdownString warns about duplicate titles (front matter + markdown) 1`] = ` -Object { +{ "content": "# Markdown Title Some text", "contentTitle": "Markdown Title", "excerpt": "Some text", - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } `; exports[`parseMarkdownString warns about duplicate titles 1`] = ` -Object { +{ "content": "# test", "contentTitle": "test", "excerpt": undefined, - "frontMatter": Object { + "frontMatter": { "title": "Frontmatter title", }, } diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index 7ab1c09720e5..14a12b8d06e0 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -3,14 +3,29 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * + * @jest-environment jsdom */ +// Jest doesn't allow pragma below other comments. https://github.com/facebook/jest/issues/12573 +// eslint-disable-next-line header/header import React from 'react'; import renderer from 'react-test-renderer'; import BrowserOnly from '../BrowserOnly'; import {Context} from '../browserContext'; describe('<BrowserOnly>', () => { + const originalEnv = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = {...originalEnv}; + }); + + afterAll(() => { + process.env = originalEnv; + }); + it('rejects react element children', () => { process.env.NODE_ENV = 'development'; expect(() => @@ -58,7 +73,7 @@ describe('<BrowserOnly>', () => { .toJSON(), ).toMatchInlineSnapshot(` <span> - https://docusaurus.io + https://docusaurus.io/ </span> `); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap index 09d0dcadd9b0..9136a8e12d29 100644 --- a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap +++ b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`<Interpolate> acceptance test 1`] = ` -Array [ +[ "Hello ", "Sébastien", " how are you ", @@ -13,7 +13,7 @@ Array [ `; exports[`interpolate acceptance test 1`] = ` -Array [ +[ <React.Fragment> Hello Sébastien @@ -31,7 +31,7 @@ Array [ `; exports[`interpolate placeholders with JSX values 1`] = ` -Array [ +[ <React.Fragment> Hello <b> @@ -51,7 +51,7 @@ Array [ `; exports[`interpolate placeholders with mixed vales 1`] = ` -Array [ +[ <React.Fragment> Hello Sébastien diff --git a/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx b/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx index 062591f3b426..1fa41bed0483 100644 --- a/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx @@ -25,12 +25,12 @@ describe('DocusaurusContextProvider', () => { const value = result.current; it('returns right value', () => { expect(value).toMatchInlineSnapshot(` - Object { - "codeTranslations": Object {}, - "globalData": Object {}, - "i18n": Object {}, - "siteConfig": Object {}, - "siteMetadata": Object {}, + { + "codeTranslations": {}, + "globalData": {}, + "i18n": {}, + "siteConfig": {}, + "siteMetadata": {}, } `); }); diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap index eeba7c337e96..333429f83a5f 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/config.test.ts.snap @@ -1,16 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`normalizeSwizzleConfig normalize partial config 1`] = ` -Object { - "components": Object { - "Other/Component": Object { - "actions": Object { +{ + "components": { + "Other/Component": { + "actions": { "eject": "unsafe", "wrap": "forbidden", }, }, - "SomeComponent": Object { - "actions": Object { + "SomeComponent": { + "actions": { "eject": "safe", "wrap": "unsafe", }, diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts index 7a5b3db9b6b7..d278e727aaa1 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/components.test.ts @@ -77,8 +77,8 @@ describe('getThemeComponents', () => { }); expect(themeComponents.getConfig(Components.ComponentInFolder)) .toMatchInlineSnapshot(` - Object { - "actions": Object { + { + "actions": { "eject": "unsafe", "wrap": "safe", }, @@ -87,8 +87,8 @@ describe('getThemeComponents', () => { `); expect(themeComponents.getConfig(Components.ComponentInSubFolder)) .toMatchInlineSnapshot(` - Object { - "actions": Object { + { + "actions": { "eject": "safe", "wrap": "unsafe", }, @@ -96,8 +96,8 @@ describe('getThemeComponents', () => { `); expect(themeComponents.getConfig(Components.FirstLevelComponent)) .toMatchInlineSnapshot(` - Object { - "actions": Object { + { + "actions": { "eject": "unsafe", "wrap": "unsafe", }, diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index ac70cb4e3f27..05963da88ac7 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -12,15 +12,15 @@ See https://docusaurus.io/docs/docusaurus.config.js/#customfields" `; exports[`loadConfig website with valid async config 1`] = ` -Object { +{ "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": Array [], - "customFields": Object {}, - "i18n": Object { + "clientModules": [], + "customFields": {}, + "i18n": { "defaultLocale": "en", - "localeConfigs": Object {}, - "locales": Array [ + "localeConfigs": {}, + "locales": [ "en", ], }, @@ -29,17 +29,17 @@ Object { "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", "organizationName": "endiliey", - "plugins": Array [], - "presets": Array [], + "plugins": [], + "presets": [], "projectName": "hello", - "scripts": Array [], - "staticDirectories": Array [ + "scripts": [], + "staticDirectories": [ "static", ], - "stylesheets": Array [], + "stylesheets": [], "tagline": "Hello World", - "themeConfig": Object {}, - "themes": Array [], + "themeConfig": {}, + "themes": [], "title": "Hello", "titleDelimiter": "|", "url": "https://docusaurus.io", @@ -47,15 +47,15 @@ Object { `; exports[`loadConfig website with valid async config creator function 1`] = ` -Object { +{ "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": Array [], - "customFields": Object {}, - "i18n": Object { + "clientModules": [], + "customFields": {}, + "i18n": { "defaultLocale": "en", - "localeConfigs": Object {}, - "locales": Array [ + "localeConfigs": {}, + "locales": [ "en", ], }, @@ -64,17 +64,17 @@ Object { "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", "organizationName": "endiliey", - "plugins": Array [], - "presets": Array [], + "plugins": [], + "presets": [], "projectName": "hello", - "scripts": Array [], - "staticDirectories": Array [ + "scripts": [], + "staticDirectories": [ "static", ], - "stylesheets": Array [], + "stylesheets": [], "tagline": "Hello World", - "themeConfig": Object {}, - "themes": Array [], + "themeConfig": {}, + "themes": [], "title": "Hello", "titleDelimiter": "|", "url": "https://docusaurus.io", @@ -82,15 +82,15 @@ Object { `; exports[`loadConfig website with valid config creator function 1`] = ` -Object { +{ "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": Array [], - "customFields": Object {}, - "i18n": Object { + "clientModules": [], + "customFields": {}, + "i18n": { "defaultLocale": "en", - "localeConfigs": Object {}, - "locales": Array [ + "localeConfigs": {}, + "locales": [ "en", ], }, @@ -99,17 +99,17 @@ Object { "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", "organizationName": "endiliey", - "plugins": Array [], - "presets": Array [], + "plugins": [], + "presets": [], "projectName": "hello", - "scripts": Array [], - "staticDirectories": Array [ + "scripts": [], + "staticDirectories": [ "static", ], - "stylesheets": Array [], + "stylesheets": [], "tagline": "Hello World", - "themeConfig": Object {}, - "themes": Array [], + "themeConfig": {}, + "themes": [], "title": "Hello", "titleDelimiter": "|", "url": "https://docusaurus.io", @@ -117,16 +117,16 @@ Object { `; exports[`loadConfig website with valid siteConfig 1`] = ` -Object { +{ "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": Array [], - "customFields": Object {}, + "clientModules": [], + "customFields": {}, "favicon": "img/docusaurus.ico", - "i18n": Object { + "i18n": { "defaultLocale": "en", - "localeConfigs": Object {}, - "locales": Array [ + "localeConfigs": {}, + "locales": [ "en", ], }, @@ -135,25 +135,25 @@ Object { "onBrokenMarkdownLinks": "warn", "onDuplicateRoutes": "warn", "organizationName": "endiliey", - "plugins": Array [ - Array [ + "plugins": [ + [ "@docusaurus/plugin-content-docs", - Object { + { "path": "../docs", }, ], "@docusaurus/plugin-content-pages", ], - "presets": Array [], + "presets": [], "projectName": "hello", - "scripts": Array [], - "staticDirectories": Array [ + "scripts": [], + "staticDirectories": [ "static", ], - "stylesheets": Array [], + "stylesheets": [], "tagline": "Hello World", - "themeConfig": Object {}, - "themes": Array [], + "themeConfig": {}, + "themes": [], "title": "Hello", "titleDelimiter": "|", "url": "https://docusaurus.io", diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index ef427a200fd3..e575e8024fb2 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -1,34 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`loadRoutes loads flat route config 1`] = ` -Object { - "registry": Object { - "component---theme-blog-list-pagea-6-a-7ba": Object { +{ + "registry": { + "component---theme-blog-list-pagea-6-a-7ba": { "loader": "() => import(/* webpackChunkName: 'component---theme-blog-list-pagea-6-a-7ba' */ '@theme/BlogListPage')", "modulePath": "@theme/BlogListPage", }, - "content---blog-0-b-4-09e": Object { + "content---blog-0-b-4-09e": { "loader": "() => import(/* webpackChunkName: 'content---blog-0-b-4-09e' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true')", "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true", }, - "content---blog-7-b-8-fd9": Object { + "content---blog-7-b-8-fd9": { "loader": "() => import(/* webpackChunkName: 'content---blog-7-b-8-fd9' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md')", "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md", }, - "metadata---blog-0-b-6-74c": Object { + "metadata---blog-0-b-6-74c": { "loader": "() => import(/* webpackChunkName: 'metadata---blog-0-b-6-74c' */ 'blog-2018-12-14-happy-first-birthday-slash-d2c.json')", "modulePath": "blog-2018-12-14-happy-first-birthday-slash-d2c.json", }, }, - "routesChunkNames": Object { - "/blog-94e": Object { + "routesChunkNames": { + "/blog-94e": { "component": "component---theme-blog-list-pagea-6-a-7ba", - "items": Array [ - Object { + "items": [ + { "content": "content---blog-0-b-4-09e", "metadata": "metadata---blog-0-b-6-74c", }, - Object { + { "content": "content---blog-7-b-8-fd9", "metadata": null, }, @@ -51,7 +51,7 @@ export default [ } ]; ", - "routesPaths": Array [ + "routesPaths": [ "/404.html", "/blog", ], @@ -59,48 +59,48 @@ export default [ `; exports[`loadRoutes loads nested route config 1`] = ` -Object { - "registry": Object { - "component---theme-doc-item-178-a40": Object { +{ + "registry": { + "component---theme-doc-item-178-a40": { "loader": "() => import(/* webpackChunkName: 'component---theme-doc-item-178-a40' */ '@theme/DocItem')", "modulePath": "@theme/DocItem", }, - "component---theme-doc-page-1-be-9be": Object { + "component---theme-doc-page-1-be-9be": { "loader": "() => import(/* webpackChunkName: 'component---theme-doc-page-1-be-9be' */ '@theme/DocPage')", "modulePath": "@theme/DocPage", }, - "content---docs-foo-baz-8-ce-61e": Object { + "content---docs-foo-baz-8-ce-61e": { "loader": "() => import(/* webpackChunkName: 'content---docs-foo-baz-8-ce-61e' */ 'docs/foo/baz.md')", "modulePath": "docs/foo/baz.md", }, - "content---docs-helloaff-811": Object { + "content---docs-helloaff-811": { "loader": "() => import(/* webpackChunkName: 'content---docs-helloaff-811' */ 'docs/hello.md')", "modulePath": "docs/hello.md", }, - "docsMetadata---docs-routef-34-881": Object { + "docsMetadata---docs-routef-34-881": { "loader": "() => import(/* webpackChunkName: 'docsMetadata---docs-routef-34-881' */ 'docs-b5f.json')", "modulePath": "docs-b5f.json", }, - "metadata---docs-foo-baz-2-cf-fa7": Object { + "metadata---docs-foo-baz-2-cf-fa7": { "loader": "() => import(/* webpackChunkName: 'metadata---docs-foo-baz-2-cf-fa7' */ 'docs-foo-baz-dd9.json')", "modulePath": "docs-foo-baz-dd9.json", }, - "metadata---docs-hello-956-741": Object { + "metadata---docs-hello-956-741": { "loader": "() => import(/* webpackChunkName: 'metadata---docs-hello-956-741' */ 'docs-hello-da2.json')", "modulePath": "docs-hello-da2.json", }, }, - "routesChunkNames": Object { - "/docs/hello-44b": Object { + "routesChunkNames": { + "/docs/hello-44b": { "component": "component---theme-doc-item-178-a40", "content": "content---docs-helloaff-811", "metadata": "metadata---docs-hello-956-741", }, - "/docs:route-63b": Object { + "/docs:route-63b": { "component": "component---theme-doc-page-1-be-9be", "docsMetadata": "docsMetadata---docs-routef-34-881", }, - "docs/foo/baz-ac2": Object { + "docs/foo/baz-ac2": { "component": "component---theme-doc-item-178-a40", "content": "content---docs-foo-baz-8-ce-61e", "metadata": "metadata---docs-foo-baz-2-cf-fa7", @@ -134,7 +134,7 @@ export default [ } ]; ", - "routesPaths": Array [ + "routesPaths": [ "/404.html", "/docs/hello", "docs/foo/baz", @@ -143,15 +143,15 @@ export default [ `; exports[`loadRoutes loads route config with empty (but valid) path string 1`] = ` -Object { - "registry": Object { - "component---hello-world-jse-0-f-b6c": Object { +{ + "registry": { + "component---hello-world-jse-0-f-b6c": { "loader": "() => import(/* webpackChunkName: 'component---hello-world-jse-0-f-b6c' */ 'hello/world.js')", "modulePath": "hello/world.js", }, }, - "routesChunkNames": Object { - "-b2a": Object { + "routesChunkNames": { + "-b2a": { "component": "component---hello-world-jse-0-f-b6c", }, }, @@ -170,7 +170,7 @@ export default [ } ]; ", - "routesPaths": Array [ + "routesPaths": [ "/404.html", "", ], diff --git a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts index de01447dc00d..46744e2d3aa8 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts @@ -14,13 +14,13 @@ import pluginHelloWorld from './__fixtures__/plugin-hello-world'; describe('loadClientModules', () => { it('empty', () => { const clientModules = loadClientModules([pluginEmpty()]); - expect(clientModules).toMatchInlineSnapshot(`Array []`); + expect(clientModules).toMatchInlineSnapshot(`[]`); }); it('non-empty', () => { const clientModules = loadClientModules([pluginFooBar()]); expect(clientModules).toMatchInlineSnapshot(` - Array [ + [ "foo", "bar", ] @@ -33,7 +33,7 @@ describe('loadClientModules', () => { pluginHelloWorld(), ]); expect(clientModules).toMatchInlineSnapshot(` - Array [ + [ "foo", "bar", "hello", @@ -48,7 +48,7 @@ describe('loadClientModules', () => { pluginFooBar(), ]); expect(clientModules).toMatchInlineSnapshot(` - Array [ + [ "hello", "world", "foo", @@ -64,7 +64,7 @@ describe('loadClientModules', () => { pluginFooBar(), ]); expect(clientModules).toMatchInlineSnapshot(` - Array [ + [ "hello", "world", "foo", @@ -80,7 +80,7 @@ describe('loadClientModules', () => { pluginEmpty(), ]); expect(clientModules).toMatchInlineSnapshot(` - Array [ + [ "hello", "world", "foo", diff --git a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts index 7b204ab38af5..19786fbea4e0 100644 --- a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts @@ -16,7 +16,7 @@ describe('loadHtmlTags', () => { it('empty plugin', () => { const htmlTags = loadHtmlTags([pluginEmpty()]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "", "postBodyTags": "", "preBodyTags": "", @@ -27,7 +27,7 @@ describe('loadHtmlTags', () => { it('only inject headTags', () => { const htmlTags = loadHtmlTags([pluginHeadTags()]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> <meta name=\\"generator\\" content=\\"docusaurus\\">", "postBodyTags": "", @@ -39,7 +39,7 @@ describe('loadHtmlTags', () => { it('only inject preBodyTags', () => { const htmlTags = loadHtmlTags([pluginPreBodyTags()]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "", "postBodyTags": "", "preBodyTags": "<script type=\\"text/javascript\\">window.foo = null;</script>", @@ -50,7 +50,7 @@ describe('loadHtmlTags', () => { it('only inject postBodyTags', () => { const htmlTags = loadHtmlTags([pluginPostBodyTags()]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "", "postBodyTags": "<div>Test content</div>", "preBodyTags": "", @@ -65,7 +65,7 @@ describe('loadHtmlTags', () => { pluginPreBodyTags(), ]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> <meta name=\\"generator\\" content=\\"docusaurus\\">", "postBodyTags": "<div>Test content</div>", @@ -81,7 +81,7 @@ describe('loadHtmlTags', () => { pluginPostBodyTags(), ]); expect(htmlTags).toMatchInlineSnapshot(` - Object { + { "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> <meta name=\\"generator\\" content=\\"docusaurus\\">", "postBodyTags": "<div>Test content</div>", diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap index 178307afa67c..2d8f4c1cad70 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap @@ -29,52 +29,52 @@ Example valid plugin config: `; exports[`sortConfig sorts route config correctly 1`] = ` -Array [ - Object { +[ + { "component": "", "path": "/community", }, - Object { + { "component": "", "path": "/some-page", }, - Object { + { "component": "", "path": "/docs", - "routes": Array [ - Object { + "routes": [ + { "component": "", "path": "/docs/someDoc", }, - Object { + { "component": "", "path": "/docs/someOtherDoc", }, ], }, - Object { + { "component": "", "path": "/", }, - Object { + { "component": "", "path": "/", - "routes": Array [ - Object { + "routes": [ + { "component": "", "path": "/someDoc", }, - Object { + { "component": "", "path": "/someOtherDoc", }, ], }, - Object { + { "component": "", "path": "/", - "routes": Array [ - Object { + "routes": [ + { "component": "", "path": "/subroute", }, @@ -84,42 +84,42 @@ Array [ `; exports[`sortConfig sorts route config given a baseURL 1`] = ` -Array [ - Object { +[ + { "component": "", "path": "/latest/community", }, - Object { + { "component": "", "path": "/latest/example", }, - Object { + { "component": "", "path": "/latest/some-page", }, - Object { + { "component": "", "path": "/latest/docs", - "routes": Array [ - Object { + "routes": [ + { "component": "", "path": "/latest/docs/someDoc", }, - Object { + { "component": "", "path": "/latest/docs/someOtherDoc", }, ], }, - Object { + { "component": "", "path": "/latest", - "routes": Array [ - Object { + "routes": [ + { "component": "", "path": "/latest/someDoc", }, - Object { + { "component": "", "path": "/latest/someOtherDoc", }, diff --git a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap index 34a36d41fc66..160beefa431d 100644 --- a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap @@ -1,121 +1,121 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`loadPresets array form 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", undefined, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], ], - "themes": Array [], + "themes": [], } `; exports[`loadPresets array form composite 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", - Object { + { "path": "../", }, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], - Array [ + [ "@docusaurus/plugin-content-pages", - Object { + { "path": "../", }, ], - Array [ + [ "@docusaurus/plugin-sitemap", undefined, ], ], - "themes": Array [], + "themes": [], } `; exports[`loadPresets array form with options 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", - Object { + { "path": "../", }, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], ], - "themes": Array [], + "themes": [], } `; exports[`loadPresets mixed form 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", - Object { + { "path": "../", }, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], - Array [ + [ "@docusaurus/plugin-content-pages", undefined, ], - Array [ + [ "@docusaurus/plugin-sitemap", undefined, ], ], - "themes": Array [], + "themes": [], } `; exports[`loadPresets mixed form with themes 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", - Object { + { "path": "../", }, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], - Array [ + [ "@docusaurus/plugin-content-pages", undefined, ], - Array [ + [ "@docusaurus/plugin-sitemap", undefined, ], - Array [ + [ "@docusaurus/plugin-test", undefined, ], ], - "themes": Array [ - Array [ + "themes": [ + [ "@docusaurus/theme-classic", undefined, ], @@ -124,41 +124,41 @@ Object { `; exports[`loadPresets string form 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", undefined, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], ], - "themes": Array [], + "themes": [], } `; exports[`loadPresets string form composite 1`] = ` -Object { - "plugins": Array [ - Array [ +{ + "plugins": [ + [ "@docusaurus/plugin-content-docs", undefined, ], - Array [ + [ "@docusaurus/plugin-content-blog", undefined, ], - Array [ + [ "@docusaurus/plugin-content-pages", undefined, ], - Array [ + [ "@docusaurus/plugin-sitemap", undefined, ], ], - "themes": Array [], + "themes": [], } `; diff --git a/packages/docusaurus/src/server/presets/__tests__/index.test.ts b/packages/docusaurus/src/server/presets/__tests__/index.test.ts index 68261597533b..444c5972384b 100644 --- a/packages/docusaurus/src/server/presets/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/presets/__tests__/index.test.ts @@ -20,9 +20,9 @@ describe('loadPresets', () => { } as LoadContext; const presets = await loadPresets(context); expect(presets).toMatchInlineSnapshot(` - Object { - "plugins": Array [], - "themes": Array [], + { + "plugins": [], + "themes": [], } `); }); diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index c593268eeadd..d0271d7c5b39 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`base webpack config creates webpack aliases 1`] = ` -Object { +{ "@docusaurus/BrowserOnly": "../../../../client/exports/BrowserOnly.tsx", "@docusaurus/ComponentCreator": "../../../../client/exports/ComponentCreator.tsx", "@docusaurus/ErrorBoundary": "../../../../client/exports/ErrorBoundary.tsx", @@ -48,7 +48,7 @@ Object { `; exports[`getDocusaurusAliases() returns appropriate webpack aliases 1`] = ` -Object { +{ "@docusaurus/BrowserOnly": "../../client/exports/BrowserOnly.tsx", "@docusaurus/ComponentCreator": "../../client/exports/ComponentCreator.tsx", "@docusaurus/ErrorBoundary": "../../client/exports/ErrorBoundary.tsx", From 009d87cbd940809d8d31c9837f81e78fa8d49a02 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 14 Mar 2022 08:16:12 +0800 Subject: [PATCH 010/405] refactor(content-blog): improve error message of authors map validation (#6909) --- .../src/__tests__/authors.test.ts | 16 ++++---- .../src/authors.ts | 39 ++++++++++++------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts index 5c159b7bbd73..0fde188e85af 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts @@ -381,7 +381,9 @@ describe('validateAuthorsMap', () => { validateAuthorsMap({ slorber: undefined, }), - ).toThrowErrorMatchingInlineSnapshot(`"\\"slorber\\" is required"`); + ).toThrowErrorMatchingInlineSnapshot( + `"\\"slorber\\" cannot be undefined. It should be an author object containing properties like name, title, and imageURL."`, + ); }); it('reject null author', () => { @@ -390,7 +392,7 @@ describe('validateAuthorsMap', () => { slorber: null, }), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" must be of type object"`, + `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -398,14 +400,13 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap({slorber: []}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" must be of type object"`, + `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, ); }); it('reject array content', () => { expect(() => validateAuthorsMap([])).toThrowErrorMatchingInlineSnapshot( - // TODO improve this error message - `"\\"value\\" must be of type object"`, + `"The authors map file should contain an object where each entry contains an author key and the corresponding author's data."`, ); }); @@ -413,8 +414,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap({name: 'Sébastien'}), ).toThrowErrorMatchingInlineSnapshot( - // TODO improve this error message - `"\\"name\\" must be of type object"`, + `"\\"name\\" should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -426,7 +426,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap(authorsMap), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" must be of type object"`, + `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/authors.ts b/packages/docusaurus-plugin-content-blog/src/authors.ts index 566da9a46ad5..9e234d86d9a7 100644 --- a/packages/docusaurus-plugin-content-blog/src/authors.ts +++ b/packages/docusaurus-plugin-content-blog/src/authors.ts @@ -17,20 +17,31 @@ import type { export type AuthorsMap = Record<string, Author>; -const AuthorsMapSchema = Joi.object<AuthorsMap>().pattern( - Joi.string(), - Joi.object({ - name: Joi.string(), - url: URISchema, - imageURL: URISchema, - title: Joi.string(), - email: Joi.string(), - }) - .rename('image_url', 'imageURL') - .or('name', 'imageURL') - .unknown() - .required(), -); +const AuthorsMapSchema = Joi.object<AuthorsMap>() + .pattern( + Joi.string(), + Joi.object({ + name: Joi.string(), + url: URISchema, + imageURL: URISchema, + title: Joi.string(), + email: Joi.string(), + }) + .rename('image_url', 'imageURL') + .or('name', 'imageURL') + .unknown() + .required() + .messages({ + 'object.base': + '{#label} should be an author object containing properties like name, title, and imageURL.', + 'any.required': + '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.', + }), + ) + .messages({ + 'object.base': + "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.", + }); export function validateAuthorsMap(content: unknown): AuthorsMap { return Joi.attempt(content, AuthorsMapSchema); From 13059770984b9fac1394b53662b0586fb1428f88 Mon Sep 17 00:00:00 2001 From: Ariful Alam <swazan.arif@gmail.com> Date: Mon, 14 Mar 2022 06:43:39 +0600 Subject: [PATCH 011/405] docs: add Reactive Button site to showcase (#6911) * Add reactive-button.png to showcase * Add `Reactive Button` to users.tsx * optimizt image Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/src/data/showcase/reactive-button.png | Bin 0 -> 7846 bytes website/src/data/users.tsx | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 website/src/data/showcase/reactive-button.png diff --git a/website/src/data/showcase/reactive-button.png b/website/src/data/showcase/reactive-button.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4bbf2287af85ce365c299eed5869b9fd750b14 GIT binary patch literal 7846 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 literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 13a8c5fdb572..def0985503c9 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -1337,6 +1337,14 @@ const Users: User[] = [ source: 'https://github.com/reduxjs/react-redux/tree/master/website', tags: ['opensource'], }, + { + title: 'Reactive Button', + description: '3D animated react button component with progress bar', + preview: require('./showcase/reactive-button.png'), + website: 'https://arifszn.github.io/reactive-button', + source: null, + tags: ['design'], + }, { title: 'Realtime Web Applications Workshop', description: From dc975fecbf2bbaad03ae23171c47c3d1153156af Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 14 Mar 2022 08:43:51 +0800 Subject: [PATCH 012/405] refactor: convert Jest infrastructure to TS (#6910) --- jest.config.mjs | 6 +- jest/{emptyModule.js => emptyModule.ts} | 2 +- ...ormalizer.js => snapshotPathNormalizer.ts} | 132 +++++++----------- website/src/data/__tests__/user.test.ts | 11 +- 4 files changed, 62 insertions(+), 89 deletions(-) rename jest/{emptyModule.js => emptyModule.ts} (90%) rename jest/{snapshotPathNormalizer.js => snapshotPathNormalizer.ts} (58%) diff --git a/jest.config.mjs b/jest.config.mjs index c469fed92fea..d973ca87d2de 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -35,13 +35,13 @@ export default { errorOnDeprecated: true, moduleNameMapper: { // Jest can't resolve CSS or asset imports - '^.+\\.(css|jpe?g|png|svg)$': '<rootDir>/jest/emptyModule.js', + '^.+\\.(css|jpe?g|png|svg|webp)$': '<rootDir>/jest/emptyModule.ts', // Using src instead of lib, so we always get fresh source '@docusaurus/(browserContext|BrowserOnly|ComponentCreator|constants|docusaurusContext|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)': '@docusaurus/core/src/client/exports/$1', // Maybe point to a fixture? - '@generated/.*': '<rootDir>/jest/emptyModule.js', + '@generated/.*': '<rootDir>/jest/emptyModule.ts', // TODO use "projects" + multiple configs if we work on another theme? '@theme/(.*)': '@docusaurus/theme-classic/src/theme/$1', '@site/(.*)': 'website/$1', @@ -50,7 +50,7 @@ export default { '@docusaurus/plugin-content-docs/client': '@docusaurus/plugin-content-docs/src/client/index.ts', }, - snapshotSerializers: ['<rootDir>/jest/snapshotPathNormalizer.js'], + snapshotSerializers: ['<rootDir>/jest/snapshotPathNormalizer.ts'], snapshotFormat: { printBasicPrototype: false, }, diff --git a/jest/emptyModule.js b/jest/emptyModule.ts similarity index 90% rename from jest/emptyModule.js rename to jest/emptyModule.ts index ec757d00e954..2687fdf661e1 100644 --- a/jest/emptyModule.js +++ b/jest/emptyModule.ts @@ -5,4 +5,4 @@ * LICENSE file in the root directory of this source tree. */ -module.exports = {}; +export default {}; diff --git a/jest/snapshotPathNormalizer.js b/jest/snapshotPathNormalizer.ts similarity index 58% rename from jest/snapshotPathNormalizer.js rename to jest/snapshotPathNormalizer.ts index 7d3fcd7d2666..f9f69cc90f29 100644 --- a/jest/snapshotPathNormalizer.js +++ b/jest/snapshotPathNormalizer.ts @@ -9,82 +9,57 @@ // Forked from https://github.com/tribou/jest-serializer-path/blob/master/lib/index.js // Added some project-specific handlers -const _ = require('lodash'); -const {escapePath} = require('@docusaurus/utils'); -const {version} = require('@docusaurus/core/package.json'); -const os = require('os'); -const path = require('path'); -const fs = require('fs'); - -module.exports = { - print(val, serialize) { - let normalizedValue = val; - - if (_.isError(normalizedValue)) { - const message = normalizePaths(normalizedValue.message); - const error = new Error(message); - - // Clone hidden props - const ownProps = Object.getOwnPropertyNames(error); - // eslint-disable-next-line no-restricted-syntax - for (const index in ownProps) { - if (Object.prototype.hasOwnProperty.call(ownProps, index)) { - const key = ownProps[index]; - - error[key] = normalizePaths(normalizedValue[key]); - } - } - - // Clone normal props - // eslint-disable-next-line no-restricted-syntax - for (const index in normalizedValue) { - if (Object.prototype.hasOwnProperty.call(normalizedValue, index)) { - error[index] = normalizePaths(normalizedValue[index]); - } - } - - normalizedValue = error; - } else if (typeof normalizedValue === 'object') { - normalizedValue = _.cloneDeep(normalizedValue); - - Object.keys(normalizedValue).forEach((key) => { - normalizedValue[key] = normalizePaths(normalizedValue[key]); - }); - } else { - normalizedValue = normalizePaths(normalizedValue); - } - +import _ from 'lodash'; +import {escapePath} from '@docusaurus/utils'; +import {version} from '@docusaurus/core/package.json'; +import os from 'os'; +import path from 'path'; +import fs from 'fs'; + +export function print( + val: unknown, + serialize: (val: unknown) => string, +): string { + if (val instanceof Error) { + const message = normalizePaths(val.message); + const error = new Error(message); + const allKeys = [ + ...Object.getOwnPropertyNames(error), + ...Object.keys(val), + ] as (keyof Error)[]; + allKeys.forEach((key) => { + error[key] = normalizePaths(val[key]) as never; + }); + return serialize(error); + } else if (val && typeof val === 'object') { + const normalizedValue = _.cloneDeep(val) as Record<string, unknown>; + + Object.keys(normalizedValue).forEach((key) => { + normalizedValue[key] = normalizePaths(normalizedValue[key]); + }); return serialize(normalizedValue); - }, - test(val) { - let has = false; - - if (val && typeof val === 'object') { - // val.message is non-enumerable in an error - if (val.message && shouldUpdate(val.message)) { - has = true; - } - - Object.keys(val).forEach((key) => { - if (shouldUpdate(val[key])) { - has = true; - } - }); - } else if (shouldUpdate(val)) { - has = true; - } - - return has; - }, - normalizePaths, - getRealPath, -}; + } + return serialize(normalizePaths(val)); +} + +export function test(val: unknown): boolean { + return ( + (typeof val === 'object' && + val && + Object.keys(val).some((key) => + shouldUpdate((val as Record<string, unknown>)[key]), + )) || + // val.message is non-enumerable in an error + (val instanceof Error && shouldUpdate(val.message)) || + shouldUpdate(val) + ); +} /** * Normalize paths across platforms. * Filters must be ran on all platforms to guard against false positives */ -function normalizePaths(value) { +function normalizePaths<T>(value: T): T { if (typeof value !== 'string') { return value; } @@ -101,7 +76,7 @@ function normalizePaths(value) { const homeRealRelativeToTempReal = path.relative(tempDirReal, homeDirReal); const homeRealRelativeToTemp = path.relative(tempDir, homeDirReal); - const runner = [ + const runner: ((val: string) => string)[] = [ // Replace process.cwd with <PROJECT_ROOT> (val) => val.split(cwdReal).join('<PROJECT_ROOT>'), (val) => val.split(cwd).join('<PROJECT_ROOT>'), @@ -149,28 +124,23 @@ function normalizePaths(value) { (val) => val.replace(/\\(?!")/g, '/'), ]; - let result = value; + let result = value as string; runner.forEach((current) => { result = current(result); }); - return result; + return result as T & string; } -function shouldUpdate(value) { - if (typeof value !== 'string') { - return false; - } - +function shouldUpdate(value: unknown) { // return true if value is different from normalized value - return normalizePaths(value) !== value; + return typeof value === 'string' && normalizePaths(value) !== value; } -function getRealPath(pathname) { +function getRealPath(pathname: string) { try { // eslint-disable-next-line no-restricted-properties const realPath = fs.realpathSync(pathname); - return realPath; } catch (error) { return pathname; diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index ab8ddf593b8c..1efe0f04da03 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -57,10 +57,13 @@ describe('users data', () => { .message('') .required(), // The preview should be jest/emptyModule - preview: Joi.object({}).unknown(false).required().messages({ - 'object.base': - 'The image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs. It must be imported with require().', - }), + preview: Joi.object({default: Joi.any()}) + .unknown(false) + .required() + .messages({ + 'object.base': + 'The image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs. It must be imported with require().', + }), tags: Joi.array() .items(...TagList) .required(), From 4e4cc0cc1764fdd8a6349419d7aa9788f64e9e13 Mon Sep 17 00:00:00 2001 From: Bugo <cheetah@bk.ru> Date: Mon, 14 Mar 2022 05:44:50 +0500 Subject: [PATCH 013/405] feat(theme-translations): complete Russian translations (#6781) --- .../locales/ru/plugin-ideal-image.json | 10 +++--- .../locales/ru/theme-common.json | 32 +++++++++---------- .../locales/ru/theme-search-algolia.json | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/docusaurus-theme-translations/locales/ru/plugin-ideal-image.json b/packages/docusaurus-theme-translations/locales/ru/plugin-ideal-image.json index 3576b692c08d..8790da025cee 100644 --- a/packages/docusaurus-theme-translations/locales/ru/plugin-ideal-image.json +++ b/packages/docusaurus-theme-translations/locales/ru/plugin-ideal-image.json @@ -1,7 +1,7 @@ { - "theme.IdealImageMessage.404error": "404. Image not found", - "theme.IdealImageMessage.error": "Error. Click to reload", - "theme.IdealImageMessage.load": "Click to load{sizeMessage}", - "theme.IdealImageMessage.loading": "Loading...", - "theme.IdealImageMessage.offline": "Your browser is offline. Image not loaded" + "theme.IdealImageMessage.404error": "404. Изображение не найдено", + "theme.IdealImageMessage.error": "Ошибка. Нажмите для перезагрузки", + "theme.IdealImageMessage.load": "Нажмите для загрузки {sizeMessage}", + "theme.IdealImageMessage.loading": "Загрузка...", + "theme.IdealImageMessage.offline": "Ваш браузер находится в автономном режиме. Изображение не загружено" } diff --git a/packages/docusaurus-theme-translations/locales/ru/theme-common.json b/packages/docusaurus-theme-translations/locales/ru/theme-common.json index abc0c4db304b..ac996abdd709 100644 --- a/packages/docusaurus-theme-translations/locales/ru/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ru/theme-common.json @@ -1,18 +1,18 @@ { "theme.AnnouncementBar.closeButtonAriaLabel": "Закрыть", - "theme.BackToTopButton.buttonAriaLabel": "Scroll back to top", + "theme.BackToTopButton.buttonAriaLabel": "Прокрутка к началу", "theme.CodeBlock.copied": "Скопировано", "theme.CodeBlock.copy": "Скопировать", "theme.CodeBlock.copyButtonAriaLabel": "Скопировать в буфер обмена", - "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'", - "theme.ErrorPageContent.title": "This page crashed.", - "theme.ErrorPageContent.tryAgain": "Try again", + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Свернуть/развернуть категорию '{label}'", + "theme.ErrorPageContent.title": "На странице произошёл сбой.", + "theme.ErrorPageContent.tryAgain": "Попробуйте ещё раз", "theme.NotFound.p1": "К сожалению, мы не смогли найти запрашиваемую вами страницу.", "theme.NotFound.p2": "Пожалуйста, обратитесь к владельцу сайта, с которого вы перешли на эту ссылку, чтобы сообщить ему, что ссылка не работает.", "theme.NotFound.title": "Страница не найдена", "theme.TOCCollapsible.toggleButtonLabel": "Содержание этой страницы", - "theme.blog.archive.description": "Archive", - "theme.blog.archive.title": "Archive", + "theme.blog.archive.description": "Архив", + "theme.blog.archive.title": "Архив", "theme.blog.paginator.navAriaLabel": "Навигация по странице списка блогов", "theme.blog.paginator.newerEntries": "Следующие записи", "theme.blog.paginator.olderEntries": "Предыдущие записи", @@ -21,17 +21,17 @@ "theme.blog.post.paginator.olderPost": "Предыдущий пост", "theme.blog.post.plurals": "{count} запись|{count} записи|{count} записей", "theme.blog.post.readMore": "Читать дальше", - "theme.blog.post.readMoreLabel": "Read more about {title}", + "theme.blog.post.readMoreLabel": "Подробнее о {title}", "theme.blog.post.readingTime.plurals": "{readingTime} мин. чтения", "theme.blog.sidebar.navAriaLabel": "Навигация по последним постам в блоге", "theme.blog.tagTitle": "{nPosts} с тегом \"{tagName}\"", - "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", - "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel": "Переключение между темным и светлым режимом (сейчас используется {mode})", + "theme.colorToggle.ariaLabel.mode.light": "Светлый режим", + "theme.colorToggle.ariaLabel.mode.dark": "Тёмный режим", "theme.common.editThisPage": "Отредактировать эту страницу", "theme.common.headingLinkTitle": "Прямая ссылка на этот заголовок", "theme.common.skipToMainContent": "Перейти к основному содержимому", - "theme.docs.DocCard.categoryDescription": "{count} items", + "theme.docs.DocCard.categoryDescription": "{count} элемент|{count} элемента|{count} элементов", "theme.docs.paginator.navAriaLabel": "Навигация по странице документации", "theme.docs.paginator.next": "Следующая страница", "theme.docs.paginator.previous": "Предыдущая страница", @@ -39,9 +39,9 @@ "theme.docs.sidebar.collapseButtonTitle": "Свернуть сайдбар", "theme.docs.sidebar.expandButtonAriaLabel": "Развернуть сайдбар", "theme.docs.sidebar.expandButtonTitle": "Развернуть сайдбар", - "theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"", - "theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged", - "theme.docs.versionBadge.label": "Version: {versionLabel}", + "theme.docs.tagDocListPageTitle": "{nDocsTagged} с тегом \"{tagName}\"", + "theme.docs.tagDocListPageTitle.nDocsTagged": "Одна страница|{count} страницы|{count} страниц", + "theme.docs.versionBadge.label": "Версия: {versionLabel}", "theme.docs.versions.latestVersionLinkLabel": "последней версии", "theme.docs.versions.latestVersionSuggestionLabel": "Актуальная документация находится на странице {latestVersionLink} ({versionLabel}).", "theme.docs.versions.unmaintainedVersionLabel": "Это документация {siteTitle} для версии {versionLabel}, которая уже не поддерживается.", @@ -49,9 +49,9 @@ "theme.lastUpdated.atDate": " {date}", "theme.lastUpdated.byUser": " от {user}", "theme.lastUpdated.lastUpdatedAtBy": "Последнее обновление{atDate}{byUser}", - "theme.navbar.mobileLanguageDropdown.label": "Languages", + "theme.navbar.mobileLanguageDropdown.label": "Языки", "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Перейти к главному меню", - "theme.navbar.mobileVersionsDropdown.label": "Versions", + "theme.navbar.mobileVersionsDropdown.label": "Версии", "theme.tags.tagsListLabel": "Теги:", "theme.tags.tagsPageLink": "Посмотреть все теги", "theme.tags.tagsPageTitle": "Теги" diff --git a/packages/docusaurus-theme-translations/locales/ru/theme-search-algolia.json b/packages/docusaurus-theme-translations/locales/ru/theme-search-algolia.json index a989e82d122f..2142bc727590 100644 --- a/packages/docusaurus-theme-translations/locales/ru/theme-search-algolia.json +++ b/packages/docusaurus-theme-translations/locales/ru/theme-search-algolia.json @@ -1,6 +1,6 @@ { "theme.SearchBar.label": "Поиск", - "theme.SearchBar.seeAll": "See all {count} results", + "theme.SearchBar.seeAll": "Посмотреть все результаты ({count})", "theme.SearchPage.algoliaLabel": "Поиск от Algolia", "theme.SearchPage.documentsFound.plurals": "{count} документ|{count} документа|{count} документов", "theme.SearchPage.emptyResultsTitle": "Поиск по сайту", From 12a7305238098a1c5f80d844b3ec59ab2a88547b Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 14 Mar 2022 08:45:47 +0800 Subject: [PATCH 014/405] feat: add SEO microdata for doc breadcrumbs (#6697) * feat: add SEO microdata for doc breadcrumbs * refactor * refactor --- .../src/theme/DocBreadcrumbs/index.tsx | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx index f912aac438a4..cdb69965ec61 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx @@ -26,11 +26,13 @@ function BreadcrumbsItemLink({ }): JSX.Element { const className = clsx('breadcrumbs__link', styles.breadcrumbsItemLink); return href ? ( - <Link className={className} href={href}> - {children} + <Link className={className} href={href} itemProp="item"> + <span itemProp="name">{children}</span> </Link> ) : ( - <span className={className}>{children}</span> + <span className={className} itemProp="item name"> + {children} + </span> ); } @@ -38,16 +40,22 @@ function BreadcrumbsItemLink({ function BreadcrumbsItem({ children, active, + index, }: { children: ReactNode; active?: boolean; + index: number; }): JSX.Element { return ( <li + itemScope + itemProp="itemListElement" + itemType="https://schema.org/ListItem" className={clsx('breadcrumbs__item', { 'breadcrumbs__item--active': active, })}> {children} + <meta itemProp="position" content={String(index + 1)} /> </li> ); } @@ -55,9 +63,13 @@ function BreadcrumbsItem({ function HomeBreadcrumbItem() { const homeHref = useBaseUrl('/'); return ( - <BreadcrumbsItem> - <BreadcrumbsItemLink href={homeHref}>🏠</BreadcrumbsItemLink> - </BreadcrumbsItem> + <li className="breadcrumbs__item"> + <Link + className={clsx('breadcrumbs__link', styles.breadcrumbsItemLink)} + href={homeHref}> + 🏠 + </Link> + </li> ); } @@ -76,10 +88,16 @@ export default function DocBreadcrumbs(): JSX.Element | null { styles.breadcrumbsContainer, )} aria-label="breadcrumbs"> - <ul className="breadcrumbs"> + <ul + className="breadcrumbs" + itemScope + itemType="https://schema.org/BreadcrumbList"> {homePageRoute && <HomeBreadcrumbItem />} {breadcrumbs.map((item, idx) => ( - <BreadcrumbsItem key={idx} active={idx === breadcrumbs.length - 1}> + <BreadcrumbsItem + key={idx} + active={idx === breadcrumbs.length - 1} + index={idx}> <BreadcrumbsItemLink href={item.href}> {item.label} </BreadcrumbsItemLink> From ad88f5cc87bad7652ce44519efcf2e113b1aaec9 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 14 Mar 2022 21:53:57 +0800 Subject: [PATCH 015/405] test: improve test coverage; multiple internal refactors (#6912) --- packages/create-docusaurus/src/index.ts | 15 +- .../__tests__/__fixtures__/outside/doc1.md | 1 + .../src/markdown/__tests__/linkify.test.ts | 10 + .../src/markdown/linkify.ts | 4 + .../src/sidebars/postProcessor.ts | 13 +- .../src/sidebars/utils.ts | 21 +- .../__tests__/locales.test.ts} | 15 +- .../locales/ar/theme-common.json | 2 +- .../locales/base/theme-common.json | 4 +- .../locales/bn/theme-common.json | 2 +- .../locales/cs/theme-common.json | 2 +- .../locales/da/theme-common.json | 2 +- .../locales/de/theme-common.json | 2 +- .../locales/es/theme-common.json | 2 +- .../locales/fa/theme-common.json | 2 +- .../locales/fil/theme-common.json | 2 +- .../locales/fr/theme-common.json | 2 +- .../locales/he/theme-common.json | 2 +- .../locales/hi/theme-common.json | 2 +- .../locales/it/theme-common.json | 2 +- .../locales/ja/theme-common.json | 2 +- .../locales/ko/theme-common.json | 2 +- .../locales/pl/theme-common.json | 2 +- .../locales/pt-BR/theme-common.json | 2 +- .../locales/pt-PT/theme-common.json | 2 +- .../locales/ru/theme-common.json | 2 +- .../locales/sr/theme-common.json | 2 +- .../locales/tr/theme-common.json | 2 +- .../locales/vi/theme-common.json | 2 +- .../locales/zh-Hans/theme-common.json | 2 +- .../locales/zh-Hant/theme-common.json | 2 +- .../package.json | 6 +- .../src/__tests__/__fixtures__/theme/index.js | 5 + .../src/__tests__/utils.test.ts | 26 ++ .../src/utils.ts | 100 +++++ .../tsconfig.build.json | 11 + .../tsconfig.json | 13 +- .../docusaurus-theme-translations/update.d.ts | 12 - .../docusaurus-theme-translations/update.js | 353 ------------------ .../docusaurus-theme-translations/update.mjs | 247 ++++++++++++ packages/docusaurus-types/src/index.d.ts | 2 +- .../src/__tests__/validationUtils.test.ts | 102 ++++- .../src/validationUtils.ts | 2 +- ...est.ts.snap => markdownUtils.test.ts.snap} | 0 ...wnParser.test.ts => markdownUtils.test.ts} | 108 +++++- .../src/__tests__/urlUtils.test.ts | 64 ++++ packages/docusaurus-utils/src/index.ts | 7 +- .../{markdownParser.ts => markdownUtils.ts} | 70 ++++ packages/docusaurus-utils/src/urlUtils.ts | 37 ++ packages/docusaurus/bin/beforeCli.mjs | 4 +- .../src/commands/__tests__/deploy.test.ts | 62 --- .../__tests__/writeHeadingIds.test.ts | 113 ------ packages/docusaurus/src/commands/deploy.ts | 38 +- packages/docusaurus/src/commands/start.ts | 2 +- .../src/commands/writeHeadingIds.ts | 85 +---- .../__snapshots__/routes.test.ts.snap | 25 +- .../src/server/__tests__/routes.test.ts | 12 + .../docusaurus/src/server/configValidation.ts | 2 +- packages/docusaurus/src/server/i18n.ts | 8 +- packages/docusaurus/src/server/index.ts | 29 +- .../__snapshots__/index.test.ts.snap | 146 ++++++++ .../__tests__/__snapshots__/init.test.ts.snap | 100 ----- .../server/plugins/__tests__/index.test.ts | 139 +++++++ .../src/server/plugins/__tests__/init.test.ts | 84 ----- .../docusaurus/src/server/plugins/index.ts | 6 +- .../{preset-qux.js => preset-mixed.js} | 0 .../{preset-bar.js => preset-plugins.js} | 0 .../{preset-foo.js => preset-themes.js} | 6 +- .../__snapshots__/index.test.ts.snap | 39 +- .../server/presets/__tests__/index.test.ts | 26 +- packages/docusaurus/src/server/routes.ts | 27 +- .../src/server/themes/__tests__/alias.test.ts | 46 ++- .../docusaurus/src/server/themes/index.ts | 2 +- .../__tests__/translations.test.ts | 331 +++++++++------- .../__tests__/translationsExtractor.test.ts | 34 +- .../src/server/translations/translations.ts | 12 +- .../__tests__/index.test.js | 76 +++- packages/stylelint-copyright/index.js | 6 +- 78 files changed, 1609 insertions(+), 1145 deletions(-) create mode 100644 packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md rename packages/docusaurus-theme-translations/{__tests__/update.test.ts => locales/__tests__/locales.test.ts} (76%) create mode 100644 packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js create mode 100644 packages/docusaurus-theme-translations/src/__tests__/utils.test.ts create mode 100644 packages/docusaurus-theme-translations/src/utils.ts create mode 100644 packages/docusaurus-theme-translations/tsconfig.build.json delete mode 100644 packages/docusaurus-theme-translations/update.d.ts delete mode 100644 packages/docusaurus-theme-translations/update.js create mode 100644 packages/docusaurus-theme-translations/update.mjs rename packages/docusaurus-utils/src/__tests__/__snapshots__/{markdownParser.test.ts.snap => markdownUtils.test.ts.snap} (100%) rename packages/docusaurus-utils/src/__tests__/{markdownParser.test.ts => markdownUtils.test.ts} (90%) rename packages/docusaurus-utils/src/{markdownParser.ts => markdownUtils.ts} (76%) delete mode 100644 packages/docusaurus/src/commands/__tests__/deploy.test.ts delete mode 100644 packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts create mode 100644 packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap create mode 100644 packages/docusaurus/src/server/plugins/__tests__/index.test.ts rename packages/docusaurus/src/server/presets/__tests__/__fixtures__/{preset-qux.js => preset-mixed.js} (100%) rename packages/docusaurus/src/server/presets/__tests__/__fixtures__/{preset-bar.js => preset-plugins.js} (100%) rename packages/docusaurus/src/server/presets/__tests__/__fixtures__/{preset-foo.js => preset-themes.js} (68%) diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index aa270c292fd2..1562e756b511 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -37,10 +37,7 @@ async function findPackageManagerFromLockFile(): Promise< SupportedPackageManager | undefined > { for (const packageManager of PackageManagersList) { - const lockFilePath = path.resolve( - process.cwd(), - SupportedPackageManagers[packageManager], - ); + const lockFilePath = path.resolve(SupportedPackageManagers[packageManager]); if (await fs.pathExists(lockFilePath)) { return packageManager; } @@ -152,7 +149,7 @@ async function copyTemplate( template: string, dest: string, ) { - await fs.copy(path.resolve(templatesDir, 'shared'), dest); + await fs.copy(path.join(templatesDir, 'shared'), dest); // TypeScript variants will copy duplicate resources like CSS & config from // base template @@ -211,7 +208,7 @@ export default async function init( const templates = await readTemplates(templatesDir); const hasTS = (templateName: string) => fs.pathExists( - path.resolve(templatesDir, `${templateName}${TypeScriptTemplateSuffix}`), + path.join(templatesDir, `${templateName}${TypeScriptTemplateSuffix}`), ); let name = siteName; @@ -297,7 +294,7 @@ export default async function init( name: 'templateDir', validate: async (dir?: string) => { if (dir) { - const fullDir = path.resolve(process.cwd(), dir); + const fullDir = path.resolve(dir); if (await fs.pathExists(fullDir)) { return true; } @@ -351,8 +348,8 @@ export default async function init( logger.error`Copying Docusaurus template name=${template} failed!`; throw err; } - } else if (await fs.pathExists(path.resolve(process.cwd(), template))) { - const templateDir = path.resolve(process.cwd(), template); + } else if (await fs.pathExists(path.resolve(template))) { + const templateDir = path.resolve(template); try { await fs.copy(templateDir, dest); } catch (err) { diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md new file mode 100644 index 000000000000..4fd86e1c55ca --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md @@ -0,0 +1 @@ +[link](../docs/doc1.md) diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index 4ee10a4acd56..2cf56ba9dcc7 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -193,4 +193,14 @@ describe('linkify', () => { expect(transformedContent).not.toContain('](../doc2.md)'); expect(content).not.toEqual(transformedContent); }); + + // See comment in linkify.ts + it('throws for file outside version', async () => { + const doc1 = path.join(__dirname, '__fixtures__/outside/doc1.md'); + await expect(() => + transform(doc1), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected error: Markdown file at \\"<PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md\\" does not belong to any docs version!"`, + ); + }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts index a029e92610d8..39e45e8f399e 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts @@ -15,6 +15,10 @@ function getVersion(filePath: string, options: DocsMarkdownOption) { filePath.startsWith(docsDirPath), ), ); + // At this point, this should never happen, because the MDX loaders' paths are + // literally using the version content paths; but if we allow sourcing content + // from outside the docs directory (through the `include` option, for example; + // is there a compelling use-case?), this would actually be testable if (!versionFound) { throw new Error( `Unexpected error: Markdown file at "${filePath}" does not belong to any docs version!`, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts index 48dafff60c63..44c652fe1959 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts @@ -58,22 +58,17 @@ function postProcessSidebarItem( `Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`, ); } - switch (category.link.type) { - case 'doc': - return { + return category.link.type === 'doc' + ? { type: 'doc', label: category.label, id: category.link.id, - }; - case 'generated-index': - return { + } + : { type: 'link', label: category.label, href: category.link.permalink, }; - default: - throw new Error('Unexpected sidebar category link type'); - } } // A non-collapsible category can't be collapsed! if (category.collapsible === false) { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index da095918d5cb..ee5de8bb582e 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -376,18 +376,13 @@ export function toNavigationLink( return undefined; } - if (navigationItem.type === 'doc') { - return toDocNavigationLink(getDocById(navigationItem.id)); - } else if (navigationItem.type === 'category') { - if (navigationItem.link.type === 'doc') { - return toDocNavigationLink(getDocById(navigationItem.link.id)); - } else if (navigationItem.link.type === 'generated-index') { - return { - title: navigationItem.label, - permalink: navigationItem.link.permalink, - }; - } - throw new Error('unexpected category link type'); + if (navigationItem.type === 'category') { + return navigationItem.link.type === 'doc' + ? toDocNavigationLink(getDocById(navigationItem.link.id)) + : { + title: navigationItem.label, + permalink: navigationItem.link.permalink, + }; } - throw new Error('unexpected navigation item'); + return toDocNavigationLink(getDocById(navigationItem.id)); } diff --git a/packages/docusaurus-theme-translations/__tests__/update.test.ts b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts similarity index 76% rename from packages/docusaurus-theme-translations/__tests__/update.test.ts rename to packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts index d9b23c69d003..e88aa90f14d5 100644 --- a/packages/docusaurus-theme-translations/__tests__/update.test.ts +++ b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts @@ -6,7 +6,7 @@ */ import {jest} from '@jest/globals'; -import {extractThemeCodeMessages} from '../update'; +import {extractThemeCodeMessages} from '../../src/utils'; import path from 'path'; import fs from 'fs-extra'; import _ from 'lodash'; @@ -16,20 +16,17 @@ jest.setTimeout(15000); describe('theme translations', () => { it('has base messages files contain EXACTLY all the translations extracted from the theme. Please run "yarn workspace @docusaurus/theme-translations update" to keep base messages files up-to-date', async () => { - const baseMessagesDirPath = path.join(__dirname, '../locales/base'); + const baseMessagesDirPath = path.join(__dirname, '../base'); const baseMessages = Object.fromEntries( await Promise.all( ( await fs.readdir(baseMessagesDirPath) ).map(async (baseMessagesFile) => Object.entries( - JSON.parse( - ( - await fs.readFile( - path.join(baseMessagesDirPath, baseMessagesFile), - ) - ).toString(), - ) as Record<string, string>, + (await fs.readJSON( + path.join(baseMessagesDirPath, baseMessagesFile), + 'utf-8', + )) as Record<string, string>, ), ), ).then((translations) => diff --git a/packages/docusaurus-theme-translations/locales/ar/theme-common.json b/packages/docusaurus-theme-translations/locales/ar/theme-common.json index 588fef9b2ca6..24e99fddfe40 100644 --- a/packages/docusaurus-theme-translations/locales/ar/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ar/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "أحدث مشاركات المدونة", "theme.blog.tagTitle": "{nPosts} موسومة ب \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "تعديل هذه الصفحة", "theme.common.headingLinkTitle": "ارتباط مباشر بالعنوان", "theme.common.skipToMainContent": "انتقل إلى المحتوى الرئيسي", diff --git a/packages/docusaurus-theme-translations/locales/base/theme-common.json b/packages/docusaurus-theme-translations/locales/base/theme-common.json index 70177fbbe97b..fb5f46320e19 100644 --- a/packages/docusaurus-theme-translations/locales/base/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/base/theme-common.json @@ -53,10 +53,10 @@ "theme.blog.tagTitle___DESCRIPTION": "The title of the page for a blog tag", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", "theme.colorToggle.ariaLabel___DESCRIPTION": "The ARIA label for the navbar color mode toggle", - "theme.colorToggle.ariaLabel.mode.light": "light mode", - "theme.colorToggle.ariaLabel.mode.light___DESCRIPTION": "The name for the light color mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", "theme.colorToggle.ariaLabel.mode.dark___DESCRIPTION": "The name for the dark color mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", + "theme.colorToggle.ariaLabel.mode.light___DESCRIPTION": "The name for the light color mode", "theme.common.editThisPage": "Edit this page", "theme.common.editThisPage___DESCRIPTION": "The link label to edit the current page", "theme.common.headingLinkTitle": "Direct link to heading", diff --git a/packages/docusaurus-theme-translations/locales/bn/theme-common.json b/packages/docusaurus-theme-translations/locales/bn/theme-common.json index d1f9b50770d3..a05c817a21c4 100644 --- a/packages/docusaurus-theme-translations/locales/bn/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/bn/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "সাম্প্রতিক ব্লগ পোস্ট নেভিগেশন", "theme.blog.tagTitle": "{nPosts} সঙ্গে ট্যাগ্গেড \"{tagName}\" ", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "এই পেজটি এডিট করুন", "theme.common.headingLinkTitle": "হেডিং এর সঙ্গে সরাসরি লিংকড", "theme.common.skipToMainContent": "স্কিপ করে মূল কন্টেন্ট এ যান", diff --git a/packages/docusaurus-theme-translations/locales/cs/theme-common.json b/packages/docusaurus-theme-translations/locales/cs/theme-common.json index 884a93704a8c..e0245b23ad23 100644 --- a/packages/docusaurus-theme-translations/locales/cs/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/cs/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Navigace s aktuálními články na blogu", "theme.blog.tagTitle": "{nPosts} s tagem \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Upravit tuto stránku", "theme.common.headingLinkTitle": "Přímý odkaz na nadpis", "theme.common.skipToMainContent": "Přeskočit na hlavní obsah", diff --git a/packages/docusaurus-theme-translations/locales/da/theme-common.json b/packages/docusaurus-theme-translations/locales/da/theme-common.json index 8da1bae99ab2..0591720ce6c9 100644 --- a/packages/docusaurus-theme-translations/locales/da/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/da/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} med følgende tag \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Rediger denne side", "theme.common.headingLinkTitle": "Direkte link til overskrift", "theme.common.skipToMainContent": "Hop til hovedindhold", diff --git a/packages/docusaurus-theme-translations/locales/de/theme-common.json b/packages/docusaurus-theme-translations/locales/de/theme-common.json index 2520186a25d3..9be17350a486 100644 --- a/packages/docusaurus-theme-translations/locales/de/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/de/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} getaggt mit \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Diese Seite bearbeiten", "theme.common.headingLinkTitle": "Direkter Link zur Überschrift", "theme.common.skipToMainContent": "Zum Hauptinhalt springen", diff --git a/packages/docusaurus-theme-translations/locales/es/theme-common.json b/packages/docusaurus-theme-translations/locales/es/theme-common.json index 5e73c5ebc50d..fbf476146716 100644 --- a/packages/docusaurus-theme-translations/locales/es/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/es/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Navegación de publicaciones recientes", "theme.blog.tagTitle": "{nPosts} etiquetados con \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Editar esta página", "theme.common.headingLinkTitle": "Enlace directo al encabezado", "theme.common.skipToMainContent": "Saltar al contenido principal", diff --git a/packages/docusaurus-theme-translations/locales/fa/theme-common.json b/packages/docusaurus-theme-translations/locales/fa/theme-common.json index 7341b54f95c1..1ba33a3417ca 100644 --- a/packages/docusaurus-theme-translations/locales/fa/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fa/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "کنترل پست های اخیر وبلاگ", "theme.blog.tagTitle": "{nPosts} با برچسب \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "ویرایش مطالب این صفحه", "theme.common.headingLinkTitle": "لینک مستقیم به عنوان", "theme.common.skipToMainContent": "پرش به مطلب اصلی", diff --git a/packages/docusaurus-theme-translations/locales/fil/theme-common.json b/packages/docusaurus-theme-translations/locales/fil/theme-common.json index e569c96bec0c..af8d60182d8b 100644 --- a/packages/docusaurus-theme-translations/locales/fil/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fil/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} na may tag na \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "I-edit ang page", "theme.common.headingLinkTitle": "Direktang link patungo sa heading", "theme.common.skipToMainContent": "Lumaktaw patungo sa pangunahing content", diff --git a/packages/docusaurus-theme-translations/locales/fr/theme-common.json b/packages/docusaurus-theme-translations/locales/fr/theme-common.json index 3e2991043408..efaa07c61103 100644 --- a/packages/docusaurus-theme-translations/locales/fr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fr/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Navigation article de blog récent", "theme.blog.tagTitle": "{nPosts} tagués avec « {tagName} »", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Éditer cette page", "theme.common.headingLinkTitle": "Lien direct vers le titre", "theme.common.skipToMainContent": "Aller au contenu principal", diff --git a/packages/docusaurus-theme-translations/locales/he/theme-common.json b/packages/docusaurus-theme-translations/locales/he/theme-common.json index e5c757aa5986..fab29a6c24bf 100644 --- a/packages/docusaurus-theme-translations/locales/he/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/he/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "מעבר לרשומות אחרונות בבלוג", "theme.blog.tagTitle": "{nPosts} עם התגית \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "ערוך דף זה", "theme.common.headingLinkTitle": "קישור ישיר לכותרת", "theme.common.skipToMainContent": "דלג לתוכן הראשי", diff --git a/packages/docusaurus-theme-translations/locales/hi/theme-common.json b/packages/docusaurus-theme-translations/locales/hi/theme-common.json index 8695d4ccd598..1850be82282f 100644 --- a/packages/docusaurus-theme-translations/locales/hi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/hi/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "नया ब्लॉग पोस्ट नेविगेशन", "theme.blog.tagTitle": "{nPosts} पोस्ट \"{tagName}\" टैग के साथ", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "इस पेज को बदलें", "theme.common.headingLinkTitle": "शीर्षक का सीधा लिंक", "theme.common.skipToMainContent": "मुख्य कंटेंट तक स्किप करें", diff --git a/packages/docusaurus-theme-translations/locales/it/theme-common.json b/packages/docusaurus-theme-translations/locales/it/theme-common.json index 2b576f920b55..feed8869eb80 100644 --- a/packages/docusaurus-theme-translations/locales/it/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/it/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Navigazione dei post recenti del blog", "theme.blog.tagTitle": "{nPosts} etichettati con \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Modifica questa pagina", "theme.common.headingLinkTitle": "Link diretto all'intestazione", "theme.common.skipToMainContent": "Passa al contenuto principale", diff --git a/packages/docusaurus-theme-translations/locales/ja/theme-common.json b/packages/docusaurus-theme-translations/locales/ja/theme-common.json index f55dcc8ca32e..926428492064 100644 --- a/packages/docusaurus-theme-translations/locales/ja/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ja/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "「{tagName}」タグの記事が{nPosts}あります", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "このページを編集", "theme.common.headingLinkTitle": "見出しへの直接リンク", "theme.common.skipToMainContent": "メインコンテンツまでスキップ", diff --git a/packages/docusaurus-theme-translations/locales/ko/theme-common.json b/packages/docusaurus-theme-translations/locales/ko/theme-common.json index c3eb573c55f9..688c695499d3 100644 --- a/packages/docusaurus-theme-translations/locales/ko/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ko/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "최근 블로그 문서 둘러보기", "theme.blog.tagTitle": "\"{tagName}\" 태그로 연결된 {nPosts}개의 게시물이 있습니다.", "theme.colorToggle.ariaLabel": "어두운 모드와 밝은 모드 전환하기 (현재 {mode})", - "theme.colorToggle.ariaLabel.mode.light": "밝은 모드", "theme.colorToggle.ariaLabel.mode.dark": "어두운 모드", + "theme.colorToggle.ariaLabel.mode.light": "밝은 모드", "theme.common.editThisPage": "페이지 편집", "theme.common.headingLinkTitle": "제목으로 바로 가기", "theme.common.skipToMainContent": "본문으로 건너뛰기", diff --git a/packages/docusaurus-theme-translations/locales/pl/theme-common.json b/packages/docusaurus-theme-translations/locales/pl/theme-common.json index 8f6490475856..a4e7bf78fa1c 100644 --- a/packages/docusaurus-theme-translations/locales/pl/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pl/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} z tagiem \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Edytuj tą stronę", "theme.common.headingLinkTitle": "Bezpośredni link do nagłówka", "theme.common.skipToMainContent": "Przejdź do głównej zawartości", diff --git a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json index 5b8b39f07240..31a708844d37 100644 --- a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} marcadas com \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Editar essa página", "theme.common.headingLinkTitle": "Link direto para o título", "theme.common.skipToMainContent": "Pular para o conteúdo principal", diff --git a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json index caf4e20d73ce..349ce35e090b 100644 --- a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", "theme.blog.tagTitle": "{nPosts} marcadas com \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Editar esta página", "theme.common.headingLinkTitle": "Link direto para o título", "theme.common.skipToMainContent": "Saltar para o conteúdo principal", diff --git a/packages/docusaurus-theme-translations/locales/ru/theme-common.json b/packages/docusaurus-theme-translations/locales/ru/theme-common.json index ac996abdd709..36cc2692ebe4 100644 --- a/packages/docusaurus-theme-translations/locales/ru/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ru/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Навигация по последним постам в блоге", "theme.blog.tagTitle": "{nPosts} с тегом \"{tagName}\"", "theme.colorToggle.ariaLabel": "Переключение между темным и светлым режимом (сейчас используется {mode})", - "theme.colorToggle.ariaLabel.mode.light": "Светлый режим", "theme.colorToggle.ariaLabel.mode.dark": "Тёмный режим", + "theme.colorToggle.ariaLabel.mode.light": "Светлый режим", "theme.common.editThisPage": "Отредактировать эту страницу", "theme.common.headingLinkTitle": "Прямая ссылка на этот заголовок", "theme.common.skipToMainContent": "Перейти к основному содержимому", diff --git a/packages/docusaurus-theme-translations/locales/sr/theme-common.json b/packages/docusaurus-theme-translations/locales/sr/theme-common.json index cf1940efbf96..294ab67609a2 100644 --- a/packages/docusaurus-theme-translations/locales/sr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/sr/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Недавни постови на блогу", "theme.blog.tagTitle": "{nPosts} означени са \"{tagName}\"", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Уреди ову страницу", "theme.common.headingLinkTitle": "Веза до наслова", "theme.common.skipToMainContent": "Пређи на главни садржај", diff --git a/packages/docusaurus-theme-translations/locales/tr/theme-common.json b/packages/docusaurus-theme-translations/locales/tr/theme-common.json index 76b335687dc4..b27a78a202af 100644 --- a/packages/docusaurus-theme-translations/locales/tr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/tr/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Blog son gönderiler navigasyonu", "theme.blog.tagTitle": "\"{tagName}\" ile etiketlenmiş {nPosts}", "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.colorToggle.ariaLabel.mode.dark": "dark mode", + "theme.colorToggle.ariaLabel.mode.light": "light mode", "theme.common.editThisPage": "Bu sayfayı düzenle", "theme.common.headingLinkTitle": "Başlığa doğrudan bağlantı", "theme.common.skipToMainContent": "Ana içeriğe geç", diff --git a/packages/docusaurus-theme-translations/locales/vi/theme-common.json b/packages/docusaurus-theme-translations/locales/vi/theme-common.json index 545fcf55d6d5..f56dc9927cd4 100644 --- a/packages/docusaurus-theme-translations/locales/vi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/vi/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "Điều hướng các bài viết gần đây trên blog", "theme.blog.tagTitle": "{nPosts} được gắn thẻ \"{tagName}\"", "theme.colorToggle.ariaLabel": "Chuyển đổi chế độ sáng và tối (hiện tại {mode})", - "theme.colorToggle.ariaLabel.mode.light": "chế độ sáng", "theme.colorToggle.ariaLabel.mode.dark": "chế độ tối", + "theme.colorToggle.ariaLabel.mode.light": "chế độ sáng", "theme.common.editThisPage": "Sửa trang này", "theme.common.headingLinkTitle": "Đường dẫn trực tiếp tới đề mục này", "theme.common.skipToMainContent": "Nhảy tới nội dung", diff --git a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json index eb407517ba02..d2579b9efeaa 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "最近博文导航", "theme.blog.tagTitle": "{nPosts} 含有标签「{tagName}」", "theme.colorToggle.ariaLabel": "切换浅色/暗黑模式(当前为{mode})", - "theme.colorToggle.ariaLabel.mode.light": "浅色模式", "theme.colorToggle.ariaLabel.mode.dark": "暗黑模式", + "theme.colorToggle.ariaLabel.mode.light": "浅色模式", "theme.common.editThisPage": "编辑此页", "theme.common.headingLinkTitle": "标题的直接链接", "theme.common.skipToMainContent": "跳到主要内容", diff --git a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json index 732aff68e28f..81a5a7d36971 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json @@ -26,8 +26,8 @@ "theme.blog.sidebar.navAriaLabel": "最近部落格文章導覽", "theme.blog.tagTitle": "{nPosts} 含有標籤「{tagName}」", "theme.colorToggle.ariaLabel": "切換淺色/暗黑模式(當前為{mode})", - "theme.colorToggle.ariaLabel.mode.light": "淺色模式", "theme.colorToggle.ariaLabel.mode.dark": "暗黑模式", + "theme.colorToggle.ariaLabel.mode.light": "淺色模式", "theme.common.editThisPage": "編輯此頁", "theme.common.headingLinkTitle": "標題的直接連結", "theme.common.skipToMainContent": "跳至主要内容", diff --git a/packages/docusaurus-theme-translations/package.json b/packages/docusaurus-theme-translations/package.json index 98f574e82aca..b690f7d48513 100644 --- a/packages/docusaurus-theme-translations/package.json +++ b/packages/docusaurus-theme-translations/package.json @@ -14,9 +14,9 @@ }, "license": "MIT", "scripts": { - "build": "tsc", - "watch": "tsc --watch", - "update": "node ./update.js" + "build": "tsc -p tsconfig.build.json", + "watch": "tsc -p tsconfig.build.json --watch", + "update": "node ./update.mjs" }, "dependencies": { "fs-extra": "^10.0.1", diff --git a/packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js b/packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js new file mode 100644 index 000000000000..80b33a00c39d --- /dev/null +++ b/packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js @@ -0,0 +1,5 @@ +import Translate from '@docusaurus/Translate'; + +export default function Foo() { + return <Translate>{index}</Translate>; +} diff --git a/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts b/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts new file mode 100644 index 000000000000..72f5cfd83994 --- /dev/null +++ b/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import {extractThemeCodeMessages} from '../utils'; + +describe('extractThemeCodeMessages', () => { + it('throws with invalid syntax', async () => { + await expect(() => + extractThemeCodeMessages([path.join(__dirname, '__fixtures__/theme')]), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + " + Please make sure all theme translations are static! + Some warnings were found! + + Translate content could not be extracted. It has to be a static string and use optional but static props, like <Translate id=\\"my-id\\" description=\\"my-description\\">text</Translate>. + File: packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js at line 4 + Full code: <Translate>{index}</Translate> + " + `); + }); +}); diff --git a/packages/docusaurus-theme-translations/src/utils.ts b/packages/docusaurus-theme-translations/src/utils.ts new file mode 100644 index 000000000000..78c666db7a64 --- /dev/null +++ b/packages/docusaurus-theme-translations/src/utils.ts @@ -0,0 +1,100 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// This file isn't used by index.ts. It's used by update.mjs and tests. It's +// only here so that (a) we get a partially typed infrastructure (although the +// update script has ts-check anyways) (b) the test coverage isn't destroyed by +// the untested update.mjs file (c) we can ergonomically import the util +// functions in the Jest test without using `await import` +/* eslint-disable import/no-extraneous-dependencies */ + +import path from 'path'; +import fs from 'fs-extra'; +// Unsafe import, should we create a package for the translationsExtractor ?; +import { + globSourceCodeFilePaths, + extractAllSourceCodeFileTranslations, +} from '@docusaurus/core/lib/server/translations/translationsExtractor'; +import type {TranslationFileContent} from '@docusaurus/types'; + +async function getPackageCodePath(packageName: string) { + const packagePath = path.join(__dirname, '../..', packageName); + const packageJsonPath = path.join(packagePath, 'package.json'); + const {main} = await fs.readJSON(packageJsonPath); + const packageSrcPath = path.join(packagePath, path.dirname(main)); + const packageLibNextPath = packageSrcPath.replace('lib', 'lib-next'); + return (await fs.pathExists(packageLibNextPath)) + ? packageLibNextPath + : packageSrcPath; +} + +export async function getThemes(): Promise<{name: string; src: string[]}[]> { + return [ + { + name: 'theme-common', + src: [ + await getPackageCodePath('docusaurus-theme-classic'), + await getPackageCodePath('docusaurus-theme-common'), + ], + }, + { + name: 'theme-search-algolia', + src: [await getPackageCodePath('docusaurus-theme-search-algolia')], + }, + { + name: 'theme-live-codeblock', + src: [await getPackageCodePath('docusaurus-theme-live-codeblock')], + }, + { + name: 'plugin-pwa', + src: [await getPackageCodePath('docusaurus-plugin-pwa')], + }, + { + name: 'plugin-ideal-image', + src: [await getPackageCodePath('docusaurus-plugin-ideal-image')], + }, + ]; +} + +export async function extractThemeCodeMessages( + targetDirs?: string[], +): Promise<TranslationFileContent> { + // eslint-disable-next-line no-param-reassign + targetDirs ??= (await getThemes()).flatMap((theme) => theme.src); + + const filePaths = (await globSourceCodeFilePaths(targetDirs)).filter( + (filePath) => ['.js', '.jsx'].includes(path.extname(filePath)), + ); + + const filesExtractedTranslations = await extractAllSourceCodeFileTranslations( + filePaths, + { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], + }, + ); + + filesExtractedTranslations.forEach((fileExtractedTranslations) => { + if (fileExtractedTranslations.warnings.length > 0) { + throw new Error(` +Please make sure all theme translations are static! +Some warnings were found! + +${fileExtractedTranslations.warnings.join('\n\n')} +`); + } + }); + + const translations = filesExtractedTranslations.reduce( + (acc, extractedTranslations) => ({ + ...acc, + ...extractedTranslations.translations, + }), + {}, + ); + + return translations; +} diff --git a/packages/docusaurus-theme-translations/tsconfig.build.json b/packages/docusaurus-theme-translations/tsconfig.build.json new file mode 100644 index 000000000000..aee99fc0f38e --- /dev/null +++ b/packages/docusaurus-theme-translations/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "incremental": true, + "tsBuildInfoFile": "./lib/.tsbuildinfo", + "sourceMap": true, + "declarationMap": true, + "rootDir": "src", + "outDir": "lib" + } +} diff --git a/packages/docusaurus-theme-translations/tsconfig.json b/packages/docusaurus-theme-translations/tsconfig.json index aee99fc0f38e..59be626a2754 100644 --- a/packages/docusaurus-theme-translations/tsconfig.json +++ b/packages/docusaurus-theme-translations/tsconfig.json @@ -1,11 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "incremental": true, - "tsBuildInfoFile": "./lib/.tsbuildinfo", - "sourceMap": true, - "declarationMap": true, - "rootDir": "src", - "outDir": "lib" - } + "module": "esnext", + "noEmit": true, + "checkJs": true, + "allowJs": true + }, + "include": ["update.mjs", "src"] } diff --git a/packages/docusaurus-theme-translations/update.d.ts b/packages/docusaurus-theme-translations/update.d.ts deleted file mode 100644 index ff8c770de0f1..000000000000 --- a/packages/docusaurus-theme-translations/update.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {TranslationFileContent} from '@docusaurus/types'; - -export function extractThemeCodeMessages( - targetDirs?: string[], -): Promise<TranslationFileContent>; diff --git a/packages/docusaurus-theme-translations/update.js b/packages/docusaurus-theme-translations/update.js deleted file mode 100644 index 6576fb182bbb..000000000000 --- a/packages/docusaurus-theme-translations/update.js +++ /dev/null @@ -1,353 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// @ts-check -// TODO convert this to ESM, which would also allow TLA -/* eslint-disable import/no-extraneous-dependencies, no-restricted-properties */ - -const logger = require('@docusaurus/logger').default; -const path = require('path'); -const fs = require('fs-extra'); -const _ = require('lodash'); - -const LocalesDirPath = path.join(__dirname, 'locales'); -const Themes = [ - { - name: 'theme-common', - src: [ - getPackageCodePath('docusaurus-theme-classic'), - getPackageCodePath('docusaurus-theme-common'), - ], - }, - { - name: 'theme-search-algolia', - src: [getPackageCodePath('docusaurus-theme-search-algolia')], - }, - { - name: 'theme-live-codeblock', - src: [getPackageCodePath('docusaurus-theme-live-codeblock')], - }, - { - name: 'plugin-pwa', - src: [getPackageCodePath('docusaurus-plugin-pwa')], - }, - { - name: 'plugin-ideal-image', - src: [getPackageCodePath('docusaurus-plugin-ideal-image')], - }, -]; -const AllThemesSrcDirs = Themes.flatMap((theme) => theme.src); - -logger.info`Will scan folders for code translations:path=${AllThemesSrcDirs}`; - -/** - * @param {string} packageName - */ -function getPackageCodePath(packageName) { - const packagePath = path.join(__dirname, '..', packageName); - const packageJsonPath = path.join(packagePath, 'package.json'); - const {main} = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); - const packageSrcPath = path.join(packagePath, path.dirname(main)); - const packageLibNextPath = packageSrcPath.replace('lib', 'lib-next'); - return fs.existsSync(packageLibNextPath) - ? packageLibNextPath - : packageSrcPath; -} - -/** - * @param {string} locale - * @param {string} themeName - */ -function getThemeLocalePath(locale, themeName) { - return path.join(LocalesDirPath, locale, `${themeName}.json`); -} - -/** - * @param {string} key - */ -function removeDescriptionSuffix(key) { - if (key.replace('___DESCRIPTION', '')) { - return key.replace('___DESCRIPTION', ''); - } - return key; -} - -/** - * @param {Record<string, string>} obj - */ -function sortObjectKeys(obj) { - let keys = Object.keys(obj); - keys = _.orderBy(keys, [(k) => removeDescriptionSuffix(k)]); - return keys.reduce((acc, key) => { - acc[key] = obj[key]; - return acc; - }, {}); -} - -/** - * @param {string[]} targetDirs - * @returns {Promise<import('@docusaurus/types').TranslationFileContent>} - */ -async function extractThemeCodeMessages(targetDirs = AllThemesSrcDirs) { - // Unsafe import, should we create a package for the translationsExtractor ? - const { - globSourceCodeFilePaths, - extractAllSourceCodeFileTranslations, - // eslint-disable-next-line global-require - } = require('@docusaurus/core/lib/server/translations/translationsExtractor'); - - const filePaths = (await globSourceCodeFilePaths(targetDirs)).filter( - (filePath) => ['.js', '.jsx'].includes(path.extname(filePath)), - ); - - const filesExtractedTranslations = await extractAllSourceCodeFileTranslations( - filePaths, - { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], - }, - ); - - filesExtractedTranslations.forEach((fileExtractedTranslations) => { - fileExtractedTranslations.warnings.forEach((warning) => { - throw new Error(` -Please make sure all theme translations are static! -Some warnings were found! - -${warning} - `); - }); - }); - - const translations = filesExtractedTranslations.reduce( - (acc, extractedTranslations) => ({ - ...acc, - ...extractedTranslations.translations, - }), - {}, - ); - - return translations; -} - -/** - * @param {string} filePath - * @returns {Promise<Record<string, string>>} - */ -async function readMessagesFile(filePath) { - if (!(await fs.pathExists(filePath))) { - logger.info`File path=${filePath} not found. Creating new translation base file.`; - await fs.outputFile(filePath, '{}\n'); - } - return JSON.parse((await fs.readFile(filePath)).toString()); -} - -/** - * @param {string} filePath - * @param {Record<string, string>} messages - */ -async function writeMessagesFile(filePath, messages) { - const sortedMessages = sortObjectKeys(messages); - - const content = `${JSON.stringify(sortedMessages, null, 2)}\n`; // \n makes prettier happy - await fs.outputFile(filePath, content); - logger.info`path=${path.basename( - filePath, - )} updated subdue=${logger.interpolate`(number=${ - Object.keys(sortedMessages).length - } messages)`}\n`; -} - -/** - * @param {string} themeName - */ -async function getCodeTranslationFiles(themeName) { - const baseFile = getThemeLocalePath('base', themeName); - const localesFiles = (await fs.readdir(LocalesDirPath)) - .filter((dirName) => dirName !== 'base') - .map((locale) => getThemeLocalePath(locale, themeName)); - return {baseFile, localesFiles}; -} - -const DescriptionSuffix = '___DESCRIPTION'; - -/** - * @param {string} baseFile - * @param {string[]} targetDirs - */ -async function updateBaseFile(baseFile, targetDirs) { - const baseMessagesWithDescriptions = await readMessagesFile(baseFile); - const baseMessages = _.pickBy( - baseMessagesWithDescriptions, - (v, key) => !key.endsWith(DescriptionSuffix), - ); - - const codeExtractedTranslations = await extractThemeCodeMessages(targetDirs); - const codeMessages = _.mapValues( - codeExtractedTranslations, - (translation) => translation.message, - ); - - const unknownMessages = _.difference( - Object.keys(baseMessages), - Object.keys(codeMessages), - ); - - if (unknownMessages.length) { - logger.error`Some messages exist in base locale but were not found by the code extractor! -They won't be removed automatically, so do the cleanup manually if necessary! code=${unknownMessages}`; - } - - const newBaseMessages = { - ...baseMessages, // Ensure we don't automatically remove unknown messages - ...codeMessages, - }; - - /** @type {Record<string, string>} */ - const newBaseMessagesDescriptions = Object.entries(newBaseMessages).reduce( - (acc, [key]) => { - const codeTranslation = codeExtractedTranslations[key]; - return { - ...acc, - [`${key}${DescriptionSuffix}`]: codeTranslation - ? codeTranslation.description - : undefined, - }; - }, - {}, - ); - - const newBaseMessagesWitDescription = { - ...newBaseMessages, - ...newBaseMessagesDescriptions, - }; - - await writeMessagesFile(baseFile, newBaseMessagesWitDescription); - - return newBaseMessages; -} - -/** - * @param {string} localeFile - * @param {Record<string, string>} baseFileMessages - */ -async function updateLocaleCodeTranslations(localeFile, baseFileMessages) { - const localeFileMessages = await readMessagesFile(localeFile); - - const unknownMessages = _.difference( - Object.keys(localeFileMessages), - Object.keys(baseFileMessages), - ); - - if (unknownMessages.length) { - logger.error`Some localized messages do not exist in base.json! -You may want to delete these! code=${unknownMessages}`; - } - - const newLocaleFileMessages = { - ...baseFileMessages, - ...localeFileMessages, - }; - - const untranslatedKeys = Object.entries(newLocaleFileMessages) - .filter(([key, value]) => value === baseFileMessages[key]) - .map(([key]) => key); - - if (untranslatedKeys.length) { - logger.warn`Some messages do not seem to be translated! code=${untranslatedKeys}`; - } - - await writeMessagesFile(localeFile, newLocaleFileMessages); - return {untranslated: untranslatedKeys.length}; -} - -async function updateCodeTranslations() { - /** @type {Record<string, {untranslated: number}>} */ - const stats = {}; - let messageCount = 0; - const {2: newLocale} = process.argv; - for (const theme of Themes) { - const {baseFile, localesFiles} = await getCodeTranslationFiles(theme.name); - logger.info`Will update base file for name=${theme.name}\n`; - const baseFileMessages = await updateBaseFile(baseFile, theme.src); - - if (newLocale) { - const newLocalePath = getThemeLocalePath(newLocale, theme.name); - - if (!fs.existsSync(newLocalePath)) { - await writeMessagesFile(newLocalePath, baseFileMessages); - logger.success`Locale file path=${path.basename( - newLocalePath, - )} have been created.`; - } else { - logger.warn`Locale file path=${path.basename( - newLocalePath, - )} was already created!`; - } - } else { - for (const localeFile of localesFiles) { - const localeName = path.basename(path.dirname(localeFile)); - const pluginName = path.basename(localeFile, path.extname(localeFile)); - logger.info`Will update name=${localeName} locale in name=${pluginName}`; - const stat = await updateLocaleCodeTranslations( - localeFile, - baseFileMessages, - ); - - stats[localeName] ??= {untranslated: 0}; - stats[localeName].untranslated += stat.untranslated; - } - messageCount += Object.keys(baseFileMessages).length; - } - } - if (newLocale) { - return null; - } - return {stats, messageCount}; -} - -if (require.main === module) { - updateCodeTranslations().then( - (result) => { - logger.success('updateCodeTranslations end\n'); - if (result) { - const {stats, messageCount} = result; - const locales = Object.entries(stats).sort( - (a, b) => a[1].untranslated - b[1].untranslated, - ); - const messages = locales.map(([name, stat]) => { - const percentage = (messageCount - stat.untranslated) / messageCount; - const filled = Math.floor(percentage * 30); - const color = - // eslint-disable-next-line no-nested-ternary - percentage > 0.99 - ? logger.green - : percentage > 0.7 - ? logger.yellow - : logger.red; - const progress = color( - `[${''.padStart(filled, '=')}${''.padStart(30 - filled, ' ')}]`, - ); - return logger.interpolate`name=${name.padStart(8)} ${progress} ${( - percentage * 100 - ).toFixed(1)} subdue=${`(${ - messageCount - stat.untranslated - }/${messageCount})`}`; - }); - logger.info`Translation coverage: -${messages.join('\n')}`; - } - }, - (e) => { - logger.error( - `\nupdateCodeTranslations failure: ${e.message}\n${e.stack}\n`, - ); - process.exit(1); - }, - ); -} - -exports.extractThemeCodeMessages = extractThemeCodeMessages; diff --git a/packages/docusaurus-theme-translations/update.mjs b/packages/docusaurus-theme-translations/update.mjs new file mode 100644 index 000000000000..3f5cab96034f --- /dev/null +++ b/packages/docusaurus-theme-translations/update.mjs @@ -0,0 +1,247 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @ts-check +/* eslint-disable import/no-extraneous-dependencies */ + +import logger from '@docusaurus/logger'; +import path from 'path'; +import {fileURLToPath} from 'url'; +import fs from 'fs-extra'; +import _ from 'lodash'; +import {getThemes, extractThemeCodeMessages} from './lib/utils.js'; + +const LocalesDirPath = fileURLToPath(new URL('locales', import.meta.url)); +const Themes = await getThemes(); +const AllThemesSrcDirs = Themes.flatMap((theme) => theme.src); + +logger.info`Will scan folders for code translations:path=${AllThemesSrcDirs}`; + +/** + * @param {string} locale + * @param {string} themeName + */ +function getThemeLocalePath(locale, themeName) { + return path.join(LocalesDirPath, locale, `${themeName}.json`); +} + +/** + * @param {string} key + */ +function removeDescriptionSuffix(key) { + if (key.replace('___DESCRIPTION', '')) { + return key.replace('___DESCRIPTION', ''); + } + return key; +} + +/** + * @param {Record<string, string>} obj + */ +function sortObjectKeys(obj) { + const keys = _.orderBy(Object.keys(obj), (k) => removeDescriptionSuffix(k)); + return Object.fromEntries(keys.map((k) => [k, obj[k]])); +} + +/** + * @param {string} filePath + * @returns {Promise<Record<string, string>>} + */ +async function readMessagesFile(filePath) { + if (!(await fs.pathExists(filePath))) { + logger.info`File path=${filePath} not found. Creating new translation base file.`; + await fs.outputFile(filePath, '{}\n'); + } + return JSON.parse((await fs.readFile(filePath)).toString()); +} + +/** + * @param {string} filePath + * @param {Record<string, string>} messages + */ +async function writeMessagesFile(filePath, messages) { + const sortedMessages = sortObjectKeys(messages); + + const content = `${JSON.stringify(sortedMessages, null, 2)}\n`; // \n makes prettier happy + await fs.outputFile(filePath, content); + logger.info`path=${path.basename( + filePath, + )} updated subdue=${logger.interpolate`(number=${ + Object.keys(sortedMessages).length + } messages)`}\n`; +} + +/** + * @param {string} themeName + */ +async function getCodeTranslationFiles(themeName) { + const baseFile = getThemeLocalePath('base', themeName); + const localesFiles = (await fs.readdir(LocalesDirPath)) + .filter((dirName) => dirName !== 'base' && !dirName.startsWith('__')) + .map((locale) => getThemeLocalePath(locale, themeName)); + return {baseFile, localesFiles}; +} + +const DescriptionSuffix = '___DESCRIPTION'; + +/** + * @param {string} baseFile + * @param {string[]} targetDirs + */ +async function updateBaseFile(baseFile, targetDirs) { + const baseMessagesWithDescriptions = await readMessagesFile(baseFile); + const baseMessages = _.pickBy( + baseMessagesWithDescriptions, + (v, key) => !key.endsWith(DescriptionSuffix), + ); + + const codeExtractedTranslations = await extractThemeCodeMessages(targetDirs); + const codeMessages = _.mapValues( + codeExtractedTranslations, + (translation) => translation.message, + ); + + const unknownMessages = _.difference( + Object.keys(baseMessages), + Object.keys(codeMessages), + ); + + if (unknownMessages.length) { + logger.error`Some messages exist in base locale but were not found by the code extractor! +They won't be removed automatically, so do the cleanup manually if necessary! code=${unknownMessages}`; + } + + const newBaseMessages = { + ...baseMessages, // Ensure we don't automatically remove unknown messages + ...codeMessages, + }; + + /** @type {Record<string, string>} */ + const newBaseMessagesDescriptions = Object.entries(newBaseMessages).reduce( + (acc, [key]) => { + const codeTranslation = codeExtractedTranslations[key]; + return { + ...acc, + [`${key}${DescriptionSuffix}`]: codeTranslation + ? codeTranslation.description + : undefined, + }; + }, + {}, + ); + + const newBaseMessagesWitDescription = { + ...newBaseMessages, + ...newBaseMessagesDescriptions, + }; + + await writeMessagesFile(baseFile, newBaseMessagesWitDescription); + + return newBaseMessages; +} + +/** + * @param {string} localeFile + * @param {Record<string, string>} baseFileMessages + */ +async function updateLocaleCodeTranslations(localeFile, baseFileMessages) { + const localeFileMessages = await readMessagesFile(localeFile); + + const unknownMessages = _.difference( + Object.keys(localeFileMessages), + Object.keys(baseFileMessages), + ); + + if (unknownMessages.length) { + logger.error`Some localized messages do not exist in base.json! +You may want to delete these! code=${unknownMessages}`; + } + + const newLocaleFileMessages = { + ...baseFileMessages, + ...localeFileMessages, + }; + + const untranslatedKeys = Object.entries(newLocaleFileMessages) + .filter(([key, value]) => value === baseFileMessages[key]) + .map(([key]) => key); + + if (untranslatedKeys.length) { + logger.warn`Some messages do not seem to be translated! code=${untranslatedKeys}`; + } + + await writeMessagesFile(localeFile, newLocaleFileMessages); + return {untranslated: untranslatedKeys.length}; +} + +/** @type {Record<string, {untranslated: number}>} */ +const stats = {}; +let messageCount = 0; +const {2: newLocale} = process.argv; +for (const theme of Themes) { + const {baseFile, localesFiles} = await getCodeTranslationFiles(theme.name); + logger.info`Will update base file for name=${theme.name}\n`; + const baseFileMessages = await updateBaseFile(baseFile, theme.src); + + if (newLocale) { + const newLocalePath = getThemeLocalePath(newLocale, theme.name); + + if (!(await fs.pathExists(newLocalePath))) { + await writeMessagesFile(newLocalePath, baseFileMessages); + logger.success`Locale file path=${path.basename( + newLocalePath, + )} have been created.`; + } else { + logger.warn`Locale file path=${path.basename( + newLocalePath, + )} was already created!`; + } + } else { + for (const localeFile of localesFiles) { + const localeName = path.basename(path.dirname(localeFile)); + const pluginName = path.basename(localeFile, path.extname(localeFile)); + logger.info`Will update name=${localeName} locale in name=${pluginName}`; + const stat = await updateLocaleCodeTranslations( + localeFile, + baseFileMessages, + ); + + (stats[localeName] ??= {untranslated: 0}).untranslated += + stat.untranslated; + } + messageCount += Object.keys(baseFileMessages).length; + } +} + +logger.success('updateCodeTranslations end\n'); +if (newLocale) { + process.exit(); +} +const locales = Object.entries(stats).sort( + (a, b) => a[1].untranslated - b[1].untranslated, +); +const messages = locales.map(([name, stat]) => { + const percentage = (messageCount - stat.untranslated) / messageCount; + const filled = Math.floor(percentage * 30); + const color = + // eslint-disable-next-line no-nested-ternary + percentage > 0.99 + ? logger.green + : percentage > 0.7 + ? logger.yellow + : logger.red; + const progress = color( + `[${''.padStart(filled, '=')}${''.padStart(30 - filled, ' ')}]`, + ); + return logger.interpolate`name=${name.padStart(8)} ${progress} ${( + percentage * 100 + ).toFixed(1)} subdue=${`(${ + messageCount - stat.untranslated + }/${messageCount})`}`; +}); +logger.info`Translation coverage: +${messages.join('\n')}`; diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 0378d5e4f8b1..f29f4d521dcb 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -288,7 +288,7 @@ export interface Plugin<Content = unknown> { } export type InitializedPlugin<Content = unknown> = Plugin<Content> & { - readonly options: PluginOptions; + readonly options: Required<PluginOptions>; readonly version: DocusaurusPluginVersionInformation; }; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts index b67cba10415c..d7f0742bfc0a 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts @@ -8,7 +8,107 @@ import {jest} from '@jest/globals'; import Joi from '../Joi'; import {JoiFrontMatter} from '../JoiFrontMatter'; -import {validateFrontMatter} from '../validationUtils'; +import { + normalizePluginOptions, + normalizeThemeConfig, + validateFrontMatter, +} from '../validationUtils'; + +describe('normalizePluginOptions', () => { + it('always adds an "id" field', () => { + const options = {id: 'a'}; + expect( + normalizePluginOptions( + // "Malicious" schema that tries to forbid "id" + Joi.object({id: Joi.any().forbidden()}), + options, + ), + ).toEqual(options); + }); + + it('normalizes plugin options', () => { + const options = {}; + expect( + normalizePluginOptions( + Joi.object({foo: Joi.string().default('a')}), + options, + ), + ).toEqual({foo: 'a', id: 'default'}); + }); + + it('throws for invalid options', () => { + const options = {foo: 1}; + expect(() => + normalizePluginOptions(Joi.object({foo: Joi.string()}), options), + ).toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" must be a string"`); + }); + + it('warns', () => { + const options = {foo: 'a'}; + const consoleMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); + expect( + normalizePluginOptions( + Joi.object({foo: Joi.string().warning('deprecated', {})}).messages({ + deprecated: '{#label} deprecated', + }), + options, + ), + ).toEqual({foo: 'a', id: 'default'}); + expect(consoleMock).toBeCalledWith( + expect.stringMatching(/"foo" deprecated/), + ); + }); +}); + +describe('normalizeThemeConfig', () => { + it('always allows unknown attributes', () => { + const themeConfig = {foo: 'a', bar: 1}; + expect( + normalizeThemeConfig( + // "Malicious" schema that tries to forbid extra properties + Joi.object({foo: Joi.string()}).unknown(false), + themeConfig, + ), + ).toEqual(themeConfig); + }); + + it('normalizes theme config', () => { + const themeConfig = {bar: 1}; + expect( + normalizeThemeConfig( + Joi.object({foo: Joi.string().default('a')}), + themeConfig, + ), + ).toEqual({bar: 1, foo: 'a'}); + }); + + it('throws for invalid options', () => { + const themeConfig = {foo: 1, bar: 1}; + expect(() => + normalizeThemeConfig(Joi.object({foo: Joi.string()}), themeConfig), + ).toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" must be a string"`); + }); + + it('warns', () => { + const themeConfig = {foo: 'a', bar: 1}; + const consoleMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); + expect( + normalizeThemeConfig( + Joi.object({foo: Joi.string().warning('deprecated', {})}).messages({ + deprecated: '{#label} deprecated', + }), + themeConfig, + ), + ).toEqual(themeConfig); + expect(consoleMock).toBeCalledWith( + expect.stringMatching(/"foo" deprecated/), + ); + }); +}); describe('validateFrontMatter', () => { it('accepts good values', () => { diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index 42ee0801b1b1..4e88d495b3c1 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -44,7 +44,7 @@ export function normalizeThemeConfig<T>( schema: Joi.ObjectSchema<T>, themeConfig: Partial<T>, ): T { - // A theme should only validate his "slice" of the full themeConfig, + // A theme should only validate its "slice" of the full themeConfig, // not the whole object, so we allow unknown attributes // otherwise one theme would fail validating the data of another theme const finalSchema = schema.unknown(); diff --git a/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap b/packages/docusaurus-utils/src/__tests__/__snapshots__/markdownUtils.test.ts.snap similarity index 100% rename from packages/docusaurus-utils/src/__tests__/__snapshots__/markdownParser.test.ts.snap rename to packages/docusaurus-utils/src/__tests__/__snapshots__/markdownUtils.test.ts.snap diff --git a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts similarity index 90% rename from packages/docusaurus-utils/src/__tests__/markdownParser.test.ts rename to packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts index a3de77298715..ae1edf89be08 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownParser.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts @@ -10,7 +10,8 @@ import { parseMarkdownContentTitle, parseMarkdownString, parseMarkdownHeadingId, -} from '../markdownParser'; + writeMarkdownHeadingId, +} from '../markdownUtils'; import dedent from 'dedent'; describe('createExcerpt', () => { @@ -801,3 +802,108 @@ describe('parseMarkdownHeadingId', () => { }); }); }); + +describe('writeMarkdownHeadingId', () => { + it('works for simple level-2 heading', () => { + expect(writeMarkdownHeadingId('## ABC')).toBe('## ABC {#abc}'); + }); + + it('works for simple level-3 heading', () => { + expect(writeMarkdownHeadingId('### ABC')).toBe('### ABC {#abc}'); + }); + + it('works for simple level-4 heading', () => { + expect(writeMarkdownHeadingId('#### ABC')).toBe('#### ABC {#abc}'); + }); + + it('unwraps markdown links', () => { + const input = `## hello [facebook](https://facebook.com) [crowdin](https://crowdin.com/translate/docusaurus-v2/126/en-fr?filter=basic&value=0)`; + expect(writeMarkdownHeadingId(input)).toBe( + `${input} {#hello-facebook-crowdin}`, + ); + }); + + it('can slugify complex headings', () => { + const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756'; + expect(writeMarkdownHeadingId(input)).toBe( + // cSpell:ignore ébastien + `${input} {#abc-hello-how-are-you-sébastien_-_---56756}`, + ); + }); + + it('does not duplicate duplicate id', () => { + expect(writeMarkdownHeadingId('## hello world {#hello-world}')).toBe( + '## hello world {#hello-world}', + ); + }); + + it('respects existing heading', () => { + expect(writeMarkdownHeadingId('## New heading {#old-heading}')).toBe( + '## New heading {#old-heading}', + ); + }); + + it('overwrites heading ID when asked to', () => { + expect( + writeMarkdownHeadingId('## New heading {#old-heading}', { + overwrite: true, + }), + ).toBe('## New heading {#new-heading}'); + }); + + it('maintains casing when asked to', () => { + expect( + writeMarkdownHeadingId('## getDataFromAPI()', { + maintainCase: true, + }), + ).toBe('## getDataFromAPI() {#getDataFromAPI}'); + }); + + it('transform the headings', () => { + const input = ` + +# Ignored title + +## abc + +### Hello world + +\`\`\` +# Heading in code block +\`\`\` + +## Hello world + + \`\`\` + # Heading in escaped code block + \`\`\` + +### abc {#abc} + + `; + + const expected = ` + +# Ignored title + +## abc {#abc-1} + +### Hello world {#hello-world} + +\`\`\` +# Heading in code block +\`\`\` + +## Hello world {#hello-world-1} + + \`\`\` + # Heading in escaped code block + \`\`\` + +### abc {#abc} + + `; + + expect(writeMarkdownHeadingId(input)).toEqual(expected); + }); +}); diff --git a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts index 178ff254d2d0..ce067a14899c 100644 --- a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts @@ -15,11 +15,18 @@ import { removeTrailingSlash, resolvePathname, encodePath, + buildSshUrl, + buildHttpsUrl, + hasSSHProtocol, } from '../urlUtils'; describe('normalizeUrl', () => { it('normalizes urls correctly', () => { const asserts = [ + { + input: [], + output: '', + }, { input: ['/', ''], output: '/', @@ -248,3 +255,60 @@ describe('encodePath', () => { expect(encodePath('a/你好/')).toBe('a/%E4%BD%A0%E5%A5%BD/'); }); }); + +describe('buildSshUrl', () => { + it('builds a normal ssh url', () => { + const url = buildSshUrl('github.com', 'facebook', 'docusaurus'); + expect(url).toBe('git@github.com:facebook/docusaurus.git'); + }); + it('builds a ssh url with port', () => { + const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422'); + expect(url).toBe('ssh://git@github.com:422/facebook/docusaurus.git'); + }); +}); + +describe('buildHttpsUrl', () => { + it('builds a normal http url', () => { + const url = buildHttpsUrl( + 'user:pass', + 'github.com', + 'facebook', + 'docusaurus', + ); + expect(url).toBe('https://user:pass@github.com/facebook/docusaurus.git'); + }); + it('builds a normal http url with port', () => { + const url = buildHttpsUrl( + 'user:pass', + 'github.com', + 'facebook', + 'docusaurus', + '5433', + ); + expect(url).toBe( + 'https://user:pass@github.com:5433/facebook/docusaurus.git', + ); + }); +}); + +describe('hasSSHProtocol', () => { + it('recognizes explicit SSH protocol', () => { + const url = 'ssh://git@github.com:422/facebook/docusaurus.git'; + expect(hasSSHProtocol(url)).toBe(true); + }); + + it('recognizes implied SSH protocol', () => { + const url = 'git@github.com:facebook/docusaurus.git'; + expect(hasSSHProtocol(url)).toBe(true); + }); + + it('does not recognize HTTPS with credentials', () => { + const url = 'https://user:pass@github.com/facebook/docusaurus.git'; + expect(hasSSHProtocol(url)).toBe(false); + }); + + it('does not recognize plain HTTPS URL', () => { + const url = 'https://github.com:5433/facebook/docusaurus.git'; + expect(hasSSHProtocol(url)).toBe(false); + }); +}); diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 9c66f3a9f460..26cb7ae65756 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -45,6 +45,9 @@ export { addLeadingSlash, addTrailingSlash, removeTrailingSlash, + hasSSHProtocol, + buildHttpsUrl, + buildSshUrl, } from './urlUtils'; export { type Tag, @@ -60,7 +63,9 @@ export { parseFrontMatter, parseMarkdownContentTitle, parseMarkdownString, -} from './markdownParser'; + writeMarkdownHeadingId, + type WriteHeadingIDOptions, +} from './markdownUtils'; export { type ContentPaths, type BrokenMarkdownLink, diff --git a/packages/docusaurus-utils/src/markdownParser.ts b/packages/docusaurus-utils/src/markdownUtils.ts similarity index 76% rename from packages/docusaurus-utils/src/markdownParser.ts rename to packages/docusaurus-utils/src/markdownUtils.ts index 354461b41473..8901c26fcde9 100644 --- a/packages/docusaurus-utils/src/markdownParser.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -7,6 +7,7 @@ import logger from '@docusaurus/logger'; import matter from 'gray-matter'; +import {createSlugger, type Slugger} from './slugger'; // Input: ## Some heading {#some-heading} // Output: {text: "## Some heading", id: "some-heading"} @@ -205,3 +206,72 @@ This can happen if you use special characters in front matter values (try using throw err; } } + +function unwrapMarkdownLinks(line: string): string { + return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1); +} + +function addHeadingId( + line: string, + slugger: Slugger, + maintainCase: boolean, +): string { + let headingLevel = 0; + while (line.charAt(headingLevel) === '#') { + headingLevel += 1; + } + + const headingText = line.slice(headingLevel).trimEnd(); + const headingHashes = line.slice(0, headingLevel); + const slug = slugger.slug(unwrapMarkdownLinks(headingText).trim(), { + maintainCase, + }); + + return `${headingHashes}${headingText} {#${slug}}`; +} + +export type WriteHeadingIDOptions = { + maintainCase?: boolean; + overwrite?: boolean; +}; + +export function writeMarkdownHeadingId( + content: string, + options: WriteHeadingIDOptions = {maintainCase: false, overwrite: false}, +): string { + const {maintainCase = false, overwrite = false} = options; + const lines = content.split('\n'); + const slugger = createSlugger(); + + // If we can't overwrite existing slugs, make sure other headings don't + // generate colliding slugs by first marking these slugs as occupied + if (!overwrite) { + lines.forEach((line) => { + const parsedHeading = parseMarkdownHeadingId(line); + if (parsedHeading.id) { + slugger.slug(parsedHeading.id); + } + }); + } + + let inCode = false; + return lines + .map((line) => { + if (line.startsWith('```')) { + inCode = !inCode; + return line; + } + // Ignore h1 headings, as we don't create anchor links for those + if (inCode || !line.startsWith('##')) { + return line; + } + const parsedHeading = parseMarkdownHeadingId(line); + + // Do not process if id is already there + if (parsedHeading.id && !overwrite) { + return line; + } + return addHeadingId(parsedHeading.text, slugger, maintainCase); + }) + .join('\n'); +} diff --git a/packages/docusaurus-utils/src/urlUtils.ts b/packages/docusaurus-utils/src/urlUtils.ts index a083a330b8d2..cf6f8aae0fd9 100644 --- a/packages/docusaurus-utils/src/urlUtils.ts +++ b/packages/docusaurus-utils/src/urlUtils.ts @@ -154,3 +154,40 @@ export function addTrailingSlash(str: string): string { export function removeTrailingSlash(str: string): string { return removeSuffix(str, '/'); } + +export function buildSshUrl( + githubHost: string, + organizationName: string, + projectName: string, + githubPort?: string, +): string { + if (githubPort) { + return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`; + } + return `git@${githubHost}:${organizationName}/${projectName}.git`; +} + +export function buildHttpsUrl( + gitCredentials: string, + githubHost: string, + organizationName: string, + projectName: string, + githubPort?: string, +): string { + if (githubPort) { + return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`; + } + return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`; +} + +export function hasSSHProtocol(sourceRepoUrl: string): boolean { + try { + if (new URL(sourceRepoUrl).protocol === 'ssh:') { + return true; + } + return false; + } catch { + // Fails when there isn't a protocol + return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git + } +} diff --git a/packages/docusaurus/bin/beforeCli.mjs b/packages/docusaurus/bin/beforeCli.mjs index 283c8d576bb4..d2524c3814a2 100644 --- a/packages/docusaurus/bin/beforeCli.mjs +++ b/packages/docusaurus/bin/beforeCli.mjs @@ -98,9 +98,7 @@ export default async function beforeCli() { .filter((p) => p.startsWith('@docusaurus')) .map((p) => p.concat('@latest')) .join(' '); - const isYarnUsed = await fs.pathExists( - path.resolve(process.cwd(), 'yarn.lock'), - ); + const isYarnUsed = await fs.pathExists(path.resolve('yarn.lock')); const upgradeCommand = isYarnUsed ? `yarn upgrade ${siteDocusaurusPackagesForUpdate}` : `npm i ${siteDocusaurusPackagesForUpdate}`; diff --git a/packages/docusaurus/src/commands/__tests__/deploy.test.ts b/packages/docusaurus/src/commands/__tests__/deploy.test.ts deleted file mode 100644 index a326ba08fac1..000000000000 --- a/packages/docusaurus/src/commands/__tests__/deploy.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {buildSshUrl, buildHttpsUrl, hasSSHProtocol} from '../deploy'; - -describe('remoteBranchUrl', () => { - it('builds a normal ssh url', () => { - const url = buildSshUrl('github.com', 'facebook', 'docusaurus'); - expect(url).toBe('git@github.com:facebook/docusaurus.git'); - }); - it('builds a ssh url with port', () => { - const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422'); - expect(url).toBe('ssh://git@github.com:422/facebook/docusaurus.git'); - }); - it('builds a normal http url', () => { - const url = buildHttpsUrl( - 'user:pass', - 'github.com', - 'facebook', - 'docusaurus', - ); - expect(url).toBe('https://user:pass@github.com/facebook/docusaurus.git'); - }); - it('builds a normal http url with port', () => { - const url = buildHttpsUrl( - 'user:pass', - 'github.com', - 'facebook', - 'docusaurus', - '5433', - ); - expect(url).toBe( - 'https://user:pass@github.com:5433/facebook/docusaurus.git', - ); - }); -}); - -describe('hasSSHProtocol', () => { - it('recognizes explicit SSH protocol', () => { - const url = 'ssh://git@github.com:422/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toBe(true); - }); - - it('recognizes implied SSH protocol', () => { - const url = 'git@github.com:facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toBe(true); - }); - - it('does not recognize HTTPS with credentials', () => { - const url = 'https://user:pass@github.com/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toBe(false); - }); - - it('does not recognize plain HTTPS URL', () => { - const url = 'https://github.com:5433/facebook/docusaurus.git'; - expect(hasSSHProtocol(url)).toBe(false); - }); -}); diff --git a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts b/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts deleted file mode 100644 index f8b9df882b4c..000000000000 --- a/packages/docusaurus/src/commands/__tests__/writeHeadingIds.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {transformMarkdownContent} from '../writeHeadingIds'; - -describe('transformMarkdownContent', () => { - it('works for simple level-2 heading', () => { - expect(transformMarkdownContent('## ABC')).toBe('## ABC {#abc}'); - }); - - it('works for simple level-3 heading', () => { - expect(transformMarkdownContent('### ABC')).toBe('### ABC {#abc}'); - }); - - it('works for simple level-4 heading', () => { - expect(transformMarkdownContent('#### ABC')).toBe('#### ABC {#abc}'); - }); - - it('unwraps markdown links', () => { - const input = `## hello [facebook](https://facebook.com) [crowdin](https://crowdin.com/translate/docusaurus-v2/126/en-fr?filter=basic&value=0)`; - expect(transformMarkdownContent(input)).toBe( - `${input} {#hello-facebook-crowdin}`, - ); - }); - - it('can slugify complex headings', () => { - const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756'; - expect(transformMarkdownContent(input)).toBe( - // cSpell:ignore ébastien - `${input} {#abc-hello-how-are-you-sébastien_-_---56756}`, - ); - }); - - it('does not duplicate duplicate id', () => { - expect(transformMarkdownContent('## hello world {#hello-world}')).toBe( - '## hello world {#hello-world}', - ); - }); - - it('respects existing heading', () => { - expect(transformMarkdownContent('## New heading {#old-heading}')).toBe( - '## New heading {#old-heading}', - ); - }); - - it('overwrites heading ID when asked to', () => { - expect( - transformMarkdownContent('## New heading {#old-heading}', { - overwrite: true, - }), - ).toBe('## New heading {#new-heading}'); - }); - - it('maintains casing when asked to', () => { - expect( - transformMarkdownContent('## getDataFromAPI()', { - maintainCase: true, - }), - ).toBe('## getDataFromAPI() {#getDataFromAPI}'); - }); - - it('transform the headings', () => { - const input = ` - -# Ignored title - -## abc - -### Hello world - -\`\`\` -# Heading in code block -\`\`\` - -## Hello world - - \`\`\` - # Heading in escaped code block - \`\`\` - -### abc {#abc} - - `; - - const expected = ` - -# Ignored title - -## abc {#abc-1} - -### Hello world {#hello-world} - -\`\`\` -# Heading in code block -\`\`\` - -## Hello world {#hello-world-1} - - \`\`\` - # Heading in escaped code block - \`\`\` - -### abc {#abc} - - `; - - expect(transformMarkdownContent(input)).toEqual(expected); - }); -}); diff --git a/packages/docusaurus/src/commands/deploy.ts b/packages/docusaurus/src/commands/deploy.ts index 6270eb3d29be..75a4cd9799cc 100644 --- a/packages/docusaurus/src/commands/deploy.ts +++ b/packages/docusaurus/src/commands/deploy.ts @@ -8,6 +8,7 @@ import fs from 'fs-extra'; import shell from 'shelljs'; import logger from '@docusaurus/logger'; +import {hasSSHProtocol, buildSshUrl, buildHttpsUrl} from '@docusaurus/utils'; import {loadContext} from '../server'; import build from './build'; import type {BuildCLIOptions} from '@docusaurus/types'; @@ -33,43 +34,6 @@ function shellExecLog(cmd: string) { } } -export function buildSshUrl( - githubHost: string, - organizationName: string, - projectName: string, - githubPort?: string, -): string { - if (githubPort) { - return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`; - } - return `git@${githubHost}:${organizationName}/${projectName}.git`; -} - -export function buildHttpsUrl( - gitCredentials: string, - githubHost: string, - organizationName: string, - projectName: string, - githubPort?: string, -): string { - if (githubPort) { - return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`; - } - return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`; -} - -export function hasSSHProtocol(sourceRepoUrl: string): boolean { - try { - if (new URL(sourceRepoUrl).protocol === 'ssh:') { - return true; - } - return false; - } catch { - // Fails when there isn't a protocol - return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git - } -} - export default async function deploy( siteDir: string, cliOptions: Partial<BuildCLIOptions> = {}, diff --git a/packages/docusaurus/src/commands/start.ts b/packages/docusaurus/src/commands/start.ts index b1d469faa819..776128478c29 100644 --- a/packages/docusaurus/src/commands/start.ts +++ b/packages/docusaurus/src/commands/start.ts @@ -123,7 +123,7 @@ export default async function start( plugins: [ // Generates an `index.html` file with the <script> injected. new HtmlWebpackPlugin({ - template: path.resolve( + template: path.join( __dirname, '../webpack/templates/index.html.template.ejs', ), diff --git a/packages/docusaurus/src/commands/writeHeadingIds.ts b/packages/docusaurus/src/commands/writeHeadingIds.ts index e0fc0f8fb096..7c8aed4d3c59 100644 --- a/packages/docusaurus/src/commands/writeHeadingIds.ts +++ b/packages/docusaurus/src/commands/writeHeadingIds.ts @@ -7,91 +7,20 @@ import fs from 'fs-extra'; import logger from '@docusaurus/logger'; -import {loadContext, loadPluginConfigs} from '../server'; -import initPlugins from '../server/plugins/init'; - import { - parseMarkdownHeadingId, - createSlugger, - type Slugger, + writeMarkdownHeadingId, + type WriteHeadingIDOptions, } from '@docusaurus/utils'; +import {loadContext, loadPluginConfigs} from '../server'; +import initPlugins from '../server/plugins/init'; import {safeGlobby} from '../server/utils'; -type Options = { - maintainCase?: boolean; - overwrite?: boolean; -}; - -function unwrapMarkdownLinks(line: string): string { - return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1); -} - -function addHeadingId( - line: string, - slugger: Slugger, - maintainCase: boolean, -): string { - let headingLevel = 0; - while (line.charAt(headingLevel) === '#') { - headingLevel += 1; - } - - const headingText = line.slice(headingLevel).trimEnd(); - const headingHashes = line.slice(0, headingLevel); - const slug = slugger.slug(unwrapMarkdownLinks(headingText).trim(), { - maintainCase, - }); - - return `${headingHashes}${headingText} {#${slug}}`; -} - -export function transformMarkdownContent( - content: string, - options: Options = {maintainCase: false, overwrite: false}, -): string { - const {maintainCase = false, overwrite = false} = options; - const lines = content.split('\n'); - const slugger = createSlugger(); - - // If we can't overwrite existing slugs, make sure other headings don't - // generate colliding slugs by first marking these slugs as occupied - if (!overwrite) { - lines.forEach((line) => { - const parsedHeading = parseMarkdownHeadingId(line); - if (parsedHeading.id) { - slugger.slug(parsedHeading.id); - } - }); - } - - let inCode = false; - return lines - .map((line) => { - if (line.startsWith('```')) { - inCode = !inCode; - return line; - } - // Ignore h1 headings, as we don't create anchor links for those - if (inCode || !line.startsWith('##')) { - return line; - } - const parsedHeading = parseMarkdownHeadingId(line); - - // Do not process if id is already there - if (parsedHeading.id && !overwrite) { - return line; - } - return addHeadingId(parsedHeading.text, slugger, maintainCase); - }) - .join('\n'); -} - async function transformMarkdownFile( filepath: string, - options?: Options, + options?: WriteHeadingIDOptions, ): Promise<string | undefined> { const content = await fs.readFile(filepath, 'utf8'); - const updatedContent = transformMarkdownContent(content, options); + const updatedContent = writeMarkdownHeadingId(content, options); if (content !== updatedContent) { await fs.writeFile(filepath, updatedContent); return filepath; @@ -118,7 +47,7 @@ async function getPathsToWatch(siteDir: string): Promise<string[]> { export default async function writeHeadingIds( siteDir: string, files?: string[], - options?: Options, + options?: WriteHeadingIDOptions, ): Promise<void> { const markdownFiles = await safeGlobby( files ?? (await getPathsToWatch(siteDir)), diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index e575e8024fb2..31aa85debae3 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -21,7 +21,7 @@ exports[`loadRoutes loads flat route config 1`] = ` }, }, "routesChunkNames": { - "/blog-94e": { + "/blog-1e7": { "component": "component---theme-blog-list-pagea-6-a-7ba", "items": [ { @@ -32,6 +32,10 @@ exports[`loadRoutes loads flat route config 1`] = ` "content": "content---blog-7-b-8-fd9", "metadata": null, }, + { + "content": "content---blog-7-b-8-fd9", + "metadata": null, + }, ], }, }, @@ -42,7 +46,7 @@ import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/blog', - component: ComponentCreator('/blog','94e'), + component: ComponentCreator('/blog','1e7'), exact: true }, { @@ -96,11 +100,11 @@ exports[`loadRoutes loads nested route config 1`] = ` "content": "content---docs-helloaff-811", "metadata": "metadata---docs-hello-956-741", }, - "/docs:route-63b": { + "/docs:route-52d": { "component": "component---theme-doc-page-1-be-9be", "docsMetadata": "docsMetadata---docs-routef-34-881", }, - "docs/foo/baz-ac2": { + "docs/foo/baz-070": { "component": "component---theme-doc-item-178-a40", "content": "content---docs-foo-baz-8-ce-61e", "metadata": "metadata---docs-foo-baz-2-cf-fa7", @@ -113,18 +117,23 @@ import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/docs:route', - component: ComponentCreator('/docs:route','63b'), + component: ComponentCreator('/docs:route','52d'), routes: [ { path: '/docs/hello', component: ComponentCreator('/docs/hello','44b'), exact: true, - 'sidebar': \\"main\\" + sidebar: \\"main\\" }, { path: 'docs/foo/baz', - component: ComponentCreator('docs/foo/baz','ac2'), - 'sidebar': \\"secondary\\" + component: ComponentCreator('docs/foo/baz','070'), + sidebar: \\"secondary\\", + \\"key:a\\": \\"containing colon\\", + \\"key'b\\": \\"containing quote\\", + \\"key\\\\\\"c\\": \\"containing double quote\\", + \\"key,d\\": \\"containing comma\\", + 字段: \\"containing unicode\\" } ] }, diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index 1a8029336eb7..70d030981976 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -35,6 +35,11 @@ describe('loadRoutes', () => { metadata: 'docs-foo-baz-dd9.json', }, sidebar: 'secondary', + 'key:a': 'containing colon', + "key'b": 'containing quote', + 'key"c': 'containing double quote', + 'key,d': 'containing comma', + 字段: 'containing unicode', }, ], }; @@ -64,6 +69,13 @@ describe('loadRoutes', () => { content: 'blog/2018-12-14-Happy-First-Birthday-Slash.md', metadata: null, }, + { + content: { + __import: true, + path: 'blog/2018-12-14-Happy-First-Birthday-Slash.md', + }, + metadata: null, + }, ], }, }; diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 241a6cbe0a03..19c104b08466 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -56,7 +56,7 @@ export const DEFAULT_CONFIG: Pick< staticDirectories: [STATIC_DIR_NAME], }; -function createPluginSchema(theme: boolean = false) { +function createPluginSchema(theme: boolean) { return ( Joi.alternatives() .try( diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts index 0e86e0ce3d93..713a347459cd 100644 --- a/packages/docusaurus/src/server/i18n.ts +++ b/packages/docusaurus/src/server/i18n.ts @@ -30,7 +30,7 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig { export async function loadI18n( config: DocusaurusConfig, - options: {locale?: string} = {}, + options: {locale?: string}, ): Promise<I18n> { const {i18n: i18nConfig} = config; @@ -88,9 +88,5 @@ export function localizePath({ return path.join(originalPath, i18n.currentLocale); } // Url paths; add a trailing slash so it's a valid base URL - if (pathType === 'url') { - return normalizeUrl([originalPath, i18n.currentLocale, '/']); - } - // should never happen - throw new Error(`Unhandled path type "${pathType}".`); + return normalizeUrl([originalPath, i18n.currentLocale, '/']); } diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index d603c46c2d56..b58aa1c54b0a 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -57,12 +57,10 @@ export async function loadSiteConfig({ siteDir: string; customConfigFilePath?: string; }): Promise<{siteConfig: DocusaurusConfig; siteConfigPath: string}> { - const siteConfigPathUnresolved = - customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME; - - const siteConfigPath = path.isAbsolute(siteConfigPathUnresolved) - ? siteConfigPathUnresolved - : path.resolve(siteDir, siteConfigPathUnresolved); + const siteConfigPath = path.resolve( + siteDir, + customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME, + ); const siteConfig = await loadConfig(siteConfigPath); return {siteConfig, siteConfigPath}; @@ -73,9 +71,7 @@ export async function loadContext( options: LoadContextOptions = {}, ): Promise<LoadContext> { const {customOutDir, locale, customConfigFilePath} = options; - const generatedFilesDir = path.isAbsolute(GENERATED_FILES_DIR_NAME) - ? GENERATED_FILES_DIR_NAME - : path.resolve(siteDir, GENERATED_FILES_DIR_NAME); + const generatedFilesDir = path.resolve(siteDir, GENERATED_FILES_DIR_NAME); const {siteConfig: initialSiteConfig, siteConfigPath} = await loadSiteConfig({ siteDir, @@ -83,9 +79,10 @@ export async function loadContext( }); const {ssrTemplate} = initialSiteConfig; - const baseOutDir = customOutDir - ? path.resolve(customOutDir) - : path.resolve(siteDir, DEFAULT_BUILD_DIR_NAME); + const baseOutDir = path.resolve( + siteDir, + customOutDir ?? DEFAULT_BUILD_DIR_NAME, + ); const i18n = await loadI18n(initialSiteConfig, {locale}); @@ -191,7 +188,9 @@ function createBootstrapPlugin({ return { name: 'docusaurus-bootstrap-plugin', content: null, - options: {}, + options: { + id: 'default', + }, version: {type: 'synthetic'}, getClientModules() { return siteConfigClientModules; @@ -241,7 +240,9 @@ function createMDXFallbackPlugin({ return { name: 'docusaurus-mdx-fallback-plugin', content: null, - options: {}, + options: { + id: 'default', + }, version: {type: 'synthetic'}, configureWebpack(config, isServer, {getJSLoader}) { // We need the mdx fallback loader to exclude files that were already diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..57398999df4f --- /dev/null +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,146 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadPlugins loads plugins 1`] = ` +{ + "globalData": { + "test1": { + "default": { + "content": "a", + "prop": "a", + }, + }, + }, + "plugins": [ + { + "content": "a", + "contentLoaded": [Function], + "loadContent": [Function], + "name": "test1", + "options": { + "id": "default", + }, + "prop": "a", + "version": { + "type": "local", + }, + }, + { + "configureWebpack": [Function], + "content": undefined, + "name": "test2", + "options": { + "id": "default", + }, + "version": { + "type": "local", + }, + }, + ], + "pluginsRouteConfigs": [], + "themeConfigTranslated": {}, +} +`; + +exports[`sortConfig sorts route config correctly 1`] = ` +[ + { + "component": "", + "path": "/community", + }, + { + "component": "", + "path": "/some-page", + }, + { + "component": "", + "path": "/docs", + "routes": [ + { + "component": "", + "path": "/docs/someDoc", + }, + { + "component": "", + "path": "/docs/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/", + }, + { + "component": "", + "path": "/", + "routes": [ + { + "component": "", + "path": "/someDoc", + }, + { + "component": "", + "path": "/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/", + "routes": [ + { + "component": "", + "path": "/subroute", + }, + ], + }, +] +`; + +exports[`sortConfig sorts route config given a baseURL 1`] = ` +[ + { + "component": "", + "path": "/latest/community", + }, + { + "component": "", + "path": "/latest/example", + }, + { + "component": "", + "path": "/latest/some-page", + }, + { + "component": "", + "path": "/latest/docs", + "routes": [ + { + "component": "", + "path": "/latest/docs/someDoc", + }, + { + "component": "", + "path": "/latest/docs/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/latest/", + }, + { + "component": "", + "path": "/latest/", + "routes": [ + { + "component": "", + "path": "/latest/someDoc", + }, + { + "component": "", + "path": "/latest/someOtherDoc", + }, + ], + }, +] +`; diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap index 2d8f4c1cad70..3c982b11453f 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap @@ -27,103 +27,3 @@ Example valid plugin config: " `; - -exports[`sortConfig sorts route config correctly 1`] = ` -[ - { - "component": "", - "path": "/community", - }, - { - "component": "", - "path": "/some-page", - }, - { - "component": "", - "path": "/docs", - "routes": [ - { - "component": "", - "path": "/docs/someDoc", - }, - { - "component": "", - "path": "/docs/someOtherDoc", - }, - ], - }, - { - "component": "", - "path": "/", - }, - { - "component": "", - "path": "/", - "routes": [ - { - "component": "", - "path": "/someDoc", - }, - { - "component": "", - "path": "/someOtherDoc", - }, - ], - }, - { - "component": "", - "path": "/", - "routes": [ - { - "component": "", - "path": "/subroute", - }, - ], - }, -] -`; - -exports[`sortConfig sorts route config given a baseURL 1`] = ` -[ - { - "component": "", - "path": "/latest/community", - }, - { - "component": "", - "path": "/latest/example", - }, - { - "component": "", - "path": "/latest/some-page", - }, - { - "component": "", - "path": "/latest/docs", - "routes": [ - { - "component": "", - "path": "/latest/docs/someDoc", - }, - { - "component": "", - "path": "/latest/docs/someOtherDoc", - }, - ], - }, - { - "component": "", - "path": "/latest", - "routes": [ - { - "component": "", - "path": "/latest/someDoc", - }, - { - "component": "", - "path": "/latest/someOtherDoc", - }, - ], - }, -] -`; diff --git a/packages/docusaurus/src/server/plugins/__tests__/index.test.ts b/packages/docusaurus/src/server/plugins/__tests__/index.test.ts new file mode 100644 index 000000000000..757c68d71d11 --- /dev/null +++ b/packages/docusaurus/src/server/plugins/__tests__/index.test.ts @@ -0,0 +1,139 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import {loadPlugins, sortConfig} from '..'; +import type {RouteConfig} from '@docusaurus/types'; + +describe('loadPlugins', () => { + it('loads plugins', async () => { + const siteDir = path.join(__dirname, '__fixtures__/site-with-plugin'); + await expect( + loadPlugins({ + pluginConfigs: [ + () => ({ + name: 'test1', + prop: 'a', + async loadContent() { + // Testing that plugin lifecycle is bound to the plugin instance + return this.prop; + }, + async contentLoaded({content, actions}) { + actions.setGlobalData({content, prop: this.prop}); + }, + }), + () => ({ + name: 'test2', + configureWebpack() { + return {}; + }, + }), + ], + + context: { + siteDir, + generatedFilesDir: path.join(siteDir, '.docusaurus'), + outDir: path.join(siteDir, 'build'), + // @ts-expect-error: good enough + siteConfig: { + baseUrl: '/', + trailingSlash: true, + themeConfig: {}, + }, + + siteConfigPath: path.join(siteDir, 'docusaurus.config.js'), + }, + }), + ).resolves.toMatchSnapshot(); + }); +}); + +describe('sortConfig', () => { + it('sorts route config correctly', () => { + const routes: RouteConfig[] = [ + { + path: '/', + component: '', + routes: [ + {path: '/someDoc', component: ''}, + {path: '/someOtherDoc', component: ''}, + ], + }, + { + path: '/', + component: '', + }, + { + path: '/', + component: '', + routes: [{path: '/subroute', component: ''}], + }, + { + path: '/docs', + component: '', + routes: [ + {path: '/docs/someDoc', component: ''}, + {path: '/docs/someOtherDoc', component: ''}, + ], + }, + { + path: '/community', + component: '', + }, + { + path: '/some-page', + component: '', + }, + ]; + + sortConfig(routes); + + expect(routes).toMatchSnapshot(); + }); + + it('sorts route config given a baseURL', () => { + const baseURL = '/latest/'; + const routes: RouteConfig[] = [ + { + path: baseURL, + component: '', + routes: [ + {path: `${baseURL}someDoc`, component: ''}, + {path: `${baseURL}someOtherDoc`, component: ''}, + ], + }, + { + path: `${baseURL}example`, + component: '', + }, + { + path: `${baseURL}docs`, + component: '', + routes: [ + {path: `${baseURL}docs/someDoc`, component: ''}, + {path: `${baseURL}docs/someOtherDoc`, component: ''}, + ], + }, + { + path: `${baseURL}community`, + component: '', + }, + { + path: `${baseURL}some-page`, + component: '', + }, + { + path: `${baseURL}`, + component: '', + }, + ]; + + sortConfig(routes, baseURL); + + expect(routes).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index a000f6e471f7..87a553cb9247 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -13,8 +13,6 @@ import { type LoadContextOptions, } from '../../index'; import initPlugins from '../init'; -import {sortConfig} from '../index'; -import type {RouteConfig} from '@docusaurus/types'; describe('initPlugins', () => { async function loadSite(options: LoadContextOptions = {}) { @@ -53,85 +51,3 @@ describe('initPlugins', () => { ).rejects.toThrowErrorMatchingSnapshot(); }); }); - -describe('sortConfig', () => { - it('sorts route config correctly', () => { - const routes: RouteConfig[] = [ - { - path: '/', - component: '', - routes: [ - {path: '/someDoc', component: ''}, - {path: '/someOtherDoc', component: ''}, - ], - }, - { - path: '/', - component: '', - }, - { - path: '/', - component: '', - routes: [{path: '/subroute', component: ''}], - }, - { - path: '/docs', - component: '', - routes: [ - {path: '/docs/someDoc', component: ''}, - {path: '/docs/someOtherDoc', component: ''}, - ], - }, - { - path: '/community', - component: '', - }, - { - path: '/some-page', - component: '', - }, - ]; - - sortConfig(routes); - - expect(routes).toMatchSnapshot(); - }); - - it('sorts route config given a baseURL', () => { - const baseURL = '/latest'; - const routes: RouteConfig[] = [ - { - path: baseURL, - component: '', - routes: [ - {path: `${baseURL}/someDoc`, component: ''}, - {path: `${baseURL}/someOtherDoc`, component: ''}, - ], - }, - { - path: `${baseURL}/example`, - component: '', - }, - { - path: `${baseURL}/docs`, - component: '', - routes: [ - {path: `${baseURL}/docs/someDoc`, component: ''}, - {path: `${baseURL}/docs/someOtherDoc`, component: ''}, - ], - }, - { - path: `${baseURL}/community`, - component: '', - }, - { - path: `${baseURL}/some-page`, - component: '', - }, - ]; - - sortConfig(routes, baseURL); - - expect(routes).toMatchSnapshot(); - }); -}); diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index c7983f16cf01..b279b4d7a659 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {generate, DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; +import {generate} from '@docusaurus/utils'; import fs from 'fs-extra'; import path from 'path'; import type { @@ -125,7 +125,7 @@ export async function loadPlugins({ .groupBy((item) => item.name) .mapValues((nameItems) => _.chain(nameItems) - .groupBy((item) => item.options.id ?? DEFAULT_PLUGIN_ID) + .groupBy((item) => item.options.id) .mapValues((idItems) => idItems[0]!.content) .value(), ) @@ -143,7 +143,7 @@ export async function loadPlugins({ return; } - const pluginId = plugin.options.id ?? DEFAULT_PLUGIN_ID; + const pluginId = plugin.options.id; // plugins data files are namespaced by pluginName/pluginId const dataDirRoot = path.join(context.generatedFilesDir, plugin.name); diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-qux.js b/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-mixed.js similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-qux.js rename to packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-mixed.js diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-bar.js b/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-plugins.js similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-bar.js rename to packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-plugins.js diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-foo.js b/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-themes.js similarity index 68% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-foo.js rename to packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-themes.js index b2fbdfedde34..fa6c08dfa66a 100644 --- a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-foo.js +++ b/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-themes.js @@ -7,9 +7,9 @@ module.exports = function preset(context, opts = {}) { return { - plugins: [ - ['@docusaurus/plugin-content-pages', opts.pages], - ['@docusaurus/plugin-sitemap', opts.sitemap], + themes: [ + ['@docusaurus/theme-live-codeblock', opts.codeblock], + ['@docusaurus/theme-algolia', opts.algolia], ], }; }; diff --git a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap index 160beefa431d..84f8e1be4bfe 100644 --- a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap @@ -29,18 +29,19 @@ exports[`loadPresets array form composite 1`] = ` "@docusaurus/plugin-content-blog", undefined, ], + ], + "themes": [ [ - "@docusaurus/plugin-content-pages", - { - "path": "../", - }, + "@docusaurus/theme-live-codeblock", + undefined, ], [ - "@docusaurus/plugin-sitemap", - undefined, + "@docusaurus/theme-algolia", + { + "trackingID": "foo", + }, ], ], - "themes": [], } `; @@ -75,16 +76,17 @@ exports[`loadPresets mixed form 1`] = ` "@docusaurus/plugin-content-blog", undefined, ], + ], + "themes": [ [ - "@docusaurus/plugin-content-pages", + "@docusaurus/theme-live-codeblock", undefined, ], [ - "@docusaurus/plugin-sitemap", + "@docusaurus/theme-algolia", undefined, ], ], - "themes": [], } `; @@ -102,19 +104,19 @@ exports[`loadPresets mixed form with themes 1`] = ` undefined, ], [ - "@docusaurus/plugin-content-pages", + "@docusaurus/plugin-test", undefined, ], + ], + "themes": [ [ - "@docusaurus/plugin-sitemap", + "@docusaurus/theme-live-codeblock", undefined, ], [ - "@docusaurus/plugin-test", + "@docusaurus/theme-algolia", undefined, ], - ], - "themes": [ [ "@docusaurus/theme-classic", undefined, @@ -150,15 +152,16 @@ exports[`loadPresets string form composite 1`] = ` "@docusaurus/plugin-content-blog", undefined, ], + ], + "themes": [ [ - "@docusaurus/plugin-content-pages", + "@docusaurus/theme-live-codeblock", undefined, ], [ - "@docusaurus/plugin-sitemap", + "@docusaurus/theme-algolia", undefined, ], ], - "themes": [], } `; diff --git a/packages/docusaurus/src/server/presets/__tests__/index.test.ts b/packages/docusaurus/src/server/presets/__tests__/index.test.ts index 444c5972384b..c3ce1f8b0685 100644 --- a/packages/docusaurus/src/server/presets/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/presets/__tests__/index.test.ts @@ -31,7 +31,7 @@ describe('loadPresets', () => { const context = { siteConfigPath: __dirname, siteConfig: { - presets: [path.join(__dirname, '__fixtures__/preset-bar.js')], + presets: [path.join(__dirname, '__fixtures__/preset-plugins.js')], }, } as LoadContext; const presets = await loadPresets(context); @@ -43,8 +43,8 @@ describe('loadPresets', () => { siteConfigPath: __dirname, siteConfig: { presets: [ - path.join(__dirname, '__fixtures__/preset-bar.js'), - path.join(__dirname, '__fixtures__/preset-foo.js'), + path.join(__dirname, '__fixtures__/preset-plugins.js'), + path.join(__dirname, '__fixtures__/preset-themes.js'), ], }, } as LoadContext; @@ -56,7 +56,7 @@ describe('loadPresets', () => { const context = { siteConfigPath: __dirname, siteConfig: { - presets: [[path.join(__dirname, '__fixtures__/preset-bar.js')]], + presets: [[path.join(__dirname, '__fixtures__/preset-plugins.js')]], }, } as Partial<LoadContext>; const presets = await loadPresets(context); @@ -69,7 +69,7 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-bar.js'), + path.join(__dirname, '__fixtures__/preset-plugins.js'), {docs: {path: '../'}}, ], ], @@ -85,12 +85,12 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-bar.js'), + path.join(__dirname, '__fixtures__/preset-plugins.js'), {docs: {path: '../'}}, ], [ - path.join(__dirname, '__fixtures__/preset-foo.js'), - {pages: {path: '../'}}, + path.join(__dirname, '__fixtures__/preset-themes.js'), + {algolia: {trackingID: 'foo'}}, ], ], }, @@ -105,10 +105,10 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-bar.js'), + path.join(__dirname, '__fixtures__/preset-plugins.js'), {docs: {path: '../'}}, ], - path.join(__dirname, '__fixtures__/preset-foo.js'), + path.join(__dirname, '__fixtures__/preset-themes.js'), ], }, } as LoadContext; @@ -122,11 +122,11 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-bar.js'), + path.join(__dirname, '__fixtures__/preset-plugins.js'), {docs: {path: '../'}}, ], - path.join(__dirname, '__fixtures__/preset-foo.js'), - path.join(__dirname, '__fixtures__/preset-qux.js'), + path.join(__dirname, '__fixtures__/preset-themes.js'), + path.join(__dirname, '__fixtures__/preset-mixed.js'), ], }, } as LoadContext; diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index ad91a94fb551..c2105c07ce84 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -30,7 +30,7 @@ function indent(str: string) { return `${spaces}${str.replace(/\n/g, `\n${spaces}`)}`; } -const createRouteCodeString = ({ +function createRouteCodeString({ routePath, routeHash, exact, @@ -42,7 +42,7 @@ const createRouteCodeString = ({ exact?: boolean; subroutesCodeStrings?: string[]; props: {[propName: string]: unknown}; -}) => { +}) { const parts = [ `path: '${routePath}'`, `component: ComponentCreator('${routePath}','${routeHash}')`, @@ -61,17 +61,30 @@ ${indent(removeSuffix(subroutesCodeStrings.join(',\n'), ',\n'))} } Object.entries(props).forEach(([propName, propValue]) => { - // Figure out how to "unquote" JS attributes that don't need to be quoted - // Is this lib reliable? https://github.com/armanozak/should-quote - const shouldQuote = true; // TODO - const key = shouldQuote ? `'${propName}'` : propName; + // Inspired by https://github.com/armanozak/should-quote/blob/main/packages/should-quote/src/lib/should-quote.ts + const shouldQuote = ((key: string) => { + // Pre-sanitation to prevent injection + if (/[.,;:}/\s]/.test(key)) { + return true; + } + try { + // If this key can be used in an expression like ({a:0}).a + // eslint-disable-next-line no-eval + eval(`({${key}:0}).${key}`); + return false; + } catch { + return true; + } + })(propName); + // Escape quotes as well + const key = shouldQuote ? JSON.stringify(propName) : propName; parts.push(`${key}: ${JSON.stringify(propValue)}`); }); return `{ ${indent(parts.join(',\n'))} }`; -}; +} const NotFoundRouteCode = `{ path: '*', diff --git a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts index cb2f7c149e47..b0a22e9c158c 100644 --- a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts +++ b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts @@ -7,7 +7,51 @@ import path from 'path'; import fs from 'fs-extra'; -import themeAlias from '../alias'; +import themeAlias, {sortAliases} from '../alias'; + +describe('sortAliases', () => { + // https://github.com/facebook/docusaurus/issues/6878 + // Not sure if the risk actually happens, but still made tests to ensure that + // behavior is consistent + it('sorts reliably', () => { + expect( + Object.values( + sortAliases({ + '@a/b': 'b', + '@a/b/c': 'c', + '@a/b/c/d': 'd', + }), + ), + ).toEqual(['d', 'c', 'b']); + expect( + Object.values( + sortAliases({ + '@a/b': 'b', + '@a/b/c/d': 'd', + '@a/b/c': 'c', + }), + ), + ).toEqual(['d', 'c', 'b']); + expect( + Object.values( + sortAliases({ + '@a/b/c/d': 'd', + '@a/b/c': 'c', + '@a/b': 'b', + }), + ), + ).toEqual(['d', 'c', 'b']); + expect( + Object.values( + sortAliases({ + '@a/b/c': 'c', + '@a/b': 'b', + '@a/b/c/d': 'd', + }), + ), + ).toEqual(['d', 'c', 'b']); + }); +}); describe('themeAlias', () => { it('valid themePath 1 with components', async () => { diff --git a/packages/docusaurus/src/server/themes/index.ts b/packages/docusaurus/src/server/themes/index.ts index 51b114846bdb..b90ec7c497bb 100644 --- a/packages/docusaurus/src/server/themes/index.ts +++ b/packages/docusaurus/src/server/themes/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import {THEME_PATH} from '@docusaurus/utils'; import themeAlias, {sortAliases} from './alias'; -const ThemeFallbackDir = path.resolve(__dirname, '../../client/theme-fallback'); +const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback'); export async function loadThemeAliases( themePaths: string[], diff --git a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts index 54871689edf8..b4dda430760b 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts @@ -7,10 +7,9 @@ import {jest} from '@jest/globals'; import { - ensureTranslationFileContent, - writeTranslationFileContent, writePluginTranslations, - readTranslationFileContent, + writeCodeTranslations, + readCodeTranslationFileContent, type WriteTranslationsOptions, localizePluginTranslationFile, getPluginsDefaultCodeTranslationMessages, @@ -35,129 +34,93 @@ async function createTmpSiteDir() { async function createTmpTranslationFile( content: TranslationFileContent | null, ) { - const filePath = await tmp.tmpName({ - prefix: 'jest-createTmpTranslationFile', - postfix: '.json', - }); + const siteDir = await createTmpSiteDir(); + const filePath = path.join(siteDir, 'i18n/en/code.json'); // null means we don't want a file, just a filename if (content !== null) { - await fs.writeFile(filePath, JSON.stringify(content, null, 2)); + await fs.outputFile(filePath, JSON.stringify(content, null, 2)); } return { - filePath, - readFile: async () => JSON.parse(await fs.readFile(filePath, 'utf8')), + siteDir, + readFile() { + return fs.readJSON(filePath); + }, }; } -describe('ensureTranslationFileContent', () => { - it('passes valid translation file content', () => { - ensureTranslationFileContent({}); - ensureTranslationFileContent({key1: {message: ''}}); - ensureTranslationFileContent({key1: {message: 'abc'}}); - ensureTranslationFileContent({key1: {message: 'abc', description: 'desc'}}); - ensureTranslationFileContent({ - key1: {message: 'abc', description: 'desc'}, - key2: {message: 'def', description: 'desc'}, - }); - }); - - it('fails for invalid translation file content', () => { - expect(() => - ensureTranslationFileContent(null), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, - ); - expect(() => - ensureTranslationFileContent(undefined), - ).toThrowErrorMatchingInlineSnapshot(`"\\"value\\" is required"`); - expect(() => - ensureTranslationFileContent('HEY'), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, - ); - expect(() => - ensureTranslationFileContent(42), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, - ); - expect(() => - ensureTranslationFileContent({key: {description: 'no message'}}), - ).toThrowErrorMatchingInlineSnapshot(`"\\"key.message\\" is required"`); - expect(() => - ensureTranslationFileContent({key: {message: 42}}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"key.message\\" must be a string"`, - ); - expect(() => - ensureTranslationFileContent({ - key: {message: 'Message', description: 42}, - }), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"key.description\\" must be a string"`, - ); +describe('writeCodeTranslations', () => { + const consoleInfoMock = jest + .spyOn(console, 'info') + .mockImplementation(() => {}); + beforeEach(() => { + consoleInfoMock.mockClear(); }); -}); -describe('writeTranslationFileContent', () => { it('creates new translation file', async () => { - const {filePath, readFile} = await createTmpTranslationFile(null); - - await writeTranslationFileContent({ - filePath, - content: { + const {siteDir, readFile} = await createTmpTranslationFile(null); + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, key3: {message: 'key3 message'}, }, - }); + {}, + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, key3: {message: 'key3 message'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/3.* translations will be written/), + ); }); it('creates new translation file with prefix', async () => { - const {filePath, readFile} = await createTmpTranslationFile(null); - - await writeTranslationFileContent({ - filePath, - content: { + const {siteDir, readFile} = await createTmpTranslationFile(null); + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, key3: {message: 'key3 message'}, }, - options: { + { messagePrefix: 'PREFIX ', }, - }); + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'PREFIX key1 message'}, key2: {message: 'PREFIX key2 message'}, key3: {message: 'PREFIX key3 message'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/3.* translations will be written/), + ); }); it('appends missing translations', async () => { - const {filePath, readFile} = await createTmpTranslationFile({ + const {siteDir, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, key3: {message: 'key3 message'}, }); - await writeTranslationFileContent({ - filePath, - content: { + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message new'}, key2: {message: 'key2 message new'}, key3: {message: 'key3 message new'}, key4: {message: 'key4 message new'}, }, - }); + {}, + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'key1 message'}, @@ -165,111 +128,139 @@ describe('writeTranslationFileContent', () => { key3: {message: 'key3 message'}, key4: {message: 'key4 message new'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/4.* translations will be written/), + ); }); - it('appends missing translations with prefix', async () => { - const {filePath, readFile} = await createTmpTranslationFile({ + it('appends missing.* translations with prefix', async () => { + const {siteDir, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); - await writeTranslationFileContent({ - filePath, - content: { + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message new'}, key2: {message: 'key2 message new'}, }, - options: { + { messagePrefix: 'PREFIX ', }, - }); + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'key1 message'}, key2: {message: 'PREFIX key2 message new'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/2.* translations will be written/), + ); }); it('overrides missing translations', async () => { - const {filePath, readFile} = await createTmpTranslationFile({ + const {siteDir, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); - await writeTranslationFileContent({ - filePath, - content: { + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message new'}, key2: {message: 'key2 message new'}, }, - options: { + { override: true, }, - }); + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'key1 message new'}, key2: {message: 'key2 message new'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/2.* translations will be written/), + ); }); it('overrides missing translations with prefix', async () => { - const {filePath, readFile} = await createTmpTranslationFile({ + const {siteDir, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message'}, }); - await writeTranslationFileContent({ - filePath, - content: { + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message new'}, key2: {message: 'key2 message new'}, }, - options: { + { override: true, messagePrefix: 'PREFIX ', }, - }); + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'PREFIX key1 message new'}, key2: {message: 'PREFIX key2 message new'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/2.* translations will be written/), + ); }); it('always overrides message description', async () => { - const {filePath, readFile} = await createTmpTranslationFile({ + const {siteDir, readFile} = await createTmpTranslationFile({ key1: {message: 'key1 message', description: 'key1 desc'}, key2: {message: 'key2 message', description: 'key2 desc'}, key3: {message: 'key3 message', description: undefined}, }); - await writeTranslationFileContent({ - filePath, - content: { + await writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message new', description: undefined}, key2: {message: 'key2 message new', description: 'key2 desc new'}, key3: {message: 'key3 message new', description: 'key3 desc new'}, }, - }); + {}, + ); await expect(readFile()).resolves.toEqual({ key1: {message: 'key1 message', description: undefined}, key2: {message: 'key2 message', description: 'key2 desc new'}, key3: {message: 'key3 message', description: 'key3 desc new'}, }); + expect(consoleInfoMock).toBeCalledWith( + expect.stringMatching(/3.* translations will be written/), + ); + }); + + it('does not create empty translation files', async () => { + const {siteDir, readFile} = await createTmpTranslationFile(null); + + await writeCodeTranslations({siteDir, locale: 'en'}, {}, {}); + + await expect(readFile()).rejects.toThrowError( + /ENOENT: no such file or directory, open /, + ); + expect(consoleInfoMock).toBeCalledTimes(0); }); it('throws for invalid content', async () => { - const {filePath} = await createTmpTranslationFile( + const {siteDir} = await createTmpTranslationFile( // @ts-expect-error: bad content on purpose {bad: 'content'}, ); - await expect( - writeTranslationFileContent({ - filePath, - content: { + await expect(() => + writeCodeTranslations( + {siteDir, locale: 'en'}, + { key1: {message: 'key1 message'}, }, - }), + {}, + ), ).rejects.toThrowErrorMatchingInlineSnapshot( `"\\"bad\\" must be of type object"`, ); @@ -308,7 +299,7 @@ describe('writePluginTranslations', () => { }, }); - await expect(readTranslationFileContent(filePath)).resolves.toEqual({ + await expect(fs.readJSON(filePath)).resolves.toEqual({ key1: {message: 'key1 message'}, key2: {message: 'key2 message'}, key3: {message: 'key3 message'}, @@ -348,14 +339,12 @@ describe('writePluginTranslations', () => { }); } - await expect(readTranslationFileContent(filePath)).resolves.toBeUndefined(); - await doWritePluginTranslations({ key1: {message: 'key1 message', description: 'key1 desc'}, key2: {message: 'key2 message', description: 'key2 desc'}, key3: {message: 'key3 message', description: 'key3 desc'}, }); - await expect(readTranslationFileContent(filePath)).resolves.toEqual({ + await expect(fs.readJSON(filePath)).resolves.toEqual({ key1: {message: 'key1 message', description: 'key1 desc'}, key2: {message: 'key2 message', description: 'key2 desc'}, key3: {message: 'key3 message', description: 'key3 desc'}, @@ -368,7 +357,7 @@ describe('writePluginTranslations', () => { }, {messagePrefix: 'PREFIX '}, ); - await expect(readTranslationFileContent(filePath)).resolves.toEqual({ + await expect(fs.readJSON(filePath)).resolves.toEqual({ key1: {message: 'key1 message', description: 'key1 desc'}, key2: {message: 'key2 message', description: 'key2 desc'}, key3: {message: 'key3 message', description: undefined}, @@ -384,13 +373,39 @@ describe('writePluginTranslations', () => { }, {messagePrefix: 'PREFIX ', override: true}, ); - await expect(readTranslationFileContent(filePath)).resolves.toEqual({ + await expect(fs.readJSON(filePath)).resolves.toEqual({ key1: {message: 'PREFIX key1 message 3', description: 'key1 desc'}, key2: {message: 'PREFIX key2 message 3', description: 'key2 desc'}, key3: {message: 'PREFIX key3 message 3', description: 'key3 desc'}, key4: {message: 'PREFIX key4 message 3', description: 'key4 desc'}, }); }); + + it('throws with explicit extension', async () => { + const siteDir = await createTmpSiteDir(); + + await expect(() => + writePluginTranslations({ + siteDir, + locale: 'fr', + translationFile: { + path: 'my/translation/file.json', + content: {}, + }, + + plugin: { + name: 'my-plugin-name', + options: { + id: 'my-plugin-id', + }, + }, + + options: {}, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Translation file path at \\"my/translation/file.json\\" does not need to end with \\".json\\", we add the extension automatically."`, + ); + }); }); describe('localizePluginTranslationFile', () => { @@ -420,22 +435,22 @@ describe('localizePluginTranslationFile', () => { expect(localizedTranslationFile).toEqual(translationFile); }); - it('does not localize if localized file does not exist 2', async () => { + it('normalizes partially localized translation files', async () => { const siteDir = await createTmpSiteDir(); - await writeTranslationFileContent({ - filePath: path.join( + await fs.outputJSON( + path.join( siteDir, 'i18n', 'fr', 'my-plugin-name', 'my/translation/file.json', ), - content: { + { key2: {message: 'key2 message localized'}, key4: {message: 'key4 message localized'}, }, - }); + ); const translationFile: TranslationFile = { path: 'my/translation/file', @@ -472,6 +487,68 @@ describe('localizePluginTranslationFile', () => { }); }); +describe('readCodeTranslationFileContent', () => { + async function testReadTranslation(val: TranslationFileContent) { + const {siteDir} = await createTmpTranslationFile(val); + return readCodeTranslationFileContent({siteDir, locale: 'en'}); + } + + it("returns undefined if file does't exist", async () => { + await expect( + readCodeTranslationFileContent({siteDir: 'foo', locale: 'en'}), + ).resolves.toBeUndefined(); + }); + + it('passes valid translation file content', async () => { + await expect(testReadTranslation({})).resolves.toEqual({}); + await expect(testReadTranslation({key1: {message: ''}})).resolves.toEqual({ + key1: {message: ''}, + }); + await expect( + testReadTranslation({key1: {message: 'abc', description: 'desc'}}), + ).resolves.toEqual({key1: {message: 'abc', description: 'desc'}}); + await expect( + testReadTranslation({ + key1: {message: 'abc', description: 'desc'}, + key2: {message: 'def', description: 'desc'}, + }), + ).resolves.toEqual({ + key1: {message: 'abc', description: 'desc'}, + key2: {message: 'def', description: 'desc'}, + }); + }); + + it('fails for invalid translation file content', async () => { + await expect(() => + testReadTranslation('HEY'), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"value\\" must be of type object"`, + ); + await expect(() => + testReadTranslation(42), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"value\\" must be of type object"`, + ); + await expect(() => + testReadTranslation({key: {description: 'no message'}}), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"key.message\\" is required"`, + ); + await expect(() => + testReadTranslation({key: {message: 42}}), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"key.message\\" must be a string"`, + ); + await expect(() => + testReadTranslation({ + key: {message: 'Message', description: 42}, + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"\\"key.description\\" must be a string"`, + ); + }); +}); + describe('getPluginsDefaultCodeTranslationMessages', () => { function createTestPlugin( fn: InitializedPlugin['getDefaultCodeTranslationMessages'], @@ -559,9 +636,11 @@ describe('getPluginsDefaultCodeTranslationMessages', () => { }); describe('applyDefaultCodeTranslations', () => { - const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + const consoleWarnMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); beforeEach(() => { - consoleSpy.mockClear(); + consoleWarnMock.mockClear(); }); it('works for no code and message', () => { @@ -571,7 +650,7 @@ describe('applyDefaultCodeTranslations', () => { defaultCodeMessages: {}, }), ).toEqual({}); - expect(consoleSpy).toHaveBeenCalledTimes(0); + expect(consoleWarnMock).toHaveBeenCalledTimes(0); }); it('works for code and message', () => { @@ -593,7 +672,7 @@ describe('applyDefaultCodeTranslations', () => { description: 'description', }, }); - expect(consoleSpy).toHaveBeenCalledTimes(0); + expect(consoleWarnMock).toHaveBeenCalledTimes(0); }); it('works for code and message mismatch', () => { @@ -615,8 +694,8 @@ describe('applyDefaultCodeTranslations', () => { description: 'description', }, }); - expect(consoleSpy).toHaveBeenCalledTimes(1); - expect(consoleSpy.mock.calls[0][0]).toMatch(/unknownId/); + expect(consoleWarnMock).toHaveBeenCalledTimes(1); + expect(consoleWarnMock.mock.calls[0][0]).toMatch(/unknownId/); }); it('works for realistic scenario', () => { @@ -657,8 +736,8 @@ describe('applyDefaultCodeTranslations', () => { description: 'description 3', }, }); - expect(consoleSpy).toHaveBeenCalledTimes(1); - expect(consoleSpy.mock.calls[0][0]).toMatch(/idUnknown1/); - expect(consoleSpy.mock.calls[0][0]).toMatch(/idUnknown2/); + expect(consoleWarnMock).toHaveBeenCalledTimes(1); + expect(consoleWarnMock.mock.calls[0][0]).toMatch(/idUnknown1/); + expect(consoleWarnMock.mock.calls[0][0]).toMatch(/idUnknown2/); }); }); diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index 869175c1799f..5b80021d7043 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -232,6 +232,7 @@ export default function MyComponent<T>(props: ComponentProps<T>) { return ( <div> <input text={translate({id: 'codeId',message: 'code message',description: 'code description'}) as string}/> + <input text={translate({message: 'code message 2',description: 'code description 2'}) as string}/> </div> ); } @@ -247,6 +248,10 @@ export default function MyComponent<T>(props: ComponentProps<T>) { sourceCodeFilePath, translations: { codeId: {message: 'code message', description: 'code description'}, + 'code message 2': { + message: 'code message 2', + description: 'code description 2', + }, }, warnings: [], }); @@ -636,6 +641,26 @@ export default function MyComponent() { } `, ); + + const plugin1File4 = path.join(plugin1Dir, 'src/theme/file4.jsx'); + // Contains some invalid translations... + await fs.outputFile( + plugin1File4, + ` +import {translate} from '@docusaurus/Translate'; + +export default function MyComponent() { + return ( + <div> + <input text={translate({id: index})}/> + </div> + ); +} +`, + ); + const consoleWarnMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); const plugin1 = createTestPlugin(plugin1Dir); const plugin2Dir = await createTmpDir(); @@ -664,7 +689,11 @@ export default function MyComponent(props: Props) { ); const plugin2 = createTestPlugin(plugin2Dir); - const plugins = [plugin1, plugin2]; + const plugins = [ + plugin1, + plugin2, + {name: 'dummy', options: {}, version: {type: 'synthetic'}} as const, + ]; const translations = await extractSiteSourceCodeTranslations( siteDir, plugins, @@ -692,5 +721,8 @@ export default function MyComponent(props: Props) { message: 'plugin2 message 2', }, }); + expect(consoleWarnMock.mock.calls[0][0]).toMatch( + /.*\[WARNING\].* Translation extraction warnings for file .*src.theme.file4\.jsx.*\n.*- translate\(\) first arg should be a statically evaluable object\./, + ); }); }); diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index 1e6fce136707..cba14d1f3e18 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -38,7 +38,7 @@ const TranslationFileContentSchema = Joi.object<TranslationFileContent>() ) .required(); -export function ensureTranslationFileContent( +function ensureTranslationFileContent( content: unknown, ): asserts content is TranslationFileContent { Joi.attempt(content, TranslationFileContentSchema, { @@ -48,7 +48,7 @@ export function ensureTranslationFileContent( }); } -export async function readTranslationFileContent( +async function readTranslationFileContent( filePath: string, ): Promise<TranslationFileContent | undefined> { if (await fs.pathExists(filePath)) { @@ -97,7 +97,7 @@ function mergeTranslationFileContent({ return result; } -export async function writeTranslationFileContent({ +async function writeTranslationFileContent({ filePath, content: newContent, options = {}, @@ -139,7 +139,7 @@ Maybe you should remove them? ${unknownKeys}`; } // should we make this configurable? -export function getTranslationsDirPath(context: TranslationContext): string { +function getTranslationsDirPath(context: TranslationContext): string { return path.resolve(path.join(context.siteDir, `i18n`)); } export function getTranslationsLocaleDirPath( @@ -148,9 +148,7 @@ export function getTranslationsLocaleDirPath( return path.join(getTranslationsDirPath(context), context.locale); } -export function getCodeTranslationsFilePath( - context: TranslationContext, -): string { +function getCodeTranslationsFilePath(context: TranslationContext): string { return path.join(getTranslationsLocaleDirPath(context), 'code.json'); } diff --git a/packages/stylelint-copyright/__tests__/index.test.js b/packages/stylelint-copyright/__tests__/index.test.js index e44dfbbeeb24..0d6ea8efe5eb 100644 --- a/packages/stylelint-copyright/__tests__/index.test.js +++ b/packages/stylelint-copyright/__tests__/index.test.js @@ -40,7 +40,7 @@ function testStylelintRule(config, tests) { } const fixedOutput = await stylelint.lint({...options, fix: true}); const fixedCode = getOutputCss(fixedOutput); - expect(fixedCode).toBe(testCase.fixed); + expect(fixedCode).toBe(testCase.code); }); }); }); @@ -113,22 +113,63 @@ testStylelintRule( }, { ruleName, - fix: false, + fix: true, accept: [ { code: ` /** * Copyright */ +.foo {}`, + }, + { + code: `/** + * Copyright + */ - .foo {}`, +.foo {}`, + }, + { + code: `/** + * Copyright + */ +.foo {}`, }, ], reject: [ + { + code: `.foo {}`, + fixed: `/** + * Copyright + */ +.foo {}`, + message: messages.rejected, + line: 1, + column: 1, + }, { code: ` - /** -* copyright +.foo {}`, + fixed: `/** + * Copyright + */ +.foo {}`, + message: messages.rejected, + line: 1, + column: 1, + }, + { + code: `/** +* Copyright +*/ + +.foo {}`, + fixed: `/** + * Copyright + */ + +/** +* Copyright */ .foo {}`, @@ -137,18 +178,37 @@ testStylelintRule( column: 1, }, { - code: ` + code: `/** + * Copyleft + */ + +.foo {}`, + fixed: `/** + * Copyright + */ + /** * Copyleft */ - .foo {}`, +.foo {}`, message: messages.rejected, line: 1, column: 1, }, { - code: ` + code: `/** + * Copyleft + */ + +/** + * Copyright + */ + .foo {}`, + fixed: `/** + * Copyright + */ + /** * Copyleft */ diff --git a/packages/stylelint-copyright/index.js b/packages/stylelint-copyright/index.js index adf34dd2fd7d..fdf2ab794ba9 100644 --- a/packages/stylelint-copyright/index.js +++ b/packages/stylelint-copyright/index.js @@ -15,7 +15,7 @@ const messages = stylelint.utils.ruleMessages(ruleName, { const plugin = stylelint.createPlugin( ruleName, (primaryOption, secondaryOption, context) => (root, result) => { - const validOptions = stylelint.utils.validateOptions( + stylelint.utils.validateOptions( result, ruleName, { @@ -28,10 +28,6 @@ const plugin = stylelint.createPlugin( }, ); - if (!validOptions) { - return; - } - if ( root.first && root.first.type === 'comment' && From ff1b7168baef93ffb431dda6ca604895e02453a0 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Tue, 15 Mar 2022 13:16:21 +0800 Subject: [PATCH 016/405] chore: upgrade dependencies (#6916) --- admin/new.docusaurus.io/package.json | 2 +- package.json | 20 +- .../templates/classic-typescript/package.json | 8 +- .../templates/classic/package.json | 4 +- .../templates/facebook/package.json | 14 +- .../docusaurus-cssnano-preset/package.json | 2 +- packages/docusaurus-mdx-loader/package.json | 4 +- packages/docusaurus-migrate/package.json | 8 +- .../package.json | 2 +- packages/docusaurus-plugin-pwa/package.json | 4 +- .../docusaurus-theme-classic/package.json | 4 +- .../package.json | 2 +- packages/docusaurus-utils/package.json | 4 +- packages/docusaurus/package.json | 12 +- packages/lqip-loader/package.json | 4 +- website/docs/migration/migration-manual.md | 4 +- website/package.json | 8 +- .../migration/migration-manual.md | 4 +- .../migration/migration-manual.md | 4 +- yarn.lock | 1282 +++++++++-------- 20 files changed, 699 insertions(+), 697 deletions(-) diff --git a/admin/new.docusaurus.io/package.json b/admin/new.docusaurus.io/package.json index 677299f656d6..0bb4203a14e0 100644 --- a/admin/new.docusaurus.io/package.json +++ b/admin/new.docusaurus.io/package.json @@ -9,6 +9,6 @@ "@netlify/functions": "^1.0.0" }, "devDependencies": { - "netlify-cli": "^9.13.0" + "netlify-cli": "^9.13.1" } } diff --git a/package.json b/package.json index a687ac54c40f..fb186a2b162a 100644 --- a/package.json +++ b/package.json @@ -61,33 +61,33 @@ }, "devDependencies": { "@babel/cli": "^7.17.6", - "@babel/core": "^7.17.5", + "@babel/core": "^7.17.7", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", - "@types/lodash": "^4.14.179", + "@types/lodash": "^4.14.180", "@types/node": "^17.0.21", "@types/prompts": "^2.0.14", - "@types/react": "^17.0.39", + "@types/react": "^17.0.40", "@types/react-dev-utils": "^9.0.10", "@types/react-test-renderer": "^17.0.1", "@types/semver": "^7.3.9", "@types/shelljs": "^0.8.11", - "@typescript-eslint/eslint-plugin": "^5.14.0", - "@typescript-eslint/parser": "^5.14.0", + "@typescript-eslint/eslint-plugin": "^5.15.0", + "@typescript-eslint/parser": "^5.15.0", "concurrently": "^7.0.0", "cross-env": "^7.0.3", - "cspell": "^5.18.5", - "eslint": "^8.10.0", + "cspell": "^5.19.2", + "eslint": "^8.11.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jest": "^26.1.1", "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.29.3", + "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-regexp": "^1.5.1", "husky": "^7.0.4", @@ -96,7 +96,7 @@ "lerna": "^4.0.0", "lerna-changelog": "^2.2.0", "lint-staged": "^12.3.5", - "netlify-cli": "^9.13.0", + "netlify-cli": "^9.13.1", "nodemon": "^2.0.15", "prettier": "^2.5.1", "react": "^17.0.2", @@ -104,7 +104,7 @@ "react-test-renderer": "^17.0.2", "remark-parse": "^8.0.2", "rimraf": "^3.0.2", - "sharp": "^0.30.2", + "sharp": "^0.30.3", "stylelint": "^14.5.3", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard": "^25.0.0", diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json index 9f93f84d81e2..e2990456ef03 100644 --- a/packages/create-docusaurus/templates/classic-typescript/package.json +++ b/packages/create-docusaurus/templates/classic-typescript/package.json @@ -19,13 +19,13 @@ "@docusaurus/preset-classic": "2.0.0-beta.17", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "prism-react-renderer": "^1.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "prism-react-renderer": "^1.3.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@tsconfig/docusaurus": "^1.0.4", + "@tsconfig/docusaurus": "^1.0.5", "typescript": "^4.6.2" }, "browserslist": { diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index 6248aefec3e0..b70d0a701a9c 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -19,8 +19,8 @@ "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "prism-react-renderer": "^1.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "browserslist": { "production": [ diff --git a/packages/create-docusaurus/templates/facebook/package.json b/packages/create-docusaurus/templates/facebook/package.json index ac3f43d874be..5941d4e692a6 100644 --- a/packages/create-docusaurus/templates/facebook/package.json +++ b/packages/create-docusaurus/templates/facebook/package.json @@ -22,18 +22,18 @@ "@docusaurus/preset-classic": "2.0.0-beta.17", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "devDependencies": { - "@babel/eslint-parser": "^7.16.3", - "eslint": "^8.8.0", - "eslint-config-airbnb": "^19.0.0", + "@babel/eslint-parser": "^7.17.0", + "eslint": "^8.11.0", + "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", - "eslint-plugin-import": "^2.25.3", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.29.3", + "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", "prettier": "^2.5.1", "stylelint": "^14.5.3" diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index 5499124e0a26..e5e13b73ce26 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -13,7 +13,7 @@ "directory": "packages/docusaurus-cssnano-preset" }, "dependencies": { - "cssnano-preset-advanced": "^5.2.1", + "cssnano-preset-advanced": "^5.2.5", "postcss": "^8.4.8", "postcss-sort-media-queries": "^4.2.1" }, diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 3d12f47209db..9ad42c9bd073 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -18,7 +18,7 @@ }, "license": "MIT", "dependencies": { - "@babel/parser": "^7.17.3", + "@babel/parser": "^7.17.7", "@babel/traverse": "^7.17.3", "@docusaurus/logger": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", @@ -38,7 +38,7 @@ "devDependencies": { "@docusaurus/types": "2.0.0-beta.17", "@types/escape-html": "^1.0.1", - "@types/mdast": "^3.0.7", + "@types/mdast": "^3.0.10", "@types/stringify-object": "^3.3.1", "@types/unist": "^2.0.6", "remark": "^12.0.0", diff --git a/packages/docusaurus-migrate/package.json b/packages/docusaurus-migrate/package.json index abf7fc7be3b5..4ae500341ba1 100644 --- a/packages/docusaurus-migrate/package.json +++ b/packages/docusaurus-migrate/package.json @@ -26,23 +26,23 @@ "@docusaurus/logger": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", "@mapbox/hast-util-to-jsx": "^2.0.0", - "color": "^4.0.1", + "color": "^4.2.1", "commander": "^5.1.0", "fs-extra": "^10.0.1", "hast-util-to-string": "^1.0.4", "html-tags": "^3.1.0", "import-fresh": "^3.3.0", - "jscodeshift": "^0.13.0", + "jscodeshift": "^0.13.1", "rehype-parse": "^7.0.1", "remark-parse": "^8.0.2", "remark-stringify": "^8.1.0", - "semver": "^7.3.4", + "semver": "^7.3.5", "tslib": "^2.3.1", "unified": "^9.2.1", "unist-util-visit": "^2.0.2" }, "devDependencies": { "@types/color": "^3.0.3", - "@types/jscodeshift": "^0.11.2" + "@types/jscodeshift": "^0.11.3" } } diff --git a/packages/docusaurus-plugin-ideal-image/package.json b/packages/docusaurus-plugin-ideal-image/package.json index 49538cf00787..8a00967829e3 100644 --- a/packages/docusaurus-plugin-ideal-image/package.json +++ b/packages/docusaurus-plugin-ideal-image/package.json @@ -28,7 +28,7 @@ "@docusaurus/utils-validation": "2.0.0-beta.17", "@endiliey/react-ideal-image": "^0.0.11", "react-waypoint": "^10.1.0", - "sharp": "^0.30.2", + "sharp": "^0.30.3", "tslib": "^2.3.1", "webpack": "^5.70.0" }, diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json index eec9e390ed92..b66eea65c0f0 100644 --- a/packages/docusaurus-plugin-pwa/package.json +++ b/packages/docusaurus-plugin-pwa/package.json @@ -20,7 +20,7 @@ }, "license": "MIT", "dependencies": { - "@babel/core": "^7.17.5", + "@babel/core": "^7.17.7", "@babel/preset-env": "^7.16.11", "@docusaurus/core": "2.0.0-beta.17", "@docusaurus/theme-common": "2.0.0-beta.17", @@ -29,7 +29,7 @@ "@docusaurus/utils-validation": "2.0.0-beta.17", "babel-loader": "^8.2.3", "clsx": "^1.1.1", - "core-js": "^3.21.0", + "core-js": "^3.21.1", "terser-webpack-plugin": "^5.3.1", "tslib": "^2.3.1", "webpack": "^5.70.0", diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 1edbb217e126..ae8f256083ee 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -36,10 +36,10 @@ "infima": "0.2.0-alpha.37", "lodash": "^4.17.21", "postcss": "^8.4.8", - "prism-react-renderer": "^1.2.1", + "prism-react-renderer": "^1.3.1", "prismjs": "^1.27.0", "react-router-dom": "^5.2.0", - "rtlcss": "^3.3.0" + "rtlcss": "^3.5.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.17", diff --git a/packages/docusaurus-theme-search-algolia/package.json b/packages/docusaurus-theme-search-algolia/package.json index 43213ac2ae24..72fd74d48ec2 100644 --- a/packages/docusaurus-theme-search-algolia/package.json +++ b/packages/docusaurus-theme-search-algolia/package.json @@ -33,7 +33,7 @@ "@docusaurus/theme-translations": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-validation": "2.0.0-beta.17", - "algoliasearch": "^4.12.2", + "algoliasearch": "^4.13.0", "algoliasearch-helper": "^3.7.0", "clsx": "^1.1.1", "eta": "^1.12.3", diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index f8d758e26859..92139190d892 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -19,11 +19,11 @@ "license": "MIT", "dependencies": { "@docusaurus/logger": "2.0.0-beta.17", - "@svgr/webpack": "^6.0.0", + "@svgr/webpack": "^6.2.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.1", "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "gray-matter": "^4.0.3", "js-yaml": "^4.1.0", "lodash": "^4.17.21", diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 55d9fa700119..763c9fd1d8c7 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -31,15 +31,15 @@ "url": "https://github.com/facebook/docusaurus/issues" }, "dependencies": { - "@babel/core": "^7.17.5", - "@babel/generator": "^7.17.3", + "@babel/core": "^7.17.7", + "@babel/generator": "^7.17.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", - "@babel/runtime": "^7.17.2", - "@babel/runtime-corejs3": "^7.17.2", + "@babel/runtime": "^7.17.7", + "@babel/runtime-corejs3": "^7.17.7", "@babel/traverse": "^7.17.3", "@docusaurus/cssnano-preset": "2.0.0-beta.17", "@docusaurus/logger": "2.0.0-beta.17", @@ -63,7 +63,7 @@ "core-js": "^3.21.1", "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", - "cssnano": "^5.0.17", + "cssnano": "^5.1.4", "del": "^6.0.0", "detect-port": "^1.3.0", "escape-html": "^1.0.3", @@ -91,7 +91,7 @@ "react-router-dom": "^5.2.0", "remark-admonitions": "^1.2.1", "rtl-detect": "^1.0.4", - "semver": "^7.3.4", + "semver": "^7.3.5", "serve-handler": "^6.1.3", "shelljs": "^0.8.5", "terser-webpack-plugin": "^5.3.1", diff --git a/packages/lqip-loader/package.json b/packages/lqip-loader/package.json index c6cfae666c32..39ffb7a11cd7 100644 --- a/packages/lqip-loader/package.json +++ b/packages/lqip-loader/package.json @@ -21,13 +21,13 @@ "file-loader": "^6.2.0", "lodash": "^4.17.21", "node-vibrant": "^3.1.6", - "sharp": "^0.30.2", + "sharp": "^0.30.3", "tslib": "^2.3.1" }, "engines": { "node": ">=14" }, "devDependencies": { - "@types/sharp": "^0.29.2" + "@types/sharp": "^0.30.0" } } diff --git a/website/docs/migration/migration-manual.md b/website/docs/migration/migration-manual.md index 4f2a53cddf82..5298838992e1 100644 --- a/website/docs/migration/migration-manual.md +++ b/website/docs/migration/migration-manual.md @@ -72,8 +72,8 @@ A typical Docusaurus 2 `package.json` may look like this: "@docusaurus/core": "^2.0.0-beta.0", "@docusaurus/preset-classic": "^2.0.0-beta.0", "clsx": "^1.1.1", - "react": "^16.8.4", - "react-dom": "^16.8.4" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "browserslist": { "production": [">0.5%", "not dead", "not op_mini all"], diff --git a/website/package.json b/website/package.json index 7d30ea5e16a7..7a9488fcc2c0 100644 --- a/website/package.json +++ b/website/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@crowdin/cli": "^3.7.8", - "@crowdin/crowdin-api-client": "^1.14.1", + "@crowdin/crowdin-api-client": "^1.15.0", "@docusaurus/core": "2.0.0-beta.17", "@docusaurus/logger": "2.0.0-beta.17", "@docusaurus/plugin-client-redirects": "2.0.0-beta.17", @@ -48,11 +48,11 @@ "@docusaurus/theme-live-codeblock": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-common": "2.0.0-beta.17", - "@popperjs/core": "^2.11.2", + "@popperjs/core": "^2.11.4", "clsx": "^1.1.1", "color": "^4.2.1", "esbuild-loader": "2.18.0", - "fs-extra": "^10.0.0", + "fs-extra": "^10.0.1", "netlify-plugin-cache": "^1.0.3", "raw-loader": "^4.0.2", "react": "^17.0.2", @@ -78,7 +78,7 @@ ] }, "devDependencies": { - "@tsconfig/docusaurus": "^1.0.4", + "@tsconfig/docusaurus": "^1.0.5", "@types/jest": "^27.4.1", "cross-env": "^7.0.3", "rimraf": "^3.0.2" diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md b/website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md index 4f2a53cddf82..5298838992e1 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md +++ b/website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md @@ -72,8 +72,8 @@ A typical Docusaurus 2 `package.json` may look like this: "@docusaurus/core": "^2.0.0-beta.0", "@docusaurus/preset-classic": "^2.0.0-beta.0", "clsx": "^1.1.1", - "react": "^16.8.4", - "react-dom": "^16.8.4" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "browserslist": { "production": [">0.5%", "not dead", "not op_mini all"], diff --git a/website/versioned_docs/version-2.0.0-beta.17/migration/migration-manual.md b/website/versioned_docs/version-2.0.0-beta.17/migration/migration-manual.md index 4f2a53cddf82..5298838992e1 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/migration/migration-manual.md +++ b/website/versioned_docs/version-2.0.0-beta.17/migration/migration-manual.md @@ -72,8 +72,8 @@ A typical Docusaurus 2 `package.json` may look like this: "@docusaurus/core": "^2.0.0-beta.0", "@docusaurus/preset-classic": "^2.0.0-beta.0", "clsx": "^1.1.1", - "react": "^16.8.4", - "react-dom": "^16.8.4" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "browserslist": { "production": [">0.5%", "not dead", "not op_mini all"], diff --git a/yarn.lock b/yarn.lock index fdb25727eb5c..c75c67a3a997 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,114 +21,114 @@ resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz#e157f9ad624ab8fd940ff28bd2094cdf199cdd79" integrity sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug== -"@algolia/cache-browser-local-storage@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.2.tgz#62935ddb81b50d539111b2146fa340495ec1cd53" - integrity sha512-z8LjFsQc0B6h6LEE3pkUGM4ErVktn6bkFbhnYbTccjmFVQ+wXFJd/D63e0WtaC+hwRB1xq8uKhkz9oojEKEsGA== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/cache-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.2.tgz#8512f311524f4d0aae8611e9879214a5e2a577ae" - integrity sha512-r//r7MF0Na0HxD2BHnjWsDKuI72Z5UEf/Rb/8MC08XKBsjCwBihGxWxycjRcNGjNEIxJBsvRMIEOipcd9qD54g== - -"@algolia/cache-in-memory@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.2.tgz#cacd13c02a7826bfad1c391d012ce00bc5db3859" - integrity sha512-opWpbBUloP1fcTG3wBDnAfcoyNXW5GFDgGtLXrSANdfnelPKkr3O8j01ZTkRlPIuBDR0izGZG8MVWMDlTf71Bw== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/client-account@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.2.tgz#adc4833b78576d1558ba45b7d44be22747debdc9" - integrity sha512-HZqEyeVVjzOlfoSUyc+7+ueEJmRgqSuC+hqQOGECYa5JVno4d8eRVuDAMOb87I2LOdg/WoFMcAtaaRq2gpfV/w== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-analytics@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.2.tgz#741115db1af7db9526acdd702890480480dc09ce" - integrity sha512-7ktimzesu+vk3l+eG9w/nQh6/9AoIieCKmoiRIguKh6okGsaSBrcTHvUwIQEIiliqPuAFBk2M8eXYFqOZzwCZw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.2.tgz#88ffd3ddececdc5f343a4a9cb1f6c4058fe780c1" - integrity sha512-+dTicT1lklwOpeoiDspUoRSQYHhrr2IzllrX89/WuTPEBm2eww1xurqrSTQYC0MuVeX1s9/i4k34Q0ZnspypWg== - dependencies: - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-personalization@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.2.tgz#5aa1d2a4bbc64559a98bb6d029dda59dbc86e490" - integrity sha512-JBW3vYFGIm5sAAy3cLUdmUCpmSAdreo5S1fERg7xgF6KyxGrwyy5BViTNWrOKG+av2yusk1wKydOYJ1Fbpbaxw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-search@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.2.tgz#940dd07ae4fa7aa86e382ecaf0a82445010b1b4c" - integrity sha512-JIqi14TgfEqAooNbSPBC1ZCk3Pnviqlaz9KofAqWBxSRTpPUFnU/XQCU5ihR0PC68SFVDnU/Y9cak/XotXPUeg== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" +"@algolia/cache-browser-local-storage@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.13.0.tgz#f8aa4fe31104b19d616ea392f9ed5c2ea847d964" + integrity sha512-nj1vHRZauTqP/bluwkRIgEADEimqojJgoTRCel5f6q8WCa9Y8QeI4bpDQP28FoeKnDRYa3J5CauDlN466jqRhg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/cache-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.13.0.tgz#27b83fd3939d08d72261b36a07eeafc4cb4d2113" + integrity sha512-f9mdZjskCui/dA/fA/5a+6hZ7xnHaaZI5tM/Rw9X8rRB39SUlF/+o3P47onZ33n/AwkpSbi5QOyhs16wHd55kA== + +"@algolia/cache-in-memory@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.13.0.tgz#10801a74550cbabb64b59ff08c56bce9c278ff2d" + integrity sha512-hHdc+ahPiMM92CQMljmObE75laYzNFYLrNOu0Q3/eyvubZZRtY2SUsEEgyUEyzXruNdzrkcDxFYa7YpWBJYHAg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/client-account@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.13.0.tgz#f8646dd40d1e9e3353e10abbd5d6c293ea92a8e2" + integrity sha512-FzFqFt9b0g/LKszBDoEsW+dVBuUe1K3scp2Yf7q6pgHWM1WqyqUlARwVpLxqyc+LoyJkTxQftOKjyFUqddnPKA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-analytics@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.13.0.tgz#a00bd02df45d71becb9dd4c5c993d805f2e1786d" + integrity sha512-klmnoq2FIiiMHImkzOm+cGxqRLLu9CMHqFhbgSy9wtXZrqb8BBUIUE2VyBe7azzv1wKcxZV2RUyNOMpFqmnRZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.13.0.tgz#8bc373d164dbdcce38b4586912bbe162492bcb86" + integrity sha512-GoXfTp0kVcbgfSXOjfrxx+slSipMqGO9WnNWgeMmru5Ra09MDjrcdunsiiuzF0wua6INbIpBQFTC2Mi5lUNqGA== + dependencies: + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-personalization@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.13.0.tgz#10fb7af356422551f11a67222b39c52306f1512c" + integrity sha512-KneLz2WaehJmNfdr5yt2HQETpLaCYagRdWwIwkTqRVFCv4DxRQ2ChPVW9jeTj4YfAAhfzE6F8hn7wkQ/Jfj6ZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-search@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.13.0.tgz#2d8ff8e755c4a37ec89968f3f9b358eed005c7f0" + integrity sha512-blgCKYbZh1NgJWzeGf+caKE32mo3j54NprOf0LZVCubQb3Kx37tk1Hc8SDs9bCAE8hUvf3cazMPIg7wscSxspA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.2.tgz#cdc9a685d7cf356a4d9e5915f741f1ee1a6baade" - integrity sha512-iOiJAymLjq137G7+8EQuUEkrgta0cZGMg6scp8s4hJ+X6k+6By4nyptdkCWYwKLsW/Xy927QcIhGlkWV78vQIQ== +"@algolia/logger-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.13.0.tgz#be2606e71aae618a1ff1ea9a1b5f5a74284b35a8" + integrity sha512-8yqXk7rMtmQJ9wZiHOt/6d4/JDEg5VCk83gJ39I+X/pwUPzIsbKy9QiK4uJ3aJELKyoIiDT1hpYVt+5ia+94IA== -"@algolia/logger-console@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.2.tgz#d7348e41378fbab5413cb5f97d8ae2ff378cfdb8" - integrity sha512-veuQZyTSqHoHJtr9mLMnYeal9Mee6hCie4eqY+645VbeOrgT9p/kCMbKg5GLJGoLPlXGu7C0XpHyUj5k7/NQyw== +"@algolia/logger-console@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.13.0.tgz#f28028a760e3d9191e28a10b12925e48f6c9afde" + integrity sha512-YepRg7w2/87L0vSXRfMND6VJ5d6699sFJBRWzZPOlek2p5fLxxK7O0VncYuc/IbVHEgeApvgXx0WgCEa38GVuQ== dependencies: - "@algolia/logger-common" "4.12.2" + "@algolia/logger-common" "4.13.0" -"@algolia/requester-browser-xhr@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.2.tgz#abfcb1901602ccdf51879b10d914208b776aa418" - integrity sha512-FpFdHNd81tS3zj6Glqd+lt+RV0ljPExKtx+QB+gani6HWZ9YlSCM+Zl82T4ibxN+hmkrMeAyT+TMzS0jiGhGyQ== +"@algolia/requester-browser-xhr@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.13.0.tgz#e2483f4e8d7f09e27cd0daf6c77711d15c5a919f" + integrity sha512-Dj+bnoWR5MotrnjblzGKZ2kCdQi2cK/VzPURPnE616NU/il7Ypy6U6DLGZ/ZYz+tnwPa0yypNf21uqt84fOgrg== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/requester-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.2.tgz#6d6181fb961205695bf535e108d2e5be8f8c9047" - integrity sha512-4szj/lvDQf/u8EyyRBBRZD1ZkKDyLBbckLj7meQDlnbfwnW1UpLwpB2l3XJ9wDmDSftGxUCeTl5oMFe4z9OEvQ== +"@algolia/requester-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.13.0.tgz#47fb3464cfb26b55ba43676d13f295d812830596" + integrity sha512-BRTDj53ecK+gn7ugukDWOOcBRul59C4NblCHqj4Zm5msd5UnHFjd/sGX+RLOEoFMhetILAnmg6wMrRrQVac9vw== -"@algolia/requester-node-http@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.2.tgz#f91e749ee6854c944cc741f13c539dff23363f67" - integrity sha512-UXfJNZt2KMwjBjiOa3cJ/PyoXWZa/F1vy6rdyG4xQeZDcLbqKP3O2b+bOJcGPmFbmdwBhtAyMVLt+hvAvAVfOw== +"@algolia/requester-node-http@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.13.0.tgz#7d981bbd31492f51dd11820a665f9d8906793c37" + integrity sha512-9b+3O4QFU4azLhGMrZAr/uZPydvzOR4aEZfSL8ZrpLZ7fbbqTO0S/5EVko+QIgglRAtVwxvf8UJ1wzTD2jvKxQ== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/transporter@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.2.tgz#60189b626b170f3386deb1d7a0a1e70ed8156864" - integrity sha512-PUq79if4CukXsm27ymTQ3eD3juSvMcyJmt6mxCkSFE0zQRL4ert61HBlNH6S9y/quUVe3g7oggfHq3d5pdpqZA== +"@algolia/transporter@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.13.0.tgz#f6379e5329efa2127da68c914d1141f5f21dbd07" + integrity sha512-8tSQYE+ykQENAdeZdofvtkOr5uJ9VcQSWgRhQ9h01AehtBIPAczk/b2CLrMsw5yQZziLs5cZ3pJ3478yI+urhA== dependencies: - "@algolia/cache-common" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/requester-common" "4.12.2" + "@algolia/cache-common" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/requester-common" "4.13.0" "@ampproject/remapping@^2.1.0": version "2.1.2" @@ -170,10 +170,10 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" - integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== "@babel/core@7.12.9": version "7.12.9" @@ -197,18 +197,18 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.4", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.15.5", "@babel/core@^7.17.5", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.4", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.15.5", "@babel/core@^7.17.7", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.7.tgz#f7c28228c83cdf2dbd1b9baa06eaf9df07f0c2f9" + integrity sha512-djHlEfFHnSnTAcPb7dATbiM5HxGOP98+3JLBZtjRb5I7RXrw7kFRoG2dXM8cm3H+o11A8IFH/uprmJpwFynRNQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.7" + "@babel/parser" "^7.17.7" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -218,7 +218,7 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/eslint-parser@^7.16.3": +"@babel/eslint-parser@^7.17.0": version "7.17.0" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== @@ -227,10 +227,10 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.17.3", "@babel/generator@^7.7.2": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== +"@babel/generator@^7.12.5", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.7.2": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== dependencies: "@babel/types" "^7.17.0" jsesc "^2.5.1" @@ -251,12 +251,12 @@ "@babel/helper-explode-assignable-expression" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.4" + "@babel/compat-data" "^7.17.7" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" @@ -334,11 +334,11 @@ "@babel/types" "^7.16.7" "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": version "7.16.7" @@ -347,14 +347,14 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" - integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" @@ -398,12 +398,12 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -439,13 +439,13 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.7.tgz#6fc0a24280fd00026e85424bbfed4650e76d7127" + integrity sha512-TKsj9NkjJfTBxM7Phfy7kv6yYc4ZcOo+AaWGqQOKTPDOmcGkIFb5xNA746eKisQkm4yavUYh4InYM9S+VnO01w== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" + "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" "@babel/highlight@^7.16.7": @@ -462,10 +462,10 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw== -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.7.tgz#fc19b645a5456c8d6fdb6cecd3c66c0173902800" + integrity sha512-bm3AQf45vR4gKggRfvJdYJ0gFLoCbsPxiFLSH6hTVYABptNHY6l9NrhnucVjQ/X+SPtLANT9lc0fFhikj+VBRA== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -812,9 +812,9 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz#c445f75819641788a27a0a3a759d9df911df6abc" - integrity sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -889,13 +889,13 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.13.8", "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.16.7": @@ -1201,9 +1201,9 @@ "@babel/plugin-transform-typescript" "^7.16.7" "@babel/register@^7.13.16": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.0.tgz#8051e0b7cb71385be4909324f072599723a1f084" - integrity sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.7.tgz#5eef3e0f4afc07e25e847720e7b987ae33f08d0b" + integrity sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA== dependencies: clone-deep "^4.0.1" find-cache-dir "^2.0.0" @@ -1211,18 +1211,18 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" - integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.7.tgz#cf914f474c490ef1aa8661d47adaa0a993636e7e" + integrity sha512-TvliGJjhxis5m7xIMvlXH/xG8Oa/LK0SCUCyfKD6nLi42n5fB4WibDJ0g9trmmBB6hwpMNx+Lzbxy9/4gpMaVw== dependencies: core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.7", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" + integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== dependencies: regenerator-runtime "^0.13.4" @@ -1235,7 +1235,7 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2": version "7.17.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== @@ -1264,10 +1264,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@bugsnag/browser@^7.16.1": - version "7.16.1" - resolved "https://registry.yarnpkg.com/@bugsnag/browser/-/browser-7.16.1.tgz#652aa3ed64e51ba0015878d252a08917429bba03" - integrity sha512-Tq9fWpwmqdOsbedYL67GzsTKrG5MERIKtnKCi5FyvFjTj143b6as0pwj7LWQ+Eh8grWlR7S11+VvJmb8xnY8Tg== +"@bugsnag/browser@^7.16.2": + version "7.16.2" + resolved "https://registry.yarnpkg.com/@bugsnag/browser/-/browser-7.16.2.tgz#b6fc7ebaeae4800d195b660abc770caf33670e03" + integrity sha512-iBbAmjTDe0I6WPTHi3wIcmKu3ykydtT6fc8atJA65rzgDLMlTM1Wnwz4Ny1cn0bVouLGa48BRiOJ27Rwy7QRYA== dependencies: "@bugsnag/core" "^7.16.1" @@ -1288,17 +1288,17 @@ integrity sha512-LOt8aaBI+KvOQGneBtpuCz3YqzyEAehd1f3nC5yr9TIYW1+IzYKa2xWS4EiMz5pPOnRPHkyyS5t/wmSmN51Gjg== "@bugsnag/js@^7.0.0": - version "7.16.1" - resolved "https://registry.yarnpkg.com/@bugsnag/js/-/js-7.16.1.tgz#4a4ec2c7f3e047333e7d15eb53cb11f165b7067f" - integrity sha512-yb83OmsbIMDJhX3hHhbHl5StN72feqdr/Ctq7gqsdcfOHNb2121Edf2EbegPJKZhFqSik66vWwiVbGJ6CdS/UQ== + version "7.16.2" + resolved "https://registry.yarnpkg.com/@bugsnag/js/-/js-7.16.2.tgz#fb15ec9cc5980f0b210aecc7b740274e50400a91" + integrity sha512-AzV0PtG3SZt+HnA2JmRJeI60aDNZsIJbEEAZIWZeATvWBt5RdVdsWKllM1SkTvURfxfdAVd4Xry3BgVrh8nEbg== dependencies: - "@bugsnag/browser" "^7.16.1" - "@bugsnag/node" "^7.16.1" + "@bugsnag/browser" "^7.16.2" + "@bugsnag/node" "^7.16.2" -"@bugsnag/node@^7.16.1": - version "7.16.1" - resolved "https://registry.yarnpkg.com/@bugsnag/node/-/node-7.16.1.tgz#473bb6eeb346b418295b49e4c4576e0004af4901" - integrity sha512-9zBA1IfDTbLKMoDltdhELpTd1e+b5+vUW4j40zGA+4SYIe64XNZKShfqRdvij7embvC1iHQ9UpuPRSk60P6Dng== +"@bugsnag/node@^7.16.2": + version "7.16.2" + resolved "https://registry.yarnpkg.com/@bugsnag/node/-/node-7.16.2.tgz#8ac1b41786306d8917fb9fe222ada74fe0c4c6d5" + integrity sha512-V5pND701cIYGzjjTwt0tuvAU1YyPB9h7vo5F/DzrDHRPmCINA/oVbc0Twco87knc2VPe8ntGFqTicTY65iOWzg== dependencies: "@bugsnag/core" "^7.16.1" byline "^5.0.0" @@ -1325,17 +1325,17 @@ njre "^0.2.0" shelljs "^0.8.4" -"@crowdin/crowdin-api-client@^1.14.1": - version "1.14.1" - resolved "https://registry.yarnpkg.com/@crowdin/crowdin-api-client/-/crowdin-api-client-1.14.1.tgz#bd54c089a6f5bf6f0e301768713091d07a53b623" - integrity sha512-/l5JKA1R/z3KKMGynIL3qGe+1yk5vdyLrrF04t3k8Xer5OrHJ3q1HnHmlBpTZQgWwYIyngGOkyHRo2PVlX4B/w== +"@crowdin/crowdin-api-client@^1.15.0": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@crowdin/crowdin-api-client/-/crowdin-api-client-1.15.0.tgz#e38eeef43f5e8c1f3918191a271252e7045807d5" + integrity sha512-qoWJZSKp0e3bmGbuBIm7H5nvZL1bGTqXkQlDvhuioGwtDQvqodgQGMqLtNGWd1CQtYwUcGE15Fs+FHMuSgRIlw== dependencies: axios "0.21.3" -"@cspell/cspell-bundled-dicts@^5.18.5": - version "5.18.5" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.18.5.tgz#76beb90ad6e0ae5c42a2d2177c300f5a6d98f1b5" - integrity sha512-jFvwF8bb8HUYqMUPQiGZUHAf8zfriZRagzoCW8w4NLLJB1IZNGlQvQCQskQG9cYtOmKAYHCbOwm8SjA9FKwQow== +"@cspell/cspell-bundled-dicts@^5.19.2": + version "5.19.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.2.tgz#c20d05d0ff5f3850bb62a32a95e05abd94673936" + integrity sha512-R+12xDw5iLCJH3O0n8t1D7acZrO/bjuULU3rs3CEt+i84/85b27shywc3E/vOiOt9613bpFNOL52J27Tu52YPQ== dependencies: "@cspell/dict-ada" "^2.0.0" "@cspell/dict-aws" "^2.0.0" @@ -1348,7 +1348,7 @@ "@cspell/dict-dart" "^1.1.0" "@cspell/dict-django" "^2.0.0" "@cspell/dict-dotnet" "^2.0.0" - "@cspell/dict-elixir" "^2.0.0" + "@cspell/dict-elixir" "^2.0.1" "@cspell/dict-en-gb" "^1.1.33" "@cspell/dict-en_us" "^2.1.7" "@cspell/dict-filetypes" "^2.0.1" @@ -1356,36 +1356,36 @@ "@cspell/dict-fullstack" "^2.0.4" "@cspell/dict-golang" "^2.0.0" "@cspell/dict-haskell" "^2.0.0" - "@cspell/dict-html" "^3.0.0" + "@cspell/dict-html" "^3.0.1" "@cspell/dict-html-symbol-entities" "^2.0.0" "@cspell/dict-java" "^2.0.0" "@cspell/dict-latex" "^2.0.0" "@cspell/dict-lorem-ipsum" "^2.0.0" "@cspell/dict-lua" "^2.0.0" "@cspell/dict-node" "^2.0.0" - "@cspell/dict-npm" "^2.0.1" + "@cspell/dict-npm" "^2.0.2" "@cspell/dict-php" "^2.0.0" "@cspell/dict-powershell" "^2.0.0" "@cspell/dict-public-licenses" "^1.0.4" "@cspell/dict-python" "^2.0.6" "@cspell/dict-r" "^1.0.2" - "@cspell/dict-ruby" "^2.0.0" + "@cspell/dict-ruby" "^2.0.1" "@cspell/dict-rust" "^2.0.0" "@cspell/dict-scala" "^2.0.0" - "@cspell/dict-software-terms" "^2.1.0" + "@cspell/dict-software-terms" "^2.1.3" "@cspell/dict-swift" "^1.0.2" "@cspell/dict-typescript" "^2.0.0" "@cspell/dict-vue" "^2.0.2" -"@cspell/cspell-pipe@^5.18.5": - version "5.18.5" - resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.18.5.tgz#d8a1cdf0aa4c0e3383ec4ffca7112b10cd8bb43a" - integrity sha512-U/4e4Zm7Mm23SuJu6b49+9Do/2aS+c9sPQa1Z9ZZqHQ4BqswJagk5oZ0V45BjYJ/0acHSRpIxbndpVJ01cjf8A== +"@cspell/cspell-pipe@^5.19.2": + version "5.19.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.19.2.tgz#40bf46fae7aa0697f9ab9e36d165fe149b9b5f36" + integrity sha512-mFFSn4ZgNgIOM0iBT0+xKBhRTQd/ecrWVvPfJpHxXIFwTt0neD19hqK54RDedLf8Hjds5cBHvS1EjMNARju/bQ== -"@cspell/cspell-types@^5.18.5": - version "5.18.5" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.18.5.tgz#7d3e6c8cdef15255aacfbdb2e3c8bb949fe2540d" - integrity sha512-yvDFCUa1CbjBuMkFCh+yUAAaG6VW5WXoewzLwhMFsMV1GZmkbftOcvZq0YuZviNsjdBViDH0dhKdlzwC953upg== +"@cspell/cspell-types@^5.19.2": + version "5.19.2" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.19.2.tgz#faae04c918dca53d6a266d86d00c3bd1682ebe16" + integrity sha512-IkMQpa7IzoFm9NXzRz8Gp38f3aoMZf6xjT7J3FvWtIntPvkIFaY53R1/I9U/gujH/zflf2VmZGxoDuFg1VcD0g== "@cspell/dict-ada@^2.0.0": version "2.0.0" @@ -1442,7 +1442,7 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-2.0.0.tgz#92729d95a71b9f72bf264fbba0c66a7b29f3993a" integrity sha512-WOHfjwMuLbo76khDsDa1lJvP/dXcwXVwonWwfUFRt82BL/GtyMalh1HEtCWwKDuK/9f8PCEt/EZMkHT3D5ZV3w== -"@cspell/dict-elixir@^2.0.0": +"@cspell/dict-elixir@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz#1a9b422215b5edabb84568cfa5c0c70bc164a2ce" integrity sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow== @@ -1487,10 +1487,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-2.0.0.tgz#a25d39e62bd2dd7191ca5612714aa0a1b90ca10f" integrity sha512-71S5wGCe7dq6C+zGDwsEAe5msub/irrLi6SExeG11a/EkpA3RKAEheDGPk0hOY4+vOcIFHaApxOjLTtgQfYWfA== -"@cspell/dict-html@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-3.0.0.tgz#0f5411518eb3cb5b069fbcad70b16829f1733208" - integrity sha512-VzZs/UtyRe4spdaH5SWakik+K3vB2fTyW3kdgGQbzjPGHyb5OXI5fmxQcX0yaSv5RkL0igVROHhu2ARUudoTpw== +"@cspell/dict-html@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-3.0.1.tgz#d5d10ef9b62361d8250cf9fe8564606993faa9df" + integrity sha512-sbuFd+nSjgbrGf5eYwSddFhm1eLLePKWyH6Zn8Zb0OODrBK5e4vGn1/scI/MOH5a2IvNs8W9wp84uMBFJcQZtw== "@cspell/dict-java@^2.0.0": version "2.0.0" @@ -1517,10 +1517,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-2.0.0.tgz#f89ca72deac5bfc7ccd46b6b8880fad52ab44843" integrity sha512-tPPl3liJORa/l6AoYqh/7rjoM7bdtaIXnIN6ox7CE0flZcBS5rWOB6mzEY3rpu/XJX0pjbBiIoqrolDkVl1RTQ== -"@cspell/dict-npm@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-2.0.1.tgz#90f9a0ffe0dfcdf998bf1a260b93a3d5ef47ff91" - integrity sha512-LRaJFSQfI0BIbbksPFE6fUjAyRFZRcknfOnYC/5c1wB/vsKH6KsqxTeCWNmHTYrk4KdBLZROhsHJXQIoqVTd4w== +"@cspell/dict-npm@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-2.0.2.tgz#8ad78bc23d10aa1dd295bf2de6078a02d3a91766" + integrity sha512-Q5ua0aeKTxW4WxvtU+UMdct46hCStOTeEiiG8iinTh/mH5brmdtMEj4olO8+mmkAKPpIC4TI3TmaaN6RN+Vpgw== "@cspell/dict-php@^2.0.0": version "2.0.0" @@ -1547,7 +1547,7 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-r/-/dict-r-1.0.2.tgz#4f21b240427e9bbaab8f82e0e20122d6b3cf7cee" integrity sha512-Rp3d4sgD6izW9TW5yVI3D//3HTl9oOGBuzTvXRdoHksVPRvzIu2liVhj8MnQ3XIRe5Kc6IhLBAm6izuV2BpGwQ== -"@cspell/dict-ruby@^2.0.0": +"@cspell/dict-ruby@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@cspell/dict-ruby/-/dict-ruby-2.0.1.tgz#1cbd4d8803428bd421a5562b2d2bb4b3bae80bce" integrity sha512-qGqhYfFeoBOashv/l0Kj5o4ilyvfq0s+t+r32juPOkOnbHz+hzxnJo2tMMg/L/UdjVV7Y8ovg4LDBC/seVrMYQ== @@ -1562,10 +1562,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-2.0.0.tgz#b8098103bb03a13406c1c79f1769052353aafac4" integrity sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g== -"@cspell/dict-software-terms@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-2.1.2.tgz#16a18f275e81426b0fbbb5342fd37701038b01c8" - integrity sha512-iTkkduYX4+NVHt1CKbDGDQJsSTqMCafGZKhtasPQTUN6UxIaDFM9Hxl1wAoECDaRRDgkaGP0v1C7F8jY7nFyKQ== +"@cspell/dict-software-terms@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-2.1.3.tgz#033f93d4cfa03e21b03ad0861ee74560b204a841" + integrity sha512-JmMfRa9Xl0MCD/z5gYUnY05BNxSMnx25Ky6kO/Cs0gBYZZdYzHZNqrbfnqBMsB9PpOzn2uqrYUmAEusoI1WyMQ== "@cspell/dict-swift@^1.0.2": version "1.0.2" @@ -1638,16 +1638,16 @@ resolved "https://registry.yarnpkg.com/@endiliey/react-ideal-image/-/react-ideal-image-0.0.11.tgz#dc3803d04e1409cf88efa4bba0f67667807bdf27" integrity sha512-QxMjt/Gvur/gLxSoCy7VIyGGGrGmDN+VHcXkN3R2ApoWX0EYUE+hMgPHSW/PV6VVebZ1Nd4t2UnGRBDihu16JQ== -"@eslint/eslintrc@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" - integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== +"@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== dependencies: ajv "^6.12.4" debug "^4.3.2" espree "^9.3.1" globals "^13.9.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.0.4" @@ -3180,13 +3180,13 @@ "@octokit/types" "^6.0.3" "@octokit/core@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== + version "3.6.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" + integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== dependencies: "@octokit/auth-token" "^2.4.4" "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" + "@octokit/request" "^5.6.3" "@octokit/request-error" "^2.0.5" "@octokit/types" "^6.0.3" before-after-hook "^2.2.0" @@ -3249,7 +3249,7 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.6.0": +"@octokit/request@^5.6.0", "@octokit/request@^5.6.3": version "5.6.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== @@ -3298,10 +3298,10 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@popperjs/core@^2.11.2": - version "2.11.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9" - integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA== +"@popperjs/core@^2.11.4": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503" + integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg== "@rollup/plugin-babel@^5.2.0": version "5.3.1" @@ -3565,7 +3565,7 @@ deepmerge "^4.2.2" svgo "^2.5.0" -"@svgr/webpack@^6.0.0", "@svgr/webpack@^6.2.1": +"@svgr/webpack@^6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== @@ -3614,10 +3614,10 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@tsconfig/docusaurus@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.4.tgz#fc40f87a672568678d83533dd4031a09d75877ca" - integrity sha512-I6sziQAzLrrqj9r6S26c7aOAjfGVXIE7gWdNONPwnpDcHiMRMQut1s1YCi/APem3dOy23tAb2rvHfNtGCaWuUQ== +"@tsconfig/docusaurus@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.5.tgz#5298c5b0333c6263f06c3149b38ebccc9f169a4e" + integrity sha512-KM/TuJa9fugo67dTGx+ktIqf3fVc077J6jwHu845Hex4EQf7LABlNonP/mohDKT0cmncdtlYVHHF74xR/YpThg== "@tsconfig/node10@^1.0.7": version "1.0.8" @@ -3958,7 +3958,7 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== -"@types/jscodeshift@^0.11.2": +"@types/jscodeshift@^0.11.3": version "0.11.3" resolved "https://registry.yarnpkg.com/@types/jscodeshift/-/jscodeshift-0.11.3.tgz#8dcab24ced39dcab1c8ff3461b3d171aafee3d48" integrity sha512-pM0JD9kWVDH9DQp5Y6td16924V3MwZHei8P3cTeuFhXpzpk0K+iWraBZz8wF61QkFs9fZeAQNX0q8SG0+TFm2w== @@ -3988,12 +3988,12 @@ dependencies: "@types/node" "*" -"@types/lodash@^4.14.179", "@types/lodash@^4.14.53": - version "4.14.179" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5" - integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w== +"@types/lodash@^4.14.180", "@types/lodash@^4.14.53": + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== -"@types/mdast@^3.0.0", "@types/mdast@^3.0.10", "@types/mdast@^3.0.7": +"@types/mdast@^3.0.0", "@types/mdast@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== @@ -4165,10 +4165,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.39": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== +"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.40": + version "17.0.40" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad" + integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -4249,10 +4249,10 @@ "@types/mime" "^1" "@types/node" "*" -"@types/sharp@^0.29.2": - version "0.29.5" - resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.29.5.tgz#9c7032d30d138ad16dde6326beaff2af757b91b3" - integrity sha512-3TC+S3H5RwnJmLYMHrcdfNjz/CaApKmujjY9b6PU/pE6n0qfooi99YqXGWoW8frU9EWYj/XTI35Pzxa+ThAZ5Q== +"@types/sharp@^0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.30.0.tgz#58cb016c8fdc558b4c5771ad1f3668336685c843" + integrity sha512-bZ0Y/JVlrOyqwlBMJ2taEgnwFavjLnyZmLOLecmOesuG5kR2Lx9b2fM4osgfVjLJi8UlE+t3R1JzRVMxF6MbfA== dependencies: "@types/node" "*" @@ -4370,9 +4370,9 @@ source-map "^0.6.0" "@types/ws@^8.2.2": - version "8.5.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.2.tgz#77e0c2e360e9579da930ffcfa53c5975ea3bdd26" - integrity sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw== + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== dependencies: "@types/node" "*" @@ -4395,14 +4395,14 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.14.0.tgz#5119b67152356231a0e24b998035288a9cd21335" - integrity sha512-ir0wYI4FfFUDfLcuwKzIH7sMVA+db7WYen47iRSaCGl+HMAZI9fpBwfDo45ZALD3A45ZGyHWDNLhbg8tZrMX4w== +"@typescript-eslint/eslint-plugin@^5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a" + integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA== dependencies: - "@typescript-eslint/scope-manager" "5.14.0" - "@typescript-eslint/type-utils" "5.14.0" - "@typescript-eslint/utils" "5.14.0" + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/type-utils" "5.15.0" + "@typescript-eslint/utils" "5.15.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -4410,30 +4410,30 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.14.0.tgz#7c79f898aa3cff0ceee6f1d34eeed0f034fb9ef3" - integrity sha512-aHJN8/FuIy1Zvqk4U/gcO/fxeMKyoSv/rS46UXMXOJKVsLQ+iYPuXNbpbH7cBLcpSbmyyFbwrniLx5+kutu1pw== +"@typescript-eslint/parser@^5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728" + integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ== dependencies: - "@typescript-eslint/scope-manager" "5.14.0" - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/typescript-estree" "5.14.0" + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/typescript-estree" "5.15.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.14.0.tgz#ea518962b42db8ed0a55152ea959c218cb53ca7b" - integrity sha512-LazdcMlGnv+xUc5R4qIlqH0OWARyl2kaP8pVCS39qSL3Pd1F7mI10DbdXeARcE62sVQE4fHNvEqMWsypWO+yEw== +"@typescript-eslint/scope-manager@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee" + integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg== dependencies: - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/visitor-keys" "5.14.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/visitor-keys" "5.15.0" -"@typescript-eslint/type-utils@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.14.0.tgz#711f08105860b12988454e91df433567205a8f0b" - integrity sha512-d4PTJxsqaUpv8iERTDSQBKUCV7Q5yyXjqXUl3XF7Sd9ogNLuKLkxz82qxokqQ4jXdTPZudWpmNtr/JjbbvUixw== +"@typescript-eslint/type-utils@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248" + integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA== dependencies: - "@typescript-eslint/utils" "5.14.0" + "@typescript-eslint/utils" "5.15.0" debug "^4.3.2" tsutils "^3.21.0" @@ -4442,18 +4442,18 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.14.0.tgz#96317cf116cea4befabc0defef371a1013f8ab11" - integrity sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw== +"@typescript-eslint/types@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501" + integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA== -"@typescript-eslint/typescript-estree@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.14.0.tgz#78b7f7385d5b6f2748aacea5c9b7f6ae62058314" - integrity sha512-QGnxvROrCVtLQ1724GLTHBTR0lZVu13izOp9njRvMkCBgWX26PKvmMP8k82nmXBRD3DQcFFq2oj3cKDwr0FaUA== +"@typescript-eslint/typescript-estree@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac" + integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA== dependencies: - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/visitor-keys" "5.14.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/visitor-keys" "5.15.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -4473,15 +4473,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.14.0", "@typescript-eslint/utils@^5.10.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.14.0.tgz#6c8bc4f384298cbbb32b3629ba7415f9f80dc8c4" - integrity sha512-EHwlII5mvUA0UsKYnVzySb/5EE/t03duUTweVy8Zqt3UQXBrpEVY144OTceFKaOe4xQXZJrkptCf7PjEBeGK4w== +"@typescript-eslint/utils@5.15.0", "@typescript-eslint/utils@^5.10.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136" + integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.14.0" - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/typescript-estree" "5.14.0" + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/typescript-estree" "5.15.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -4493,12 +4493,12 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.14.0.tgz#1927005b3434ccd0d3ae1b2ecf60e65943c36986" - integrity sha512-yL0XxfzR94UEkjBqyymMLgCBdojzEuy/eim7N9/RIcTNxpJudAcqsU8eRyfzBbcEzGoPWfdM3AGak3cN08WOIw== +"@typescript-eslint/visitor-keys@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027" + integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ== dependencies: - "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/types" "5.15.0" eslint-visitor-keys "^3.0.0" "@vercel/nft@^0.17.0": @@ -4821,25 +4821,25 @@ algoliasearch-helper@^3.7.0: dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.0.0, algoliasearch@^4.12.2: - version "4.12.2" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.2.tgz#d7672a15b8fd1b261d9ae193535b68bcb189cfd2" - integrity sha512-bn1P9+V415zeDQJtXn+1SwuwedEAv9/LJAxt8XwR6ygH/sMwaHSm2hpkz8wIbCBt/tKQ43TL672Kyxzv5PwGgQ== - dependencies: - "@algolia/cache-browser-local-storage" "4.12.2" - "@algolia/cache-common" "4.12.2" - "@algolia/cache-in-memory" "4.12.2" - "@algolia/client-account" "4.12.2" - "@algolia/client-analytics" "4.12.2" - "@algolia/client-common" "4.12.2" - "@algolia/client-personalization" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/logger-console" "4.12.2" - "@algolia/requester-browser-xhr" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/requester-node-http" "4.12.2" - "@algolia/transporter" "4.12.2" +algoliasearch@^4.0.0, algoliasearch@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.13.0.tgz#e36611fda82b1fc548c156ae7929a7f486e4b663" + integrity sha512-oHv4faI1Vl2s+YC0YquwkK/TsaJs79g2JFg5FDm2rKN12VItPTAeQ7hyJMHarOPPYuCnNC5kixbtcqvb21wchw== + dependencies: + "@algolia/cache-browser-local-storage" "4.13.0" + "@algolia/cache-common" "4.13.0" + "@algolia/cache-in-memory" "4.13.0" + "@algolia/client-account" "4.13.0" + "@algolia/client-analytics" "4.13.0" + "@algolia/client-common" "4.13.0" + "@algolia/client-personalization" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/logger-console" "4.13.0" + "@algolia/requester-browser-xhr" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/requester-node-http" "4.13.0" + "@algolia/transporter" "4.13.0" all-node-versions@^8.0.0: version "8.0.0" @@ -4902,9 +4902,9 @@ ansi-regex@^3.0.0: integrity sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ== ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" @@ -5977,9 +5977,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001313: - version "1.0.30001314" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz#65c7f9fb7e4594fca0a333bec1d8939662377596" - integrity sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw== + version "1.0.30001317" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" + integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== caseless@~0.12.0: version "0.12.0" @@ -6437,7 +6437,7 @@ color@^3.1.3: color-convert "^1.9.3" color-string "^1.6.0" -color@^4.0.1, color@^4.2.1: +color@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== @@ -6561,7 +6561,7 @@ comment-json@^4.2.2: comment-parser@^1.1.2: version "1.3.0" - resolved "https://registry.npmmirror.com/comment-parser/-/comment-parser-1.3.0.tgz#68beb7dbe0849295309b376406730cd16c719c44" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.0.tgz#68beb7dbe0849295309b376406730cd16c719c44" integrity sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA== common-path-prefix@^3.0.0: @@ -6898,7 +6898,7 @@ core-js@^2.4.1: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.21.0, core-js@^3.21.1: +core-js@^3.21.1: version "3.21.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== @@ -7026,73 +7026,75 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -cspell-gitignore@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.18.5.tgz#fc8024f13475d85dae1f447864ef56aed3966fe3" - integrity sha512-YKYFYMswkia0Uc5CMOapLwo8OKRfP+QbqyODTJ7IJACT7KCOSEj7A3B250LR2mWyvThyIUB+2c7+6ePdFCnh2g== +cspell-gitignore@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.19.2.tgz#8a364a18fbeef7b35356f2537933ea4fc1761063" + integrity sha512-j0iMQoLmq4J/19hM0j0rNUQoHsw1b9Yg1AZMus8WJgABPUPGgk4fRKJChUQu0+ys3wwWT/4vhKt7hU89ScphJQ== dependencies: - cspell-glob "^5.18.5" + cspell-glob "^5.19.2" find-up "^5.0.0" -cspell-glob@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.18.5.tgz#1cc757bb2028cc12bf5acd9336cfc505cd5cd311" - integrity sha512-Tr/wMHpJ5zvD4qV4d5is1WJ6OQZSQSjiWoLCQ8pslpltGJhjYXPh3W9A8n4Ghr4AUUJNLKEQyCX+Z1kcA3hgOQ== +cspell-glob@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.19.2.tgz#57a208bbb583d8385403d35fa2f1a1351b50e883" + integrity sha512-23pgM0KzWsnNv6zwC/xnxdE86MfLU7NWbBqDmn1KixhJjezOhg/LiSjnJuRVUuLR+4qApzjrBRpk+Rj1jzYi6A== dependencies: micromatch "^4.0.4" -cspell-io@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.18.5.tgz#320c0c67b7f0f5046b1d7e31d4372fe1a65366a6" - integrity sha512-Ar2shXmKtLP935Linv+162xY6SNqIrwLI3rBRXs0/KnD/YdcLJQB0iBgFqvfvg7TcPg+EZOf9Oc6EvTLg2eprg== +cspell-io@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.19.2.tgz#32ae634cccc73c8a0b8f1c83038301fbe137c85f" + integrity sha512-TLlXMmDdZQold3ZsbHEpwKjUIRtYksp7Qr9Z0Rt9JpII6riliUPdB0SMFgtrqAvV1+bhJEPPmSxts8SdtLkdnA== -cspell-lib@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.18.5.tgz#76b169399c5e635cde59381d86260019b6b42909" - integrity sha512-yrUk3MbRXy/YGNIcLfURDnw4fRiXcbHo9K5B6IhwYfHKc3VM6QgvEQ0ce44uzZ+AEZzWuQ++GbhUih+bSJ87DQ== +cspell-lib@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.19.2.tgz#678ade6f3217e0ca3bb12efca55871912d90d2ff" + integrity sha512-x8NhOiXKRj6PHQty9RmaujE8dywzX0ZJr6AlPE/0N8IHmOg0Y8gAs7aN45l3PjFz+vaWfCghPbCIyxE/fdXNaw== dependencies: - "@cspell/cspell-bundled-dicts" "^5.18.5" - "@cspell/cspell-types" "^5.18.5" + "@cspell/cspell-bundled-dicts" "^5.19.2" + "@cspell/cspell-pipe" "^5.19.2" + "@cspell/cspell-types" "^5.19.2" clear-module "^4.1.2" comment-json "^4.2.2" configstore "^5.0.1" cosmiconfig "^7.0.1" - cspell-glob "^5.18.5" - cspell-io "^5.18.5" - cspell-trie-lib "^5.18.5" + cspell-glob "^5.19.2" + cspell-io "^5.19.2" + cspell-trie-lib "^5.19.2" fast-equals "^3.0.0" find-up "^5.0.0" - fs-extra "^10.0.0" + fs-extra "^10.0.1" gensequence "^3.1.1" import-fresh "^3.3.0" resolve-from "^5.0.0" resolve-global "^1.0.0" + vscode-languageserver-textdocument "^1.0.4" vscode-uri "^3.0.3" -cspell-trie-lib@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.18.5.tgz#dff995e8773857564d4bda91e64626838c69674a" - integrity sha512-FifImmkcArPYiE8fLXcbB/yS15QyWwvHw/gpCPEkcuJMJH2gxC+HOE909JnBsyPyjCaX5gHWiIf7ePjdXlWsDg== +cspell-trie-lib@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.19.2.tgz#4573f897de9ad1200390c14b73d43066acdf8746" + integrity sha512-JCPBuA6XtIRuMZtIzRAV/nk/NmTQwxcQA4GEAkdxYZ9aUPTpMDItxQkrKrlEvAuqt8hKZkOpE6ZpChdLW7aKsg== dependencies: - "@cspell/cspell-pipe" "^5.18.5" - fs-extra "^10.0.0" + "@cspell/cspell-pipe" "^5.19.2" + fs-extra "^10.0.1" gensequence "^3.1.1" -cspell@^5.18.5: - version "5.18.5" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.18.5.tgz#944b27def0607d8938bcffeae6df38f60b26bf11" - integrity sha512-rfk7sSZO304olxBXUFfec3YZL0gIyvjggwicGEgsweuh0Efdeq0zMmUV2sMckSOH9TVJdxW/DxTqjG+DLz8w+A== +cspell@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.19.2.tgz#79de5ab9335b089058fb9765fbdf39aebade3aa7" + integrity sha512-HqjwOZ5iJ4WBfl6TfQkGXax0uYVL3SI9XAsstFs7yQW+6/DwjgvR7GFTkGH+rZgN5hdGZPk81NYbfNLm0uyKCQ== dependencies: - "@cspell/cspell-pipe" "^5.18.5" + "@cspell/cspell-pipe" "^5.19.2" chalk "^4.1.2" commander "^9.0.0" comment-json "^4.2.2" - cspell-gitignore "^5.18.5" - cspell-glob "^5.18.5" - cspell-lib "^5.18.5" + cspell-gitignore "^5.19.2" + cspell-glob "^5.19.2" + cspell-lib "^5.19.2" fast-json-stable-stringify "^2.1.0" file-entry-cache "^6.0.1" - fs-extra "^10.0.0" + fs-extra "^10.0.1" get-stdin "^8.0.0" glob "^7.2.0" imurmurhash "^0.1.4" @@ -7190,64 +7192,64 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.2.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.2.tgz#6b627997939d0f2970c2bd0b91c7f353e0637e24" - integrity sha512-3rU6UV8RrGEfIGGdQyGjYoCjnW0OYi/+J78yWQSuH4ygf/Dsh/YkwhUtrMFiRw3Vo5+GPtvuu4FNSxxhXhSgww== +cssnano-preset-advanced@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.5.tgz#bf1564b0702bbad6f55dc2b6717346eeeab090ff" + integrity sha512-Zjq42GtsRN1gw1LcgY7PHsXlw/k65Ps3uc9cG8jKY1uNqux6eDqt6Fdc/vTWb/Z6ZhnDyecul8cdCHImbU6E5g== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.1" - postcss-discard-unused "^5.1.0" - postcss-merge-idents "^5.1.0" - postcss-reduce-idents "^5.1.0" - postcss-zindex "^5.1.0" + cssnano-preset-default "^*" + postcss-discard-unused "^*" + postcss-merge-idents "^*" + postcss-reduce-idents "^*" + postcss-zindex "^*" -cssnano-preset-default@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.1.tgz#a83b15d3294c69bd1cedd14b0066c2f2357d108e" - integrity sha512-Y+CUCS5iZ1uzHn5KtmKIlysQVXrTtLCnYsYTOJcbdd5rghOwtw1gobvEXefBncjGO4fWwGZr9/n9hwZfo6W1Fw== +cssnano-preset-default@^*: + version "5.2.4" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.4.tgz#eced79bbc1ab7270337c4038a21891daac2329bc" + integrity sha512-w1Gg8xsebln6/axZ6qDFQHuglrGfbIHOIx0g4y9+etRlRab8CGpSpe6UMsrgJe4zhCaJ0LwLmc+PhdLRTwnhIA== dependencies: css-declaration-sorter "^6.0.3" - cssnano-utils "^3.1.0" + cssnano-utils "^*" postcss-calc "^8.2.3" - postcss-colormin "^5.3.0" - postcss-convert-values "^5.1.0" - postcss-discard-comments "^5.1.1" - postcss-discard-duplicates "^5.1.0" - postcss-discard-empty "^5.1.0" - postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.0" - postcss-merge-rules "^5.1.0" - postcss-minify-font-values "^5.1.0" - postcss-minify-gradients "^5.1.0" - postcss-minify-params "^5.1.0" - postcss-minify-selectors "^5.2.0" - postcss-normalize-charset "^5.1.0" - postcss-normalize-display-values "^5.1.0" - postcss-normalize-positions "^5.1.0" - postcss-normalize-repeat-style "^5.1.0" - postcss-normalize-string "^5.1.0" - postcss-normalize-timing-functions "^5.1.0" - postcss-normalize-unicode "^5.1.0" - postcss-normalize-url "^5.1.0" - postcss-normalize-whitespace "^5.1.0" - postcss-ordered-values "^5.1.0" - postcss-reduce-initial "^5.1.0" - postcss-reduce-transforms "^5.1.0" - postcss-svgo "^5.1.0" - postcss-unique-selectors "^5.1.1" - -cssnano-utils@^3.1.0: + postcss-colormin "^*" + postcss-convert-values "^*" + postcss-discard-comments "^*" + postcss-discard-duplicates "^*" + postcss-discard-empty "^*" + postcss-discard-overridden "^*" + postcss-merge-longhand "^*" + postcss-merge-rules "^*" + postcss-minify-font-values "^*" + postcss-minify-gradients "^*" + postcss-minify-params "^*" + postcss-minify-selectors "^*" + postcss-normalize-charset "^*" + postcss-normalize-display-values "^*" + postcss-normalize-positions "^*" + postcss-normalize-repeat-style "^*" + postcss-normalize-string "^*" + postcss-normalize-timing-functions "^*" + postcss-normalize-unicode "^*" + postcss-normalize-url "^*" + postcss-normalize-whitespace "^*" + postcss-ordered-values "^*" + postcss-reduce-initial "^*" + postcss-reduce-transforms "^*" + postcss-svgo "^*" + postcss-unique-selectors "^*" + +cssnano-utils@^*, cssnano-utils@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.17, cssnano@^5.0.6: - version "5.1.1" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.1.tgz#2df44d26461b95f699096b6830df5107b1a758f4" - integrity sha512-WWfN7jBK/3Uk3oX/jsFbQApDf9DkXj6dOYull5ZaSGskcDggzg3RyDZI4GKKO+00LdfLMEZtY1cwTQUL+YMg2Q== +cssnano@^5.0.6, cssnano@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.4.tgz#c648192e8e2f1aacb7d839e6aa3706b50cc7f8e4" + integrity sha512-hbfhVZreEPyzl+NbvRsjNo54JOX80b+j6nqG2biLVLaZHJEiqGyMh4xDGHtwhUKd5p59mj2GlDqlUBwJUuIu5A== dependencies: - cssnano-preset-default "^5.2.1" + cssnano-preset-default "^*" lilconfig "^2.0.3" yaml "^1.10.2" @@ -7998,9 +8000,9 @@ ejs@^3.1.6: jake "^10.6.1" electron-to-chromium@^1.4.76: - version "1.4.77" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.77.tgz#c26e454cb8721d4ebdae3e276c57cd32e51c32ed" - integrity sha512-fiDxw8mO9Ph1Z0bjX2sFTPpi0J0QkOiwOJF+5Q0J0baNc/F9lLePAvDPlnoxvbUYYMizqrKPeotRRkJ9LtxAew== + version "1.4.84" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.84.tgz#2700befbcb49c42c4ee162e137ff392c07658249" + integrity sha512-b+DdcyOiZtLXHdgEG8lncYJdxbdJWJvclPNMg0eLUDcSOSO876WA/pYjdSblUTd7eJdIs4YdIxHWGazx7UPSJw== elegant-spinner@^1.0.1: version "1.0.1" @@ -8158,75 +8160,75 @@ es6-promisify@^6.0.0: resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621" integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg== -esbuild-android-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz#d532d38cb5fe0ae45167ce35f4bbc784c636be40" - integrity sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ== - -esbuild-android-arm64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz#9c5bb3366aabfd14a1c726d36978b79441dfcb6e" - integrity sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw== - -esbuild-darwin-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz#05dcdb6d884f427039ffee5e92ff97527e56c26d" - integrity sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA== - -esbuild-darwin-arm64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz#28e080da4ea0cfe9498071e7f8060498caee1a95" - integrity sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw== - -esbuild-freebsd-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz#200d3664a3b945bc9fdcba73614b49a11ebd1cfa" - integrity sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ== - -esbuild-freebsd-arm64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz#624b08c5da6013bdc312aaa23c4ff409580f5c3c" - integrity sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug== - -esbuild-linux-32@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz#0238e597eb0b60aa06c7e98fccbbfd6bb9a0d6c5" - integrity sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw== - -esbuild-linux-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz#8a8b8cf47dfce127c858e71229d9a385a82c62e8" - integrity sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug== - -esbuild-linux-arm64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz#7ac94371418a2640ba413bc1700aaedeb2794e52" - integrity sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw== - -esbuild-linux-arm@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz#034bd18e9310b9f010c89f90ef7f05706689600b" - integrity sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw== - -esbuild-linux-mips64le@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz#05f98a8cf6b578eab6b4e6b0ab094f37530934f4" - integrity sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ== - -esbuild-linux-ppc64le@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz#46fd0add8d8535678439d7a9c2876ad20042d952" - integrity sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw== - -esbuild-linux-riscv64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz#ea2e986f0f3e5df73c635135dd778051734fc605" - integrity sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w== - -esbuild-linux-s390x@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz#efe89486e9a1b1508925048076e3f3a6698aa6a3" - integrity sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ== +esbuild-android-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.27.tgz#b868bbd9955a92309c69df628d8dd1945478b45c" + integrity sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ== + +esbuild-android-arm64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.27.tgz#e7d6430555e8e9c505fd87266bbc709f25f1825c" + integrity sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ== + +esbuild-darwin-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.27.tgz#4dc7484127564e89b4445c0a560a3cb50b3d68e1" + integrity sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g== + +esbuild-darwin-arm64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.27.tgz#469e59c665f84a8ed323166624c5e7b9b2d22ac1" + integrity sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ== + +esbuild-freebsd-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.27.tgz#895df03bf5f87094a56c9a5815bf92e591903d70" + integrity sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA== + +esbuild-freebsd-arm64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.27.tgz#0b72a41a6b8655e9a8c5608f2ec1afdcf6958441" + integrity sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA== + +esbuild-linux-32@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.27.tgz#43b8ba3803b0bbe7f051869c6a8bf6de1e95de28" + integrity sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw== + +esbuild-linux-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.27.tgz#dc8072097327ecfadba1735562824ce8c05dd0bd" + integrity sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg== + +esbuild-linux-arm64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.27.tgz#c52b58cbe948426b1559910f521b0a3f396f10b8" + integrity sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ== + +esbuild-linux-arm@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.27.tgz#df869dbd67d4ee3a04b3c7273b6bd2b233e78a18" + integrity sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw== + +esbuild-linux-mips64le@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.27.tgz#a2b646d9df368b01aa970a7b8968be6dd6b01d19" + integrity sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A== + +esbuild-linux-ppc64le@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.27.tgz#9a21af766a0292578a3009c7408b8509cac7cefd" + integrity sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA== + +esbuild-linux-riscv64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.27.tgz#344a27f91568056a5903ad5841b447e00e78d740" + integrity sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg== + +esbuild-linux-s390x@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.27.tgz#73a7309bd648a07ef58f069658f989a5096130db" + integrity sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg== esbuild-loader@2.18.0: version "2.18.0" @@ -8240,61 +8242,61 @@ esbuild-loader@2.18.0: tapable "^2.2.0" webpack-sources "^2.2.0" -esbuild-netbsd-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz#439fe27d8ee3b5887501ee63988e85f920107db6" - integrity sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA== +esbuild-netbsd-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.27.tgz#482a587cdbd18a6c264a05136596927deb46c30a" + integrity sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q== -esbuild-openbsd-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz#31ebf616aadf6e60674469f2b92cec92280d9930" - integrity sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A== +esbuild-openbsd-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.27.tgz#e99f8cdc63f1628747b63edd124d53cf7796468d" + integrity sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw== -esbuild-sunos-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz#815e4f936d74970292a63ccfd5791fe5e3569f5f" - integrity sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw== +esbuild-sunos-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.27.tgz#8611d825bcb8239c78d57452e83253a71942f45c" + integrity sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg== -esbuild-windows-32@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz#189e14df2478f2c193c86968ab1fb54e1ceaafd2" - integrity sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA== +esbuild-windows-32@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.27.tgz#c06374206d4d92dd31d4fda299b09f51a35e82f6" + integrity sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw== -esbuild-windows-64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz#3d5fbfdc3856850bb47439299e3b60dd18be111f" - integrity sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA== +esbuild-windows-64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.27.tgz#756631c1d301dfc0d1a887deed2459ce4079582f" + integrity sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg== -esbuild-windows-arm64@0.14.25: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz#8b243cbbad8a86cf98697da9ccb88c05df2ef458" - integrity sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA== +esbuild-windows-arm64@0.14.27: + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.27.tgz#ad7e187193dcd18768b16065a950f4441d7173f4" + integrity sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg== esbuild@^0.14.6: - version "0.14.25" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.25.tgz#ddb9d47b91ca76abb7d850ce3dfed0bc3dc88d16" - integrity sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q== + version "0.14.27" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.27.tgz#41fe0f1b6b68b9f77cac025009bc54bb96e616f1" + integrity sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q== optionalDependencies: - esbuild-android-64 "0.14.25" - esbuild-android-arm64 "0.14.25" - esbuild-darwin-64 "0.14.25" - esbuild-darwin-arm64 "0.14.25" - esbuild-freebsd-64 "0.14.25" - esbuild-freebsd-arm64 "0.14.25" - esbuild-linux-32 "0.14.25" - esbuild-linux-64 "0.14.25" - esbuild-linux-arm "0.14.25" - esbuild-linux-arm64 "0.14.25" - esbuild-linux-mips64le "0.14.25" - esbuild-linux-ppc64le "0.14.25" - esbuild-linux-riscv64 "0.14.25" - esbuild-linux-s390x "0.14.25" - esbuild-netbsd-64 "0.14.25" - esbuild-openbsd-64 "0.14.25" - esbuild-sunos-64 "0.14.25" - esbuild-windows-32 "0.14.25" - esbuild-windows-64 "0.14.25" - esbuild-windows-arm64 "0.14.25" + esbuild-android-64 "0.14.27" + esbuild-android-arm64 "0.14.27" + esbuild-darwin-64 "0.14.27" + esbuild-darwin-arm64 "0.14.27" + esbuild-freebsd-64 "0.14.27" + esbuild-freebsd-arm64 "0.14.27" + esbuild-linux-32 "0.14.27" + esbuild-linux-64 "0.14.27" + esbuild-linux-arm "0.14.27" + esbuild-linux-arm64 "0.14.27" + esbuild-linux-mips64le "0.14.27" + esbuild-linux-ppc64le "0.14.27" + esbuild-linux-riscv64 "0.14.27" + esbuild-linux-s390x "0.14.27" + esbuild-netbsd-64 "0.14.27" + esbuild-openbsd-64 "0.14.27" + esbuild-sunos-64 "0.14.27" + esbuild-windows-32 "0.14.27" + esbuild-windows-64 "0.14.27" + esbuild-windows-arm64 "0.14.27" escalade@^3.1.1: version "3.1.1" @@ -8353,7 +8355,7 @@ eslint-config-airbnb-base@^15.0.0: object.entries "^1.1.5" semver "^6.3.0" -eslint-config-airbnb@^19.0.0, eslint-config-airbnb@^19.0.4: +eslint-config-airbnb@^19.0.4: version "19.0.4" resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz#84d4c3490ad70a0ffa571138ebcdea6ab085fdc3" integrity sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew== @@ -8388,7 +8390,7 @@ eslint-plugin-header@^3.1.1: resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6" integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg== -eslint-plugin-import@^2.25.3, eslint-plugin-import@^2.25.4: +eslint-plugin-import@^2.25.4: version "2.25.4" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== @@ -8437,10 +8439,10 @@ eslint-plugin-react-hooks@^4.3.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== -eslint-plugin-react@^7.29.3: - version "7.29.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.3.tgz#f4eab757f2756d25d6d4c2a58a9e20b004791f05" - integrity sha512-MzW6TuCnDOcta67CkpDyRfRsEVx9FNMDV8wZsDqe1luHPdGTrQIUaUXD27Ja3gHsdOIs/cXzNchWGlqm+qRVRg== +eslint-plugin-react@^7.29.4: + version "7.29.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: array-includes "^3.1.4" array.prototype.flatmap "^1.2.5" @@ -8459,7 +8461,7 @@ eslint-plugin-react@^7.29.3: eslint-plugin-regexp@^1.5.1: version "1.5.1" - resolved "https://registry.npmmirror.com/eslint-plugin-regexp/-/eslint-plugin-regexp-1.5.1.tgz#982ea8936283035897d6bb1ba32c0ea5d9a4dee0" + resolved "https://registry.yarnpkg.com/eslint-plugin-regexp/-/eslint-plugin-regexp-1.5.1.tgz#982ea8936283035897d6bb1ba32c0ea5d9a4dee0" integrity sha512-5v0rQIi54m2KycQHqmOAHrZhvI56GHmI2acr6zEffAqfeifTtobAEapv9Uf4o8//lGvwVkHKyjLoSbBNEFcfOA== dependencies: comment-parser "^1.1.2" @@ -8504,12 +8506,12 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.10.0, eslint@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" - integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== +eslint@^8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" + integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== dependencies: - "@eslint/eslintrc" "^1.2.0" + "@eslint/eslintrc" "^1.2.1" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -9362,7 +9364,7 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^10.0.0, fs-extra@^10.0.1: +fs-extra@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== @@ -9596,9 +9598,9 @@ gh-release-fetch@^3.0.0: semver "^7.0.0" gifwrap@^0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.2.tgz#348e286e67d7cf57942172e1e6f05a71cee78489" - integrity sha512-fcIswrPaiCDAyO8xnWvHSZdWChjKXUanKKpAiWWJ/UTkEi/aYKn5+90e7DE820zbEaVR9CE2y4z9bzhQijZ0BA== + version "0.9.3" + resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.3.tgz#66d939219bb038d19745abf6024a8ab231786bdb" + integrity sha512-HSLpe3qhAdAoIBbwuTjKnxMGemj80uRpr55IhDv1Xf25h1E0SrKr8nIBFXysKUlYm8ZCkDhAuvX7/hRQnE9rLw== dependencies: image-q "^1.1.1" omggif "^1.0.10" @@ -9910,7 +9912,7 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1. grapheme-splitter@^1.0.4: version "1.0.4" - resolved "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== graphql@16.0.0: @@ -10443,9 +10445,9 @@ http-proxy-middleware@^1.0.0: micromatch "^4.0.2" http-proxy-middleware@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz#5df04f69a89f530c2284cd71eeaa51ba52243289" - integrity sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA== + version "2.0.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz#03af0f4676d172ae775cb5c33f592f40e1a4e07a" + integrity sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" @@ -10547,7 +10549,7 @@ ignore-walk@^3.0.1, ignore-walk@^3.0.3: dependencies: minimatch "^3.0.4" -ignore@^4.0.3, ignore@^4.0.6: +ignore@^4.0.3: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -11868,7 +11870,7 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jscodeshift@^0.13.0: +jscodeshift@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.13.1.tgz#69bfe51e54c831296380585c6d9e733512aecdef" integrity sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ== @@ -11895,7 +11897,7 @@ jscodeshift@^0.13.0: jsdoctypeparser@^9.0.0: version "9.0.0" - resolved "https://registry.npmmirror.com/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz#8c97e2fb69315eb274b0f01377eaa5c940bd7b26" + resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz#8c97e2fb69315eb274b0f01377eaa5c940bd7b26" integrity sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw== jsdom@^16.6.0: @@ -12086,9 +12088,9 @@ jwt-decode@^3.0.0: integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== katex@^0.15.0: - version "0.15.2" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.15.2.tgz#c05ece41ab497597b17abca2cecde3e4c0127f9d" - integrity sha512-FfZ/f6f8bQdLmJ3McXDNTkKenQkoXkItpW0I9bsG2wgb+8JAY5bwpXFtI8ZVrg5hc1wo1X/UIhdkVMpok46tEQ== + version "0.15.3" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.15.3.tgz#08781a7ed26800b20380d959d1ffcd62bca0ec14" + integrity sha512-Al6V7RJsmjklT9QItyHWGaQCt+NYTle1bZwB1e9MR/tLoIT1MXaHy9UpfGSB7eaqDgjjqqRxQOaQGrALCrEyBQ== dependencies: commander "^8.0.0" @@ -12348,16 +12350,16 @@ listr-verbose-renderer@^0.5.0: figures "^2.0.0" listr2@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.4.tgz#d098a1c419284fb26e184b5d5889b235e8912245" - integrity sha512-vJOm5KD6uZXjSsrwajr+mNacIjf87gWvlBEltPWLbTkslUscWAzquyK4xfe9Zd4RDgO5nnwFyV06FC+uVR+5mg== + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== dependencies: cli-truncate "^2.1.0" colorette "^2.0.16" log-update "^4.0.0" p-map "^4.0.0" rfdc "^1.3.0" - rxjs "^7.5.4" + rxjs "^7.5.5" through "^2.3.8" wrap-ansi "^7.0.0" @@ -13100,12 +13102,7 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -"mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -13123,11 +13120,11 @@ mime-types@2.1.18: mime-db "~1.33.0" mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.51.0" + mime-db "1.52.0" mime@1.6.0, mime@^1.2.11, mime@^1.3.4: version "1.6.0" @@ -13512,10 +13509,10 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== -netlify-cli@^9.13.0: - version "9.13.0" - resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.0.tgz#f2f6aa772aed25fa92d170e49260286e97ace308" - integrity sha512-uAseQ475poerqUAgjgEKBEFgINEROz7iob2FJ4Fc5omd7edKWjvZnRtcsOUVNFyWNhyJ56QhA642SIcsc0d1yQ== +netlify-cli@^9.13.1: + version "9.13.1" + resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.1.tgz#f5c272c4c66888a622f8c5daea211fc109cc4e4b" + integrity sha512-l2MUAG53jZvWWB6uAcL1pU28Daty2Kq5hjE5qIKPXO8db5c9Dn28WbqPKEH39X5JOBGqcibDGHQSTWYMBi9wvQ== dependencies: "@netlify/build" "^26.4.0" "@netlify/config" "^17.0.18" @@ -13737,9 +13734,9 @@ node-fetch@2.6.7, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node- whatwg-url "^5.0.0" node-fetch@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.2.tgz#16d33fbe32ca7c6ca1ca8ba5dfea1dd885c59f04" - integrity sha512-Cwhq1JFIoon15wcIkFzubVNFE5GvXGV82pKf4knXXjvGmn7RJKcypeuqcVNZMGDZsAFWyIRya/anwAJr7TWJ7w== + version "3.2.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.3.tgz#a03c9cc2044d21d1a021566bd52f080f333719a6" + integrity sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA== dependencies: data-uri-to-buffer "^4.0.0" fetch-blob "^3.1.4" @@ -14739,9 +14736,9 @@ parse-gitignore@^1.0.1: integrity sha512-UGyowyjtx26n65kdAMWhm6/3uy5uSrpcuH7tt+QEVudiBoVS+eqHxD5kbi9oWVRwj7sCzXqwuM+rUGw7earl6A== parse-headers@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.4.tgz#9eaf2d02bed2d1eff494331ce3df36d7924760bf" - integrity sha512-psZ9iZoCNFLrgRjZ1d8mn0h9WRqJwFxM9q3x7iUjN/YT2OksthDJ5TiPCu2F38kS4zutqfW+YdVVkBZZx3/1aw== + version "2.0.5" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" + integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== parse-json@^4.0.0: version "4.0.0" @@ -15041,7 +15038,7 @@ postcss-calc@^8.2.3: postcss-selector-parser "^6.0.9" postcss-value-parser "^4.2.0" -postcss-colormin@^5.3.0: +postcss-colormin@^*: version "5.3.0" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== @@ -15051,34 +15048,34 @@ postcss-colormin@^5.3.0: colord "^2.9.1" postcss-value-parser "^4.2.0" -postcss-convert-values@^5.1.0: +postcss-convert-values@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.0.tgz#f8d3abe40b4ce4b1470702a0706343eac17e7c10" integrity sha512-GkyPbZEYJiWtQB0KZ0X6qusqFHUepguBCNFi9t5JJc7I2OTXG7C0twbTLvCfaKOLl3rSXmpAwV7W5txd91V84g== dependencies: postcss-value-parser "^4.2.0" -postcss-discard-comments@^5.1.1: +postcss-discard-comments@^*: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== -postcss-discard-duplicates@^5.1.0: +postcss-discard-duplicates@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.0.tgz#7f51b16cd1b89f8180bbc7cee34d6cbabf2ef810" - integrity sha512-782T/buGgb3HOuHOJAHpdyKzAAKsv/BxWqsutnZ+QsiHEcDkY7v+6WWdturuBiSal6XMOO1p1aJvwXdqLD5vhA== +postcss-discard-empty@^*: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== -postcss-discard-overridden@^5.1.0: +postcss-discard-overridden@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== -postcss-discard-unused@^5.1.0: +postcss-discard-unused@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz#8974e9b143d887677304e558c1166d3762501142" integrity sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw== @@ -15107,7 +15104,7 @@ postcss-media-query-parser@^0.2.3: resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== -postcss-merge-idents@^5.1.0: +postcss-merge-idents@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.0.tgz#948e1183cd659cfb5f99c7389f5fcec83c8f9a00" integrity sha512-l+awq6+uUiCILsHahWK5KE25495I4oCKlUrIA+EdBvklnVdWlBEsbkzq5+ouPKb8OAe4WwRBgFvaSq7f77FY+w== @@ -15115,15 +15112,15 @@ postcss-merge-idents@^5.1.0: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.0.tgz#f716bffbf0bdfbde6ea78c36088e21559f8a0a95" - integrity sha512-Gr46srN2tsLD8fudKYoHO56RG0BLQ2nsBRnSZGY04eNBPwTeWa9KeHrbL3tOLAHyB2aliikycPH2TMJG1U+W6g== +postcss-merge-longhand@^*: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.2.tgz#fe3002f38ad5827c1d6f7d5bb3f71d2566a2a138" + integrity sha512-18/bp9DZnY1ai9RlahOfLBbmIUKfKFPASxRCiZ1vlpZqWPCn8qWPFlEozqmWL+kBtcEQmG8W9YqGCstDImvp/Q== dependencies: postcss-value-parser "^4.2.0" - stylehacks "^5.1.0" + stylehacks "^*" -postcss-merge-rules@^5.1.0: +postcss-merge-rules@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.0.tgz#a2d5117eba09c8686a5471d97bd9afcf30d1b41f" integrity sha512-NecukEJovQ0mG7h7xV8wbYAkXGTO3MPKnXvuiXzOKcxoOodfTTKYjeo8TMhAswlSkjcPIBlnKbSFcTuVSDaPyQ== @@ -15133,14 +15130,14 @@ postcss-merge-rules@^5.1.0: cssnano-utils "^3.1.0" postcss-selector-parser "^6.0.5" -postcss-minify-font-values@^5.1.0: +postcss-minify-font-values@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@^5.1.0: +postcss-minify-gradients@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.0.tgz#de0260a67a13b7b321a8adc3150725f2c6612377" integrity sha512-J/TMLklkONn3LuL8wCwfwU8zKC1hpS6VcxFkNUNjmVt53uKqrrykR3ov11mdUYyqVMEx67slMce0tE14cE4DTg== @@ -15149,16 +15146,16 @@ postcss-minify-gradients@^5.1.0: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.0.tgz#e0b1f4e05cfd396682f612856485907e4064f25e" - integrity sha512-q67dcts4Hct6x8+JmhBgctHkbvUsqGIg2IItenjE63iZXMbhjr7AlVZkNnKtIGt/1Wsv7p/7YzeSII6Q+KPXRg== +postcss-minify-params@^*: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.1.tgz#c5f8e7dac565e577dd99904787fbec576cbdbfb2" + integrity sha512-WCpr+J9Uz8XzMpAfg3UL8z5rde6MifBbh5L8bn8S2F5hq/YDJJzASYCnCHvAB4Fqb94ys8v95ULQkW2EhCFvNg== dependencies: browserslist "^4.16.6" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-selectors@^5.2.0: +postcss-minify-selectors@^*: version "5.2.0" resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.0.tgz#17c2be233e12b28ffa8a421a02fc8b839825536c" integrity sha512-vYxvHkW+iULstA+ctVNx0VoRAR4THQQRkG77o0oa4/mBS0OzGvvzLIvHDv/nNEM0crzN2WIyFU5X7wZhaUK3RA== @@ -15193,47 +15190,47 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-normalize-charset@^5.1.0: +postcss-normalize-charset@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== -postcss-normalize-display-values@^5.1.0: +postcss-normalize-display-values@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-positions@^5.1.0: +postcss-normalize-positions@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.0.tgz#902a7cb97cf0b9e8b1b654d4a43d451e48966458" integrity sha512-8gmItgA4H5xiUxgN/3TVvXRoJxkAWLW6f/KKhdsH03atg0cB8ilXnrB5PpSshwVu/dD2ZsRFQcR1OEmSBDAgcQ== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-repeat-style@^5.1.0: +postcss-normalize-repeat-style@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.0.tgz#f6d6fd5a54f51a741cc84a37f7459e60ef7a6398" integrity sha512-IR3uBjc+7mcWGL6CtniKNQ4Rr5fTxwkaDHwMBDGGs1x9IVRkYIT/M4NelZWkAOBdV6v3Z9S46zqaKGlyzHSchw== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-string@^5.1.0: +postcss-normalize-string@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-timing-functions@^5.1.0: +postcss-normalize-timing-functions@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-unicode@^5.1.0: +postcss-normalize-unicode@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75" integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== @@ -15241,7 +15238,7 @@ postcss-normalize-unicode@^5.1.0: browserslist "^4.16.6" postcss-value-parser "^4.2.0" -postcss-normalize-url@^5.1.0: +postcss-normalize-url@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== @@ -15249,14 +15246,14 @@ postcss-normalize-url@^5.1.0: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.0.tgz#aed8b4580c9ad6e8eac034177291187ea16a059c" - integrity sha512-7O1FanKaJkpWFyCghFzIkLhehujV/frGkdofGLwhg5upbLyGsSfiTcZAdSzoPsSUgyPCkBkNMeWR8yVgPdQybg== +postcss-normalize-whitespace@^*: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@^5.1.0: +postcss-ordered-values@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.0.tgz#04ef429e0991b0292bc918b135cd4c038f7b889f" integrity sha512-wU4Z4D4uOIH+BUKkYid36gGDJNQtkVJT7Twv8qH6UyfttbbJWyw4/xIPuVEkkCtQLAJ0EdsNSh8dlvqkXb49TA== @@ -15264,14 +15261,14 @@ postcss-ordered-values@^5.1.0: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@^5.1.0: +postcss-reduce-idents@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.1.0.tgz#386b65cf861a9045663bd349d572027ab138ca4a" integrity sha512-2xDoPTzv98D/HFDrGTgVEBlcuS47wvua2oc4g2WoZdYPwzPWMWb2TCRruCyN7vbl+HAtVLGvEOMZIZb3wYgv7w== dependencies: postcss-value-parser "^4.2.0" -postcss-reduce-initial@^5.1.0: +postcss-reduce-initial@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6" integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== @@ -15279,7 +15276,7 @@ postcss-reduce-initial@^5.1.0: browserslist "^4.16.6" caniuse-api "^3.0.0" -postcss-reduce-transforms@^5.1.0: +postcss-reduce-transforms@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== @@ -15311,7 +15308,7 @@ postcss-sort-media-queries@^4.2.1: dependencies: sort-css-media-queries "2.0.4" -postcss-svgo@^5.1.0: +postcss-svgo@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== @@ -15319,7 +15316,7 @@ postcss-svgo@^5.1.0: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@^5.1.1: +postcss-unique-selectors@^*: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== @@ -15340,7 +15337,7 @@ postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-zindex@^5.1.0: +postcss-zindex@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== @@ -15817,7 +15814,7 @@ react-dev-utils@^12.0.0: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.1, react-dom@^17.0.2: +react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -16019,7 +16016,7 @@ react-waypoint@^10.1.0: prop-types "^15.0.0" react-is "^17.0.1" -react@^17.0.1, react@^17.0.2: +react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -16235,7 +16232,7 @@ redent@^3.0.0: refa@^0.9.0: version "0.9.1" - resolved "https://registry.npmmirror.com/refa/-/refa-0.9.1.tgz#12731fce378d235731b1f73182b20083c8a75ca8" + resolved "https://registry.yarnpkg.com/refa/-/refa-0.9.1.tgz#12731fce378d235731b1f73182b20083c8a75ca8" integrity sha512-egU8LgFq2VXlAfUi8Jcbr5X38wEOadMFf8tCbshgcpVCYlE7k84pJOSlnvXF+muDB4igkdVMq7Z/kiNPqDT9TA== dependencies: regexpp "^3.2.0" @@ -16281,7 +16278,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexp-ast-analysis@^0.2.3: version "0.2.4" - resolved "https://registry.npmmirror.com/regexp-ast-analysis/-/regexp-ast-analysis-0.2.4.tgz#a497a7c8bfbba51438693821e4b0e3ed43e20f1b" + resolved "https://registry.yarnpkg.com/regexp-ast-analysis/-/regexp-ast-analysis-0.2.4.tgz#a497a7c8bfbba51438693821e4b0e3ed43e20f1b" integrity sha512-8L7kOZQaKPxKKAwGuUZxTQtlO3WZ+tiXy4s6G6PKL6trbOXcZoumwC3AOHHFtI/xoSbNxt7jgLvCnP1UADLWqg== dependencies: refa "^0.9.0" @@ -16289,7 +16286,7 @@ regexp-ast-analysis@^0.2.3: regexp-ast-analysis@^0.3.0: version "0.3.0" - resolved "https://registry.npmmirror.com/regexp-ast-analysis/-/regexp-ast-analysis-0.3.0.tgz#386f177dfe5abc5ac58b51eb5962beac64e898ce" + resolved "https://registry.yarnpkg.com/regexp-ast-analysis/-/regexp-ast-analysis-0.3.0.tgz#386f177dfe5abc5ac58b51eb5962beac64e898ce" integrity sha512-11PlbBSUxwWpdj6BdZUKfhDdV9g+cveqHB+BqBQDBD7ZermDBVgtyowUaXTvT0dO3tZYo2bDIr/GoED6X1aYSA== dependencies: refa "^0.9.0" @@ -16772,9 +16769,9 @@ rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: estree-walker "^0.6.1" rollup@^2.23.1, rollup@^2.43.1: - version "2.70.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.0.tgz#17a92e5938e92a251b962352e904c9f558230ec7" - integrity sha512-iEzYw+syFxQ0X9RefVwhr8BA2TNJsTaX8L8dhyeyMECDbmiba+8UQzcu+xZdji0+JQ+s7kouQnw+9Oz5M19XKA== + version "2.70.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" + integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== optionalDependencies: fsevents "~2.3.2" @@ -16790,7 +16787,7 @@ rtl-detect@^1.0.4: resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== -rtlcss@^3.3.0: +rtlcss@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== @@ -16819,7 +16816,7 @@ rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.2, rxjs@^6.6.3: dependencies: tslib "^1.9.0" -rxjs@^7.5.4: +rxjs@^7.5.4, rxjs@^7.5.5: version "7.5.5" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== @@ -16922,7 +16919,7 @@ screenfull@^5.1.0: scslre@^0.1.6: version "0.1.6" - resolved "https://registry.npmmirror.com/scslre/-/scslre-0.1.6.tgz#71a2832e4bf3a9254973a04fbed90aec94f75757" + resolved "https://registry.yarnpkg.com/scslre/-/scslre-0.1.6.tgz#71a2832e4bf3a9254973a04fbed90aec94f75757" integrity sha512-JORxVRlQTfjvlOAaiQKebgFElyAm5/W8b50lgaZ0OkEnKnagJW2ufDh3xRfU75UD9z3FGIu1gL1IyR3Poa6Qmw== dependencies: refa "^0.9.0" @@ -17102,10 +17099,10 @@ shallowequal@^1.1.0: resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== -sharp@^0.30.2: - version "0.30.2" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.30.2.tgz#95b309b2740424702dc19b62a62595dd34a458b1" - integrity sha512-mrMeKI5ECTdYhslPlA2TbBtU3nZXMEBcQwI6qYXjPlu1LpW4HBZLFm6xshMI1HpIdEEJ3UcYp5AKifLT/fEHZQ== +sharp@^0.30.3: + version "0.30.3" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.30.3.tgz#315a1817423a4d1cde5119a21c99c234a7a6fb37" + integrity sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg== dependencies: color "^4.2.1" detect-libc "^2.0.1" @@ -17894,7 +17891,7 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -stylehacks@^5.1.0: +stylehacks@^*: version "5.1.0" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== @@ -18219,9 +18216,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.1: terser "^5.7.2" terser@^5.0.0, terser@^5.10.0, terser@^5.7.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" - integrity sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A== + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== dependencies: acorn "^8.5.0" commander "^2.20.0" @@ -18586,9 +18583,9 @@ ts-node@10.4.0: yn "3.1.1" tsconfig-paths@^3.12.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz#f3e9b8f6876698581d94470c03c95b3a48c0e3d7" - integrity sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw== + version "3.14.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976" + integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" @@ -18729,9 +18726,9 @@ ua-parser-js@^0.7.30: integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== uglify-js@^3.1.4: - version "3.15.2" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.2.tgz#1ed2c976f448063b1f87adb68c741be79959f951" - integrity sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A== + version "3.15.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" + integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== uid-number@0.0.6: version "0.0.6" @@ -19300,6 +19297,11 @@ vlq@^1.0.0: resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== +vscode-languageserver-textdocument@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" + integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== + vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" From f4f4c1dfd8cd89779a3300bfd3c884f2d4c1947f Mon Sep 17 00:00:00 2001 From: Pawel Kowaluk <49525373+pkowaluk@users.noreply.github.com> Date: Tue, 15 Mar 2022 09:31:55 +0100 Subject: [PATCH 017/405] feat(theme-classic): set aria-expanded on expandable sidebar categories (#6914) --- .../docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index cd3fe4266016..d78050a920d0 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -179,6 +179,7 @@ function DocSidebarItemCategory({ } } aria-current={isCurrentPage ? 'page' : undefined} + aria-expanded={collapsible ? !collapsed : undefined} href={collapsible ? hrefWithSSRFallback ?? '#' : hrefWithSSRFallback} {...props}> {label} From 46b1027c4ad60a73da246c2d14bc616bd3f51fde Mon Sep 17 00:00:00 2001 From: WonChul Heo <heowc1992@gmail.com> Date: Tue, 15 Mar 2022 17:45:05 +0900 Subject: [PATCH 018/405] fix(content-blog): remove double leading slash in blog-only paginated view (#6918) * fix(content-blog): Fix permalink function of paginateBlogPosts * add test Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../__snapshots__/blogUtils.test.ts.snap | 135 +++++++++++++++++ .../src/__tests__/blogUtils.test.ts | 138 +++++++++++------- .../src/blogUtils.ts | 4 +- 3 files changed, 226 insertions(+), 51 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap index 3820f35780e5..11e9d9ff1cbf 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap @@ -22,3 +22,138 @@ title: This post links to another one! [Linked post](/blog/2018/12/14/Happy-First-Birthday-Slash)" `; + +exports[`paginateBlogPosts generates right pages 1`] = ` +[ + { + "items": [ + "post1", + "post2", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": "/blog/page/2", + "page": 1, + "permalink": "/blog", + "postsPerPage": 2, + "previousPage": null, + "totalCount": 5, + "totalPages": 3, + }, + }, + { + "items": [ + "post3", + "post4", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": "/blog/page/3", + "page": 2, + "permalink": "/blog/page/2", + "postsPerPage": 2, + "previousPage": "/blog", + "totalCount": 5, + "totalPages": 3, + }, + }, + { + "items": [ + "post5", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": null, + "page": 3, + "permalink": "/blog/page/3", + "postsPerPage": 2, + "previousPage": "/blog/page/2", + "totalCount": 5, + "totalPages": 3, + }, + }, +] +`; + +exports[`paginateBlogPosts generates right pages 2`] = ` +[ + { + "items": [ + "post1", + "post2", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": "/page/2", + "page": 1, + "permalink": "/", + "postsPerPage": 2, + "previousPage": null, + "totalCount": 5, + "totalPages": 3, + }, + }, + { + "items": [ + "post3", + "post4", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": "/page/3", + "page": 2, + "permalink": "/page/2", + "postsPerPage": 2, + "previousPage": "/", + "totalCount": 5, + "totalPages": 3, + }, + }, + { + "items": [ + "post5", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": null, + "page": 3, + "permalink": "/page/3", + "postsPerPage": 2, + "previousPage": "/page/2", + "totalCount": 5, + "totalPages": 3, + }, + }, +] +`; + +exports[`paginateBlogPosts generates right pages 3`] = ` +[ + { + "items": [ + "post1", + "post2", + "post3", + "post4", + "post5", + ], + "metadata": { + "blogDescription": "Blog Description", + "blogTitle": "Blog Title", + "nextPage": null, + "page": 1, + "permalink": "/", + "postsPerPage": 10, + "previousPage": null, + "totalCount": 5, + "totalPages": 1, + }, + }, +] +`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts index c7d638771c08..5460a4440f9f 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/blogUtils.test.ts @@ -11,6 +11,7 @@ import { parseBlogFileName, linkify, getSourceToPermalink, + paginateBlogPosts, type LinkifyParams, } from '../blogUtils'; import fs from 'fs-extra'; @@ -21,56 +22,6 @@ import type { BlogPost, } from '../types'; -const siteDir = path.join(__dirname, '__fixtures__', 'website'); -const contentPaths: BlogContentPaths = { - contentPath: path.join(siteDir, 'blog-with-ref'), - contentPathLocalized: path.join(siteDir, 'blog-with-ref-localized'), -}; -const pluginDir = 'blog-with-ref'; -const blogPosts: BlogPost[] = [ - { - id: 'Happy 1st Birthday Slash!', - metadata: { - permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', - source: path.posix.join( - '@site', - pluginDir, - '2018-12-14-Happy-First-Birthday-Slash.md', - ), - title: 'Happy 1st Birthday Slash!', - description: `pattern name`, - date: new Date('2018-12-14'), - tags: [], - prevItem: { - permalink: '/blog/2019/01/01/date-matter', - title: 'date-matter', - }, - truncated: false, - }, - }, -]; - -const transform = async ( - filePath: string, - options?: Partial<LinkifyParams>, -) => { - const fileContent = await fs.readFile(filePath, 'utf-8'); - const transformedContent = linkify({ - filePath, - fileString: fileContent, - siteDir, - contentPaths, - sourceToPermalink: getSourceToPermalink(blogPosts), - onBrokenMarkdownLink: (brokenMarkdownLink) => { - throw new Error( - `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, - ); - }, - ...options, - }); - return [fileContent, transformedContent]; -}; - describe('truncate', () => { it('truncates texts', () => { expect( @@ -89,6 +40,45 @@ describe('truncate', () => { }); }); +describe('paginateBlogPosts', () => { + it('generates right pages', () => { + const blogPosts = [ + {id: 'post1', metadata: {}, content: 'Foo 1'}, + {id: 'post2', metadata: {}, content: 'Foo 2'}, + {id: 'post3', metadata: {}, content: 'Foo 3'}, + {id: 'post4', metadata: {}, content: 'Foo 4'}, + {id: 'post5', metadata: {}, content: 'Foo 5'}, + ] as BlogPost[]; + expect( + paginateBlogPosts({ + blogPosts, + basePageUrl: '/blog', + blogTitle: 'Blog Title', + blogDescription: 'Blog Description', + postsPerPageOption: 2, + }), + ).toMatchSnapshot(); + expect( + paginateBlogPosts({ + blogPosts, + basePageUrl: '/', + blogTitle: 'Blog Title', + blogDescription: 'Blog Description', + postsPerPageOption: 2, + }), + ).toMatchSnapshot(); + expect( + paginateBlogPosts({ + blogPosts, + basePageUrl: '/', + blogTitle: 'Blog Title', + blogDescription: 'Blog Description', + postsPerPageOption: 10, + }), + ).toMatchSnapshot(); + }); +}); + describe('parseBlogFileName', () => { it('parses file', () => { expect(parseBlogFileName('some-post.md')).toEqual({ @@ -198,6 +188,54 @@ describe('parseBlogFileName', () => { }); describe('linkify', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'website'); + const contentPaths: BlogContentPaths = { + contentPath: path.join(siteDir, 'blog-with-ref'), + contentPathLocalized: path.join(siteDir, 'blog-with-ref-localized'), + }; + const pluginDir = 'blog-with-ref'; + + const blogPosts: BlogPost[] = [ + { + id: 'Happy 1st Birthday Slash!', + metadata: { + permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', + source: path.posix.join( + '@site', + pluginDir, + '2018-12-14-Happy-First-Birthday-Slash.md', + ), + title: 'Happy 1st Birthday Slash!', + description: `pattern name`, + date: new Date('2018-12-14'), + tags: [], + prevItem: { + permalink: '/blog/2019/01/01/date-matter', + title: 'date-matter', + }, + truncated: false, + }, + }, + ]; + + async function transform(filePath: string, options?: Partial<LinkifyParams>) { + const fileContent = await fs.readFile(filePath, 'utf-8'); + const transformedContent = linkify({ + filePath, + fileString: fileContent, + siteDir, + contentPaths, + sourceToPermalink: getSourceToPermalink(blogPosts), + onBrokenMarkdownLink: (brokenMarkdownLink) => { + throw new Error( + `Broken markdown link found: ${JSON.stringify(brokenMarkdownLink)}`, + ); + }, + ...options, + }); + return [fileContent, transformedContent]; + } + it('transforms to correct link', async () => { const post = path.join(contentPaths.contentPath, 'post.md'); const [content, transformedContent] = await transform(post); diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 39d0b70b7be1..eefbf31cba85 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -72,7 +72,9 @@ export function paginateBlogPosts({ const pages: BlogPaginated[] = []; function permalink(page: number) { - return page > 0 ? `${basePageUrl}/page/${page + 1}` : basePageUrl; + return page > 0 + ? normalizeUrl([basePageUrl, `page/${page + 1}`]) + : basePageUrl; } for (let page = 0; page < numberOfPages; page += 1) { From 8d1c1954c194c5dd5f2e4c0407679cb3f83dfc96 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 16 Mar 2022 19:36:57 +0800 Subject: [PATCH 019/405] refactor(content-blog): clean up type definitions; in-code documentation (#6922) * refactor(content-blog): clean up type definitions; in-code documentation * add doc --- .../__snapshots__/blogUtils.test.ts.snap | 12 +- .../__tests__/__snapshots__/feed.test.ts.snap | 1 + .../__snapshots__/index.test.ts.snap | 16 +- .../__snapshots__/translations.test.ts.snap | 8 +- .../src/__tests__/feed.test.ts | 1 + .../src/__tests__/translations.test.ts | 4 +- .../src/authors.ts | 4 +- .../src/blogUtils.ts | 4 +- .../src/feed.ts | 11 +- .../src/index.ts | 16 +- .../src/plugin-content-blog.d.ts | 455 +++++++++++++++--- .../src/types.ts | 59 +-- .../src/theme-classic.d.ts | 8 +- .../src/theme/BlogLayout/index.tsx | 2 +- packages/docusaurus-utils/src/tags.ts | 4 +- .../docs/api/plugins/plugin-content-blog.md | 20 +- 16 files changed, 447 insertions(+), 178 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap index 11e9d9ff1cbf..6137538dad52 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/blogUtils.test.ts.snap @@ -37,7 +37,7 @@ exports[`paginateBlogPosts generates right pages 1`] = ` "page": 1, "permalink": "/blog", "postsPerPage": 2, - "previousPage": null, + "previousPage": undefined, "totalCount": 5, "totalPages": 3, }, @@ -66,7 +66,7 @@ exports[`paginateBlogPosts generates right pages 1`] = ` "metadata": { "blogDescription": "Blog Description", "blogTitle": "Blog Title", - "nextPage": null, + "nextPage": undefined, "page": 3, "permalink": "/blog/page/3", "postsPerPage": 2, @@ -92,7 +92,7 @@ exports[`paginateBlogPosts generates right pages 2`] = ` "page": 1, "permalink": "/", "postsPerPage": 2, - "previousPage": null, + "previousPage": undefined, "totalCount": 5, "totalPages": 3, }, @@ -121,7 +121,7 @@ exports[`paginateBlogPosts generates right pages 2`] = ` "metadata": { "blogDescription": "Blog Description", "blogTitle": "Blog Title", - "nextPage": null, + "nextPage": undefined, "page": 3, "permalink": "/page/3", "postsPerPage": 2, @@ -146,11 +146,11 @@ exports[`paginateBlogPosts generates right pages 3`] = ` "metadata": { "blogDescription": "Blog Description", "blogTitle": "Blog Title", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/", "postsPerPage": 10, - "previousPage": null, + "previousPage": undefined, "totalCount": 5, "totalPages": 1, }, diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index ec932459f47a..5fa35968ed25 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -182,6 +182,7 @@ exports[`rss has feed item for each post 1`] = ` <lastBuildDate>Sat, 06 Mar 2021 00:00:00 GMT</lastBuildDate> <docs>https://validator.w3.org/feed/docs/rss2.html</docs> <generator>https://github.com/jpmonette/feed</generator> + <language>en</language> <copyright>Copyright</copyright> <item> <title><![CDATA[MDX Blog Sample with require calls]]> diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap index 473ed4d5bdc3..1eab791d4450 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap @@ -19,11 +19,11 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/blog/tags/tag-1", "postsPerPage": 3, - "previousPage": null, + "previousPage": undefined, "totalCount": 3, "totalPages": 1, }, @@ -46,11 +46,11 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/blog/tags/tag-2", "postsPerPage": 2, - "previousPage": null, + "previousPage": undefined, "totalCount": 2, "totalPages": 1, }, @@ -83,7 +83,7 @@ exports[`blog plugin works with blog tags 1`] = ` "page": 1, "permalink": "/blog/tags/tag-1", "postsPerPage": 2, - "previousPage": null, + "previousPage": undefined, "totalCount": 3, "totalPages": 2, }, @@ -95,7 +95,7 @@ exports[`blog plugin works with blog tags 1`] = ` "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": null, + "nextPage": undefined, "page": 2, "permalink": "/blog/tags/tag-1/page/2", "postsPerPage": 2, @@ -122,11 +122,11 @@ exports[`blog plugin works with blog tags 1`] = ` "metadata": { "blogDescription": "Blog", "blogTitle": "Blog", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/blog/tags/tag-2", "postsPerPage": 2, - "previousPage": null, + "previousPage": undefined, "totalCount": 2, "totalPages": 1, }, diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap index e07e327f88f7..beb31a882566 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/translations.test.ts.snap @@ -32,11 +32,11 @@ exports[`translateContent falls back when translation is incomplete 1`] = ` "metadata": { "blogDescription": "Someone's random blog", "blogTitle": "My blog", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/", "postsPerPage": 10, - "previousPage": null, + "previousPage": undefined, "totalCount": 1, "totalPages": 1, }, @@ -73,11 +73,11 @@ exports[`translateContent returns translated loaded 1`] = ` "metadata": { "blogDescription": "Someone's random blog (translated)", "blogTitle": "My blog (translated)", - "nextPage": null, + "nextPage": undefined, "page": 1, "permalink": "/", "postsPerPage": 10, - "previousPage": null, + "previousPage": undefined, "totalCount": 1, "totalPages": 1, }, diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index 99ac95ca49ed..03b4abb14d78 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -49,6 +49,7 @@ async function testGenerateFeeds( options, siteConfig: context.siteConfig, outDir: context.outDir, + locale: 'en', }); } diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts index c6cfd5b5ae04..b6f950a10e53 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts @@ -45,8 +45,8 @@ const sampleBlogContent: BlogContent = { postsPerPage: 10, totalPages: 1, totalCount: 1, - previousPage: null, - nextPage: null, + previousPage: undefined, + nextPage: undefined, blogTitle: sampleBlogOptions.blogTitle, blogDescription: sampleBlogOptions.blogDescription, }, diff --git a/packages/docusaurus-plugin-content-blog/src/authors.ts b/packages/docusaurus-plugin-content-blog/src/authors.ts index 9e234d86d9a7..1de62ec0c8c6 100644 --- a/packages/docusaurus-plugin-content-blog/src/authors.ts +++ b/packages/docusaurus-plugin-content-blog/src/authors.ts @@ -70,7 +70,7 @@ type AuthorsParam = { // We may want to deprecate those in favor of using only frontMatter.authors function getFrontMatterAuthorLegacy( frontMatter: BlogPostFrontMatter, -): BlogPostFrontMatterAuthor | undefined { +): Author | undefined { const name = frontMatter.author; const title = frontMatter.author_title ?? frontMatter.authorTitle; const url = frontMatter.author_url ?? frontMatter.authorURL; @@ -92,7 +92,7 @@ function normalizeFrontMatterAuthors( frontMatterAuthors: BlogPostFrontMatterAuthors = [], ): BlogPostFrontMatterAuthor[] { function normalizeAuthor( - authorInput: string | BlogPostFrontMatterAuthor, + authorInput: string | Author, ): BlogPostFrontMatterAuthor { if (typeof authorInput === 'string') { // Technically, we could allow users to provide an author's name here, but diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index eefbf31cba85..ab24aa34ab92 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -88,8 +88,8 @@ export function paginateBlogPosts({ postsPerPage, totalPages: numberOfPages, totalCount, - previousPage: page !== 0 ? permalink(page - 1) : null, - nextPage: page < numberOfPages - 1 ? permalink(page + 1) : null, + previousPage: page !== 0 ? permalink(page - 1) : undefined, + nextPage: page < numberOfPages - 1 ? permalink(page + 1) : undefined, blogDescription, blogTitle, }, diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index 58a59b4302e4..426f19df8db5 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -29,11 +29,13 @@ async function generateBlogFeed({ options, siteConfig, outDir, + locale, }: { blogPosts: BlogPost[]; options: PluginOptions; siteConfig: DocusaurusConfig; outDir: string; + locale: string; }): Promise { if (!blogPosts.length) { return null; @@ -47,11 +49,11 @@ async function generateBlogFeed({ const feed = new Feed({ id: blogBaseUrl, - title: feedOptions.title || `${title} Blog`, + title: feedOptions.title ?? `${title} Blog`, updated, - language: feedOptions.language, + language: feedOptions.language ?? locale, link: blogBaseUrl, - description: feedOptions.description || `${siteConfig.title} Blog`, + description: feedOptions.description ?? `${siteConfig.title} Blog`, favicon: favicon ? normalizeUrl([siteUrl, baseUrl, favicon]) : undefined, copyright: feedOptions.copyright, }); @@ -140,17 +142,20 @@ export async function createBlogFeedFiles({ options, siteConfig, outDir, + locale, }: { blogPosts: BlogPost[]; options: PluginOptions; siteConfig: DocusaurusConfig; outDir: string; + locale: string; }): Promise { const feed = await generateBlogFeed({ blogPosts, options, siteConfig, outDir, + locale, }); const feedTypes = options.feedOptions.type; diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 2027f068ffb4..fca3a7d81b30 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -26,13 +26,9 @@ import type { BlogTag, BlogTags, BlogContent, - BlogItemsToMetadata, - TagsModule, BlogPaginated, BlogContentPaths, BlogMarkdownLoaderOptions, - MetaData, - TagModule, } from './types'; import {PluginOptionSchema} from './pluginOptionSchema'; import type { @@ -52,7 +48,9 @@ import {createBlogFeedFiles} from './feed'; import type { PluginOptions, BlogPostFrontMatter, + BlogPostMetadata, Assets, + TagModule, } from '@docusaurus/plugin-content-blog'; export default async function pluginContentBlog( @@ -214,7 +212,7 @@ export default async function pluginContentBlog( blogTagsListPath, } = blogContents; - const blogItemsToMetadata: BlogItemsToMetadata = {}; + const blogItemsToMetadata: Record = {}; const sidebarBlogPosts = options.blogSidebarCount === 'ALL' @@ -325,11 +323,10 @@ export default async function pluginContentBlog( return; } - const tagsModule: TagsModule = Object.fromEntries( - Object.entries(blogTags).map(([tagKey, tag]) => { + const tagsModule: Record = Object.fromEntries( + Object.entries(blogTags).map(([, tag]) => { const tagModule: TagModule = { allTagsPath: blogTagsListPath, - slug: tagKey, name: tag.name, count: tag.items.length, permalink: tag.permalink, @@ -479,7 +476,7 @@ export default async function pluginContentBlog( metadata, }: { frontMatter: BlogPostFrontMatter; - metadata: MetaData; + metadata: BlogPostMetadata; }): Assets => ({ image: frontMatter.image, authorsImageUrls: metadata.authors.map( @@ -512,6 +509,7 @@ export default async function pluginContentBlog( options, outDir, siteConfig, + locale: currentLocale, }); }, diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index 411f95ced3e3..b369cd978644 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -11,184 +11,487 @@ declare module '@docusaurus/plugin-content-blog' { import type {Overwrite} from 'utility-types'; export interface Assets { + /** + * If `metadata.image` is a collocated image path, this entry will be the + * bundler-generated image path. Otherwise, it's empty, and the image URL + * should be accessed through `frontMatter.image`. + */ image?: string; - authorsImageUrls: (string | undefined)[]; // Array of same size as the original MetaData.authors array + /** + * Array where each item is 1-1 correlated with the `metadata.authors` array + * so that client can render the correct author images. If the author's + * image is a local file path, the slot will be filled with the bundler- + * generated image path; otherwise, it's empty, and the author's image URL + * should be accessed through `authors.imageURL`. + */ + authorsImageUrls: (string | undefined)[]; } - // We allow passing custom fields to authors, e.g., twitter + /** + * Unknown keys are allowed, so that we can pass custom fields to authors, + * e.g., `twitter`. + */ export interface Author extends Record { + /** + * If `name` doesn't exist, an `imageURL` is expected. + */ name?: string; + /** + * The image path could be collocated, in which case + * `metadata.assets.authorsImageUrls` should be used instead. If `imageURL` + * doesn't exist, a `name` is expected. + */ imageURL?: string; + /** + * Used to generate the author's link. + */ url?: string; + /** + * Used as a subtitle for the author, e.g. "maintainer of Docusaurus" + */ title?: string; + /** + * Mainly used for RSS feeds; if `url` doesn't exist, `email` can be used + * to generate a fallback `mailto:` URL. + */ email?: string; } + /** + * Everything is partial/unnormalized, because front matter is always + * preserved as-is. Default values will be applied when generating metadata + */ export type BlogPostFrontMatter = { + /** + * @deprecated Use `slug` instead. + */ id?: string; + /** + * Will override the default title collected from h1 heading. + * @see {@link BlogPostMetadata.title} + */ title?: string; + /** + * Will override the default excerpt. + * @see {@link BlogPostMetadata.description} + */ description?: string; + /** + * Front matter tags, unnormalized. + * @see {@link BlogPostMetadata.tags} + */ tags?: FrontMatterTag[]; + /** + * Custom slug appended after /// + * @see {@link BlogPostMetadata.slug} + */ slug?: string; + /** + * Marks the post as draft and excludes it from the production build. + */ draft?: boolean; - date?: Date | string; // Yaml automatically convert some string patterns as Date, but not all - + /** + * Will override the default publish date inferred from git/filename. Yaml + * only converts standard yyyy-MM-dd format to dates, so this may stay as a + * plain string. + * @see {@link BlogPostMetadata.date} + */ + date?: Date | string; + /** + * Authors, unnormalized. + * @see {@link BlogPostMetadata.authors} + */ authors?: BlogPostFrontMatterAuthors; - - // We may want to deprecate those older author front matter fields later: + /** + * To be deprecated + * @see {@link BlogPostFrontMatterAuthor.name} + */ author?: string; + /** + * To be deprecated + * @see {@link BlogPostFrontMatterAuthor.title} + */ author_title?: string; + /** + * To be deprecated + * @see {@link BlogPostFrontMatterAuthor.url} + */ author_url?: string; + /** + * To be deprecated + * @see {@link BlogPostFrontMatterAuthor.imageURL} + */ author_image_url?: string; - /** @deprecated */ + /** @deprecated v1 legacy */ authorTitle?: string; - /** @deprecated */ + /** @deprecated v1 legacy */ authorURL?: string; - /** @deprecated */ + /** @deprecated v1 legacy */ authorImageURL?: string; + /** + * @see {@link BlogPostMetadata.image} + */ image?: string; + /** + * Used in the head meta + */ keywords?: string[]; + /** + * Hide the right TOC + */ hide_table_of_contents?: boolean; + /** + * Minimum TOC heading level + */ toc_min_heading_level?: number; + /** + * Maximum TOC heading level + */ toc_max_heading_level?: number; }; - export type BlogPostFrontMatterAuthor = Record & { + export type BlogPostFrontMatterAuthor = Author & { + /** + * Will be normalized into the `imageURL` prop. + */ + image_url?: string; + /** + * References an existing author in the authors map. + */ key?: string; - name?: string; - imageURL?: string; - url?: string; - title?: string; }; - // All the possible variants that the user can use for convenience + /** + * Blog post authors can be declared in front matter as a string key + * (referencing an author in authors map), an object (partially overriding the + * data in authors map, or a completely new author), or an array of a mix of + * both. + */ export type BlogPostFrontMatterAuthors = | string | BlogPostFrontMatterAuthor | (string | BlogPostFrontMatterAuthor)[]; + export type BlogPostMetadata = { + /** + * Path to the Markdown source, with `@site` alias. + */ + readonly source: string; + /** + * Used to generate the page h1 heading, tab title, and pagination title. + */ + readonly title: string; + /** + * The publish date of the post. On client side, this will be serialized + * into a string. + */ + readonly date: Date; + /** + * Publish date formatted according to the locale, so that the client can + * render the date regardless of the existence of `Intl.DateTimeFormat`. + */ + readonly formattedDate: string; + /** + * Full link including base URL. + */ + readonly permalink: string; + /** + * Description used in the meta. Could be an empty string (empty content) + */ + readonly description: string; + /** + * Absolute URL to the editing page of the post. Undefined if the post + * shouldn't be edited. + */ + readonly editUrl?: string; + /** + * Reading time in minutes calculated based on word count. + */ + readonly readingTime?: number; + /** + * Whether the truncate marker exists in the post's content. + */ + readonly truncated?: boolean; + /** + * Used in pagination. Generated after the other metadata, so not readonly. + * Content is just a subset of another post's metadata. + */ + nextItem?: {readonly title: string; readonly permalink: string}; + /** + * Used in pagination. Generated after the other metadata, so not readonly. + * Content is just a subset of another post's metadata. + */ + prevItem?: {readonly title: string; readonly permalink: string}; + /** + * Author metadata, normalized. Should be used in joint with + * `assets.authorsImageUrls` on client side. + */ + readonly authors: Author[]; + /** + * Front matter, as-is. + */ + readonly frontMatter: BlogPostFrontMatter & Record; + /** + * Tags, normalized. + */ + readonly tags: readonly { + readonly label: string; + readonly permalink: string; + }[]; + }; + /** + * @returns The edit URL that's directly plugged into metadata. + */ export type EditUrlFunction = (editUrlParams: { + /** + * The root content directory containing this post file, relative to the + * site path. Usually the same as `options.path` but can be localized + */ blogDirPath: string; + /** + * Path to this post file, relative to `blogDirPath` + */ blogPath: string; + /** + * @see {@link BlogPostMetadata.permalink} + */ permalink: string; + /** + * Locale name. + */ locale: string; }) => string | undefined; export type FeedType = 'rss' | 'atom' | 'json'; + /** + * Normalized feed options used within code. + */ export type FeedOptions = { + /** If `null`, no feed is generated. */ type?: FeedType[] | null; + /** Title of generated feed. */ title?: string; + /** Description of generated feed. */ description?: string; + /** Copyright notice. Required because the feed library marked it that. */ copyright: string; + /** Language of the feed. */ language?: string; }; - // Feed options, as provided by user config - export type UserFeedOptions = Overwrite< - Partial, - {type?: FeedOptions['type'] | 'all'} // Handle the type: "all" shortcut - >; - // Duplicate from ngryman/reading-time to keep stability of API + /** + * Duplicate from ngryman/reading-time to keep stability of API. + */ type ReadingTimeOptions = { wordsPerMinute?: number; + /** + * @param char The character to be matched. + * @returns `true` if this character is a word bound. + */ wordBound?: (char: string) => boolean; }; + /** + * Represents the default reading time implementation. + * @returns The reading time directly plugged into metadata. + */ export type ReadingTimeFunction = (params: { + /** Markdown content. */ content: string; + /** Front matter. */ frontMatter?: BlogPostFrontMatter & Record; + /** Options accepted by ngryman/reading-time. */ options?: ReadingTimeOptions; }) => number; + /** + * @returns The reading time directly plugged into metadata. `undefined` to + * hide reading time for a specific post. + */ export type ReadingTimeFunctionOption = ( + /** + * The `options` is not provided by the caller; the user can inject their + * own option values into `defaultReadingTime` + */ params: Required[0], 'options'>> & { + /** + * The default reading time implementation from ngryman/reading-time. + */ defaultReadingTime: ReadingTimeFunction; }, ) => number | undefined; - + /** + * Plugin options after normalization. + */ export type PluginOptions = RemarkAndRehypePluginOptions & { + /** Plugin ID. */ id?: string; + /** + * Path to the blog content directory on the file system, relative to site + * directory. + */ path: string; + /** + * URL route for the blog section of your site. **DO NOT** include a + * trailing slash. Use `/` to put the blog at root path. + */ routeBasePath: string; + /** + * URL route for the tags section of your blog. Will be appended to + * `routeBasePath`. **DO NOT** include a trailing slash. + */ tagsBasePath: string; + /** + * URL route for the archive section of your blog. Will be appended to + * `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to + * disable generation of archive. + */ archiveBasePath: string | null; + /** + * Array of glob patterns matching Markdown files to be built, relative to + * the content path. + */ include: string[]; + /** + * Array of glob patterns matching Markdown files to be excluded. Serves as + * refinement based on the `include` option. + */ exclude: string[]; + /** + * Number of posts to show per page in the listing page. Use `'ALL'` to + * display all posts on one listing page. + */ postsPerPage: number | 'ALL'; + /** Root component of the blog listing page. */ blogListComponent: string; + /** Root component of each blog post page. */ blogPostComponent: string; + /** Root component of the tags list page. */ blogTagsListComponent: string; + /** Root component of the "posts containing tag" page. */ blogTagsPostsComponent: string; + /** Root component of the blog archive page. */ blogArchiveComponent: string; + /** Blog page title for better SEO. */ blogTitle: string; + /** Blog page meta description for better SEO. */ blogDescription: string; + /** + * Number of blog post elements to show in the blog sidebar. `'ALL'` to show + * all blog posts; `0` to disable. + */ blogSidebarCount: number | 'ALL'; + /** Title of the blog sidebar. */ blogSidebarTitle: string; + /** Truncate marker marking where the summary ends. */ truncateMarker: RegExp; + /** Show estimated reading time for the blog post. */ showReadingTime: boolean; - feedOptions: { - type?: FeedType[] | null; - title?: string; - description?: string; - copyright: string; - language?: string; - }; + /** Blog feed. */ + feedOptions: FeedOptions; + /** + * Base URL to edit your site. The final URL is computed by `editUrl + + * relativePostPath`. Using a function allows more nuanced control for each + * file. Omitting this variable entirely will disable edit links. + */ editUrl?: string | EditUrlFunction; + /** + * The edit URL will target the localized file, instead of the original + * unlocalized file. Ignored when `editUrl` is a function. + */ editLocalizedFiles?: boolean; admonitions: Record; + /** Path to the authors map file, relative to the blog content directory. */ authorsMapPath: string; + /** A callback to customize the reading time number displayed. */ readingTime: ReadingTimeFunctionOption; + /** Governs the direction of blog post sorting. */ sortPosts: 'ascending' | 'descending'; }; - // Options, as provided in the user config (before normalization) + + /** + * Feed options, as provided by user config. `type` accepts `all` as shortcut + */ + export type UserFeedOptions = Overwrite< + Partial, + { + /** Type of feed to be generated. Use `null` to disable generation. */ + type?: FeedOptions['type'] | 'all' | FeedType; + } + >; + /** + * Options as provided in the user config (before normalization) + */ export type Options = Overwrite< Partial, - {feedOptions?: UserFeedOptions} + { + /** Blog feed. */ + feedOptions?: UserFeedOptions; + } >; + + export type TagModule = { + /** Permalink of the tag's own page. */ + permalink: string; + /** Name of the tag. */ + name: string; + /** Number of posts with this tag. */ + count: number; + /** The tags list page. */ + allTagsPath: string; + }; + + export type BlogSidebar = { + title: string; + items: {title: string; permalink: string}[]; + }; } declare module '@theme/BlogPostPage' { - import type {BlogSidebar} from '@theme/BlogSidebar'; import type {TOCItem} from '@docusaurus/types'; import type { BlogPostFrontMatter, - Author, + BlogPostMetadata, Assets, + BlogSidebar, } from '@docusaurus/plugin-content-blog'; + import type {Overwrite} from 'utility-types'; export type FrontMatter = BlogPostFrontMatter; - export type Metadata = { - readonly title: string; - readonly date: string; - readonly formattedDate: string; - readonly permalink: string; - readonly description?: string; - readonly editUrl?: string; - readonly readingTime?: number; - readonly truncated?: string; - readonly nextItem?: {readonly title: string; readonly permalink: string}; - readonly prevItem?: {readonly title: string; readonly permalink: string}; - readonly authors: Author[]; - readonly frontMatter: FrontMatter & Record; - readonly tags: readonly { - readonly label: string; - readonly permalink: string; - }[]; - }; + export type Metadata = Overwrite< + BlogPostMetadata, + { + /** The publish date of the post. Serialized from the `Date` object. */ + date: string; + } + >; export type Content = { + // TODO remove this. `metadata.frontMatter` is preferred because it can be + // accessed in enhanced plugins + /** Same as `metadata.frontMatter` */ readonly frontMatter: FrontMatter; + /** + * Usually image assets that may be collocated like `./img/thumbnail.png`. + * The loader would also bundle these assets and the client should use these + * in priority. + */ readonly assets: Assets; + /** Metadata of the post. */ readonly metadata: Metadata; + /** A list of TOC items (headings). */ readonly toc: readonly TOCItem[]; + /** Renders the actual MDX content. */ (): JSX.Element; }; export interface Props { + /** Blog sidebar. */ readonly sidebar: BlogSidebar; + /** Content of this post as an MDX component, with useful metadata. */ readonly content: Content; } @@ -197,23 +500,38 @@ declare module '@theme/BlogPostPage' { declare module '@theme/BlogListPage' { import type {Content} from '@theme/BlogPostPage'; - import type {BlogSidebar} from '@theme/BlogSidebar'; + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; export type Metadata = { + /** Title of the entire blog. */ readonly blogTitle: string; + /** Blog description. */ readonly blogDescription: string; + /** Permalink to the next list page. */ readonly nextPage?: string; - readonly page: number; + /** Permalink of the current page. */ readonly permalink: string; - readonly postsPerPage: number; + /** Permalink to the previous list page. */ readonly previousPage?: string; + /** Index of the current page, 1-based. */ + readonly page: number; + /** Posts displayed on each list page. */ + readonly postsPerPage: number; + /** Total number of posts in the entire blog. */ readonly totalCount: number; + /** Total number of list pages. */ readonly totalPages: number; }; export interface Props { + /** Blog sidebar. */ readonly sidebar: BlogSidebar; + /** Metadata of the current listing page. */ readonly metadata: Metadata; + /** + * Array of blog posts included on this page. Every post's metadata is also + * available. + */ readonly items: readonly {readonly content: Content}[]; } @@ -221,34 +539,34 @@ declare module '@theme/BlogListPage' { } declare module '@theme/BlogTagsListPage' { - import type {BlogSidebar} from '@theme/BlogSidebar'; - - export type Tag = { - permalink: string; - name: string; - count: number; - allTagsPath: string; - slug: string; - }; + import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog'; export interface Props { + /** Blog sidebar. */ readonly sidebar: BlogSidebar; - readonly tags: Readonly>; + /** A map from tag names to the full tag module. */ + readonly tags: Readonly>; } export default function BlogTagsListPage(props: Props): JSX.Element; } declare module '@theme/BlogTagsPostsPage' { - import type {BlogSidebar} from '@theme/BlogSidebar'; - import type {Tag} from '@theme/BlogTagsListPage'; + import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog'; import type {Content} from '@theme/BlogPostPage'; import type {Metadata} from '@theme/BlogListPage'; export interface Props { + /** Blog sidebar. */ readonly sidebar: BlogSidebar; - readonly metadata: Tag; + /** Metadata of this tag. */ + readonly metadata: TagModule; + /** Looks exactly the same as the posts list page */ readonly listMetadata: Metadata; + /** + * Array of blog posts included on this page. Every post's metadata is also + * available. + */ readonly items: readonly {readonly content: Content}[]; } @@ -258,10 +576,13 @@ declare module '@theme/BlogTagsPostsPage' { declare module '@theme/BlogArchivePage' { import type {Content} from '@theme/BlogPostPage'; + /** We may add extra metadata or prune some metadata from here */ export type ArchiveBlogPost = Content; export interface Props { + /** The entirety of the blog's data. */ readonly archive: { + /** All posts. Can select any useful data/metadata to render. */ readonly blogPosts: readonly ArchiveBlogPost[]; }; } diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index 54dc73c501b0..451f571d9342 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -5,15 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import type {Tag} from '@docusaurus/utils'; import type { BrokenMarkdownLink, ContentPaths, } from '@docusaurus/utils/lib/markdownLinks'; -import type { - BlogPostFrontMatter, - Author, -} from '@docusaurus/plugin-content-blog'; +import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog'; +import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage'; export type BlogContentPaths = ContentPaths; @@ -42,65 +39,15 @@ export interface BlogTag { export interface BlogPost { id: string; - metadata: MetaData; + metadata: BlogPostMetadata; content: string; } -export interface BlogPaginatedMetadata { - permalink: string; - page: number; - postsPerPage: number; - totalPages: number; - totalCount: number; - previousPage: string | null; - nextPage: string | null; - blogTitle: string; - blogDescription: string; -} - export interface BlogPaginated { metadata: BlogPaginatedMetadata; items: string[]; // blog post permalinks } -export interface MetaData { - permalink: string; - source: string; - description: string; - date: Date; - formattedDate: string; - tags: Tag[]; - title: string; - readingTime?: number; - prevItem?: Paginator; - nextItem?: Paginator; - truncated: boolean; - editUrl?: string; - authors: Author[]; - frontMatter: BlogPostFrontMatter & Record; -} - -export interface Paginator { - title: string; - permalink: string; -} - -export interface BlogItemsToMetadata { - [key: string]: MetaData; -} - -export interface TagsModule { - [key: string]: TagModule; -} - -export interface TagModule { - allTagsPath: string; - slug: string; - name: string; - count: number; - permalink: string; -} - export type BlogBrokenMarkdownLink = BrokenMarkdownLink; export type BlogMarkdownLoaderOptions = { siteDir: string; diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index bd926b51379d..f6973773c9b3 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -41,11 +41,7 @@ declare module '@theme/BlogListPaginator' { } declare module '@theme/BlogSidebar' { - export type BlogSidebarItem = {title: string; permalink: string}; - export type BlogSidebar = { - title: string; - items: BlogSidebarItem[]; - }; + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; export interface Props { readonly sidebar: BlogSidebar; @@ -106,7 +102,7 @@ declare module '@theme/BlogPostPaginator' { declare module '@theme/BlogLayout' { import type {ReactNode} from 'react'; import type {Props as LayoutProps} from '@theme/Layout'; - import type {BlogSidebar} from '@theme/BlogSidebar'; + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; export interface Props extends LayoutProps { readonly sidebar?: BlogSidebar; diff --git a/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx index 08c183746090..009eef93276d 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx @@ -22,7 +22,7 @@ export default function BlogLayout(props: Props): JSX.Element {
    {hasSidebar && ( )}
    = { * override the other */ export function groupTaggedItems( - items: Item[], - getItemTags: (item: Item) => Tag[], + items: readonly Item[], + getItemTags: (item: Item) => readonly Tag[], ): Record> { const result: Record> = {}; diff --git a/website/docs/api/plugins/plugin-content-blog.md b/website/docs/api/plugins/plugin-content-blog.md index 7eda77338a4c..dbd658b6812e 100644 --- a/website/docs/api/plugins/plugin-content-blog.md +++ b/website/docs/api/plugins/plugin-content-blog.md @@ -37,32 +37,32 @@ Accepted fields: | Name | Type | Default | Description | | --- | --- | --- | --- | -| `path` | `string` | `'blog'` | Path to the blog content directory on the filesystem, relative to site dir. | -| `editUrl` | string \| EditUrlFunction | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | +| `path` | `string` | `'blog'` | Path to the blog content directory on the file system, relative to site dir. | +| `editUrl` | string \| EditUrlFunction | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativePostPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | | `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. | | `blogTitle` | `string` | `'Blog'` | Blog page title for better SEO. | | `blogDescription` | `string` | `'Blog'` | Blog page meta description for better SEO. | -| `blogSidebarCount` | number \| 'ALL' | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable | +| `blogSidebarCount` | number \| 'ALL' | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable. | | `blogSidebarTitle` | `string` | `'Recent posts'` | Title of the blog sidebar. | | `routeBasePath` | `string` | `'blog'` | URL route for the blog section of your site. **DO NOT** include a trailing slash. Use `/` to put the blog at root path. | -| `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. | -| `archiveBasePath` | string \| null | `'/archive'` | URL route for the archive blog section of your site. It is prepended to the `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. | -| `include` | `string[]` | `['**/*.{md,mdx}']` | Matching files will be included and processed. | -| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. | +| `tagsBasePath` | `string` | `'tags'` | URL route for the tags section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. | +| `archiveBasePath` | string \| null | `'archive'` | URL route for the archive section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. | +| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. | +| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. | | `postsPerPage` | number \| 'ALL' | `10` | Number of posts to show per page in the listing page. Use `'ALL'` to display all posts on one listing page. | | `blogListComponent` | `string` | `'@theme/BlogListPage'` | Root component of the blog listing page. | | `blogPostComponent` | `string` | `'@theme/BlogPostPage'` | Root component of each blog post page. | -| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page | +| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page. | | `blogTagsPostsComponent` | `string` | `'@theme/BlogTagsPostsPage'` | Root component of the "posts containing tag" page. | | `blogArchiveComponent` | `string` | `'@theme/BlogArchivePage'` | Root component of the blog archive page. | | `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. | | `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. | | `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. | | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | -| `truncateMarker` | `string` | `//` | Truncate marker, can be a regex or string. | +| `truncateMarker` | `RegExp` | `//` | Truncate marker marking where the summary ends. | | `showReadingTime` | `boolean` | `true` | Show estimated reading time for the blog post. | | `readingTime` | `ReadingTimeFunctionOption` | The default reading time | A callback to customize the reading time number displayed. | -| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory specified with `path`. Can also be a `json` file. | +| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory. | | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions.type` | FeedType \| FeedType[] \| 'all' \| null | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | From 68aaf9201f1bdff94c970c43d4ebc90761b84fdb Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 16 Mar 2022 20:47:15 +0800 Subject: [PATCH 020/405] feat(core): allow plugin lifecycles to return relative paths (#6921) * feat(core): resolve plugin lifecycles returning relative paths * fix typo * fix tests * revert * rename path -> entryPath --- packages/docusaurus-plugin-debug/src/index.ts | 4 +-- .../src/index.ts | 3 +- .../src/index.ts | 3 +- .../src/index.ts | 6 ++-- packages/docusaurus-plugin-pwa/src/index.ts | 6 ++-- packages/docusaurus-plugin-pwa/src/options.ts | 3 +- .../docusaurus-theme-classic/src/index.ts | 9 +++-- .../src/index.ts | 7 ++-- .../src/index.ts | 4 +-- packages/docusaurus-types/src/index.d.ts | 4 +++ .../src/commands/swizzle/context.ts | 4 +-- .../docusaurus/src/commands/swizzle/themes.ts | 13 +++++-- .../__tests__/__fixtures__/plugin-empty.js | 1 + .../__tests__/__fixtures__/plugin-foo-bar.js | 1 + .../__fixtures__/plugin-hello-world.js | 1 + .../client-modules/__tests__/index.test.ts | 36 +++++++++---------- .../src/server/client-modules/index.ts | 11 ++++-- packages/docusaurus/src/server/index.ts | 7 +++- .../__snapshots__/index.test.ts.snap | 2 ++ .../docusaurus/src/server/plugins/init.ts | 20 ++++++++--- .../docusaurus/src/server/themes/index.ts | 5 ++- .../translations/translationsExtractor.ts | 2 +- website/_dogfooding/dogfooding.config.js | 4 +-- .../plugin-methods/extend-infrastructure.md | 8 ++--- website/docusaurus.config.js | 2 +- website/src/plugins/changelog/index.js | 2 +- 26 files changed, 100 insertions(+), 68 deletions(-) diff --git a/packages/docusaurus-plugin-debug/src/index.ts b/packages/docusaurus-plugin-debug/src/index.ts index 0094918b4c4d..01a9e0a4e03f 100644 --- a/packages/docusaurus-plugin-debug/src/index.ts +++ b/packages/docusaurus-plugin-debug/src/index.ts @@ -24,10 +24,10 @@ export default function pluginDebug({ name: 'docusaurus-plugin-debug', getThemePath() { - return path.resolve(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, async contentLoaded({actions: {createData, addRoute}, allContent}) { diff --git a/packages/docusaurus-plugin-google-analytics/src/index.ts b/packages/docusaurus-plugin-google-analytics/src/index.ts index 3abe326da3ce..5e75e58b9929 100644 --- a/packages/docusaurus-plugin-google-analytics/src/index.ts +++ b/packages/docusaurus-plugin-google-analytics/src/index.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; import {Joi} from '@docusaurus/utils-validation'; import type { LoadContext, @@ -28,7 +27,7 @@ export default function pluginGoogleAnalytics( name: 'docusaurus-plugin-google-analytics', getClientModules() { - return isProd ? [path.resolve(__dirname, './analytics')] : []; + return isProd ? ['./analytics'] : []; }, injectHtmlTags() { diff --git a/packages/docusaurus-plugin-google-gtag/src/index.ts b/packages/docusaurus-plugin-google-gtag/src/index.ts index ad66bca06929..238fe699a69a 100644 --- a/packages/docusaurus-plugin-google-gtag/src/index.ts +++ b/packages/docusaurus-plugin-google-gtag/src/index.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; import {Joi} from '@docusaurus/utils-validation'; import type { LoadContext, @@ -32,7 +31,7 @@ export default function pluginGoogleGtag( }, getClientModules() { - return isProd ? [path.resolve(__dirname, './gtag')] : []; + return isProd ? ['./gtag'] : []; }, injectHtmlTags() { diff --git a/packages/docusaurus-plugin-ideal-image/src/index.ts b/packages/docusaurus-plugin-ideal-image/src/index.ts index 1630f46e597d..de28f087dfb3 100644 --- a/packages/docusaurus-plugin-ideal-image/src/index.ts +++ b/packages/docusaurus-plugin-ideal-image/src/index.ts @@ -15,8 +15,6 @@ import type {PluginOptions} from '@docusaurus/plugin-ideal-image'; import {Joi} from '@docusaurus/utils-validation'; import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations'; -import path from 'path'; - export default function pluginIdealImage( context: LoadContext, options: PluginOptions, @@ -29,11 +27,11 @@ export default function pluginIdealImage( name: 'docusaurus-plugin-ideal-image', getThemePath() { - return path.resolve(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, getDefaultCodeTranslationMessages() { diff --git a/packages/docusaurus-plugin-pwa/src/index.ts b/packages/docusaurus-plugin-pwa/src/index.ts index 368fc5e9cb11..e43af904e070 100644 --- a/packages/docusaurus-plugin-pwa/src/index.ts +++ b/packages/docusaurus-plugin-pwa/src/index.ts @@ -64,10 +64,10 @@ export default function pluginPWA( name: 'docusaurus-plugin-pwa', getThemePath() { - return path.resolve(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, getClientModules() { @@ -138,7 +138,7 @@ export default function pluginPWA( const swSourceFileTest = /\.m?js$/; const swWebpackConfig: Configuration = { - entry: path.resolve(__dirname, 'sw.js'), + entry: require.resolve('./sw.js'), output: { path: outDir, filename: 'sw.js', diff --git a/packages/docusaurus-plugin-pwa/src/options.ts b/packages/docusaurus-plugin-pwa/src/options.ts index ae5242b0b6c5..418313fafb4f 100644 --- a/packages/docusaurus-plugin-pwa/src/options.ts +++ b/packages/docusaurus-plugin-pwa/src/options.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; import {Joi} from '@docusaurus/utils-validation'; import type { ThemeConfig, @@ -24,7 +23,7 @@ const DEFAULT_OPTIONS = { injectManifestConfig: {}, pwaHead: [], swCustom: undefined, - swRegister: path.join(__dirname, 'registerSw.js'), + swRegister: './registerSw.js', reloadPopup: '@theme/PwaReloadPopup', }; diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index d5066c5d4f9a..a3904f3582a5 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -8,7 +8,6 @@ import type {LoadContext, Plugin, PostCssOptions} from '@docusaurus/types'; import type {ThemeConfig} from '@docusaurus/theme-common'; import {getTranslationFiles, translateThemeConfig} from './translations'; -import path from 'path'; import {createRequire} from 'module'; import type {Plugin as PostCssPlugin} from 'postcss'; import rtlcss from 'rtlcss'; @@ -112,11 +111,11 @@ export default function docusaurusThemeClassic( name: 'docusaurus-theme-classic', getThemePath() { - return path.join(__dirname, '../lib-next/theme'); + return '../lib-next/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, getTranslationFiles: async () => getTranslationFiles({themeConfig}), @@ -137,8 +136,8 @@ export default function docusaurusThemeClassic( getClientModules() { const modules = [ require.resolve(getInfimaCSSFile(direction)), - path.resolve(__dirname, './prism-include-languages'), - path.resolve(__dirname, './admonitions.css'), + './prism-include-languages', + './admonitions.css', ]; if (customCss) { diff --git a/packages/docusaurus-theme-live-codeblock/src/index.ts b/packages/docusaurus-theme-live-codeblock/src/index.ts index 67d239b6852e..0f02878c50c0 100644 --- a/packages/docusaurus-theme-live-codeblock/src/index.ts +++ b/packages/docusaurus-theme-live-codeblock/src/index.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations'; import type {LoadContext, Plugin} from '@docusaurus/types'; @@ -18,10 +17,10 @@ export default function themeLiveCodeblock(context: LoadContext): Plugin { name: 'docusaurus-theme-live-codeblock', getThemePath() { - return path.resolve(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, getDefaultCodeTranslationMessages() { @@ -35,7 +34,7 @@ export default function themeLiveCodeblock(context: LoadContext): Plugin { return { resolve: { alias: { - buble: path.resolve(__dirname, './custom-buble.js'), + buble: require.resolve('./custom-buble.js'), }, }, }; diff --git a/packages/docusaurus-theme-search-algolia/src/index.ts b/packages/docusaurus-theme-search-algolia/src/index.ts index 6c41d564f8c9..46f80161652c 100644 --- a/packages/docusaurus-theme-search-algolia/src/index.ts +++ b/packages/docusaurus-theme-search-algolia/src/index.ts @@ -47,10 +47,10 @@ export default function themeSearchAlgolia(context: LoadContext): Plugin { name: 'docusaurus-theme-search-algolia', getThemePath() { - return path.resolve(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, getDefaultCodeTranslationMessages() { diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index f29f4d521dcb..cead1c6ed2d6 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -290,6 +290,10 @@ export interface Plugin { export type InitializedPlugin = Plugin & { readonly options: Required; readonly version: DocusaurusPluginVersionInformation; + /** + * The absolute path to the folder containing the entry point file. + */ + readonly path: string; }; export type LoadedPlugin = InitializedPlugin & { diff --git a/packages/docusaurus/src/commands/swizzle/context.ts b/packages/docusaurus/src/commands/swizzle/context.ts index f4ca176f09e0..7c06ef00c7f2 100644 --- a/packages/docusaurus/src/commands/swizzle/context.ts +++ b/packages/docusaurus/src/commands/swizzle/context.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import {createRequire} from 'module'; import {loadContext, loadPluginConfigs} from '../../server'; import initPlugins, {normalizePluginConfigs} from '../../server/plugins/init'; import type {InitializedPlugin} from '@docusaurus/types'; @@ -15,7 +14,6 @@ export async function initSwizzleContext( siteDir: string, ): Promise { const context = await loadContext(siteDir); - const pluginRequire = createRequire(context.siteConfigPath); const pluginConfigs = await loadPluginConfigs(context); const plugins: InitializedPlugin[] = await initPlugins({ @@ -25,7 +23,7 @@ export async function initSwizzleContext( const pluginsNormalized = await normalizePluginConfigs( pluginConfigs, - pluginRequire, + context.siteConfigPath, ); return { diff --git a/packages/docusaurus/src/commands/swizzle/themes.ts b/packages/docusaurus/src/commands/swizzle/themes.ts index ead1fc69994c..49381089dd18 100644 --- a/packages/docusaurus/src/commands/swizzle/themes.ts +++ b/packages/docusaurus/src/commands/swizzle/themes.ts @@ -6,6 +6,7 @@ */ import logger from '@docusaurus/logger'; +import path from 'path'; import leven from 'leven'; import _ from 'lodash'; import {askThemeName} from './prompts'; @@ -132,8 +133,16 @@ export function getThemePath({ }): string { const pluginInstance = getPluginByThemeName(plugins, themeName); const themePath = typescript - ? pluginInstance.instance.getTypeScriptThemePath?.() - : pluginInstance.instance.getThemePath?.(); + ? pluginInstance.instance.getTypeScriptThemePath && + path.resolve( + pluginInstance.instance.path, + pluginInstance.instance.getTypeScriptThemePath(), + ) + : pluginInstance.instance.getThemePath && + path.resolve( + pluginInstance.instance.path, + pluginInstance.instance.getThemePath(), + ); if (!themePath) { logger.warn( typescript diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js index 6b8398c7d40e..def0cfe25df1 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js +++ b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js @@ -8,5 +8,6 @@ module.exports = function() { return { name: 'plugin-empty', + path: __dirname, }; }; diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js index 52d26e15a638..94276570052e 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js +++ b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js @@ -8,6 +8,7 @@ module.exports = function() { return { name: 'plugin-foo-bar', + path: __dirname, getClientModules() { return ['foo', 'bar']; }, diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js index 9fa02b19e68e..3047719c6d9e 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js +++ b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js @@ -8,6 +8,7 @@ module.exports = function() { return { plugin: 'plugin-hello-world', + path: __dirname, getClientModules() { return ['hello', 'world']; }, diff --git a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts index 46744e2d3aa8..1eb43c28b933 100644 --- a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts @@ -21,8 +21,8 @@ describe('loadClientModules', () => { const clientModules = loadClientModules([pluginFooBar()]); expect(clientModules).toMatchInlineSnapshot(` [ - "foo", - "bar", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", ] `); }); @@ -34,10 +34,10 @@ describe('loadClientModules', () => { ]); expect(clientModules).toMatchInlineSnapshot(` [ - "foo", - "bar", - "hello", - "world", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", ] `); }); @@ -49,10 +49,10 @@ describe('loadClientModules', () => { ]); expect(clientModules).toMatchInlineSnapshot(` [ - "hello", - "world", - "foo", - "bar", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", ] `); }); @@ -65,10 +65,10 @@ describe('loadClientModules', () => { ]); expect(clientModules).toMatchInlineSnapshot(` [ - "hello", - "world", - "foo", - "bar", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", ] `); }); @@ -81,10 +81,10 @@ describe('loadClientModules', () => { ]); expect(clientModules).toMatchInlineSnapshot(` [ - "hello", - "world", - "foo", - "bar", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", + "/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", ] `); }); diff --git a/packages/docusaurus/src/server/client-modules/index.ts b/packages/docusaurus/src/server/client-modules/index.ts index 68080ee72c9b..6a51d751a5e6 100644 --- a/packages/docusaurus/src/server/client-modules/index.ts +++ b/packages/docusaurus/src/server/client-modules/index.ts @@ -5,10 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -import type {Plugin} from '@docusaurus/types'; +import path from 'path'; +import type {LoadedPlugin} from '@docusaurus/types'; export default function loadClientModules( - plugins: Plugin[], + plugins: LoadedPlugin[], ): string[] { - return plugins.flatMap((plugin) => plugin.getClientModules?.() ?? []); + return plugins.flatMap( + (plugin) => + plugin.getClientModules?.().map((p) => path.resolve(plugin.path, p)) ?? + [], + ); } diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index b58aa1c54b0a..678c5823c6af 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -176,8 +176,10 @@ export async function loadPluginConfigs( // - Resolve aliased theme components // - Inject scripts/stylesheets function createBootstrapPlugin({ + siteDir, siteConfig, }: { + siteDir: string; siteConfig: DocusaurusConfig; }): LoadedPlugin { const { @@ -192,6 +194,7 @@ function createBootstrapPlugin({ id: 'default', }, version: {type: 'synthetic'}, + path: siteDir, getClientModules() { return siteConfigClientModules; }, @@ -244,6 +247,8 @@ function createMDXFallbackPlugin({ id: 'default', }, version: {type: 'synthetic'}, + // Synthetic, the path doesn't matter much + path: '.', configureWebpack(config, isServer, {getJSLoader}) { // We need the mdx fallback loader to exclude files that were already // processed by content plugins mdx loaders. This works, but a bit @@ -336,7 +341,7 @@ export default ${JSON.stringify(siteConfig, null, 2)}; `, ); - plugins.push(createBootstrapPlugin({siteConfig})); + plugins.push(createBootstrapPlugin({siteDir, siteConfig})); plugins.push(createMDXFallbackPlugin({siteDir, siteConfig})); // Load client modules. diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap index 57398999df4f..7435ca95c597 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap @@ -19,6 +19,7 @@ exports[`loadPlugins loads plugins 1`] = ` "options": { "id": "default", }, + "path": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin", "prop": "a", "version": { "type": "local", @@ -31,6 +32,7 @@ exports[`loadPlugins loads plugins 1`] = ` "options": { "id": "default", }, + "path": "/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin", "version": { "type": "local", }, diff --git a/packages/docusaurus/src/server/plugins/init.ts b/packages/docusaurus/src/server/plugins/init.ts index 6e4a600386f3..504071617a07 100644 --- a/packages/docusaurus/src/server/plugins/init.ts +++ b/packages/docusaurus/src/server/plugins/init.ts @@ -6,6 +6,7 @@ */ import {createRequire} from 'module'; +import path from 'path'; import importFresh from 'import-fresh'; import type { DocusaurusPluginVersionInformation, @@ -32,12 +33,18 @@ export type NormalizedPluginConfig = { path: string; module: ImportedPluginModule; }; + /** + * Different from pluginModule.path, this one is always an absolute path used + * to resolve relative paths returned from lifecycles + */ + entryPath: string; }; async function normalizePluginConfig( pluginConfig: PluginConfig, - pluginRequire: NodeRequire, + configPath: string, ): Promise { + const pluginRequire = createRequire(configPath); // plugins: ['./plugin'] if (typeof pluginConfig === 'string') { const pluginModuleImport = pluginConfig; @@ -50,6 +57,7 @@ async function normalizePluginConfig( path: pluginModuleImport, module: pluginModule, }, + entryPath: pluginPath, }; } @@ -58,6 +66,7 @@ async function normalizePluginConfig( return { plugin: pluginConfig, options: {}, + entryPath: configPath, }; } @@ -75,6 +84,7 @@ async function normalizePluginConfig( path: pluginModuleImport, module: pluginModule, }, + entryPath: pluginPath, }; } // plugins: [ @@ -83,16 +93,17 @@ async function normalizePluginConfig( return { plugin: pluginConfig[0], options: pluginConfig[1], + entryPath: configPath, }; } export async function normalizePluginConfigs( pluginConfigs: PluginConfig[], - pluginRequire: NodeRequire, + configPath: string, ): Promise { return Promise.all( pluginConfigs.map((pluginConfig) => - normalizePluginConfig(pluginConfig, pluginRequire), + normalizePluginConfig(pluginConfig, configPath), ), ); } @@ -135,7 +146,7 @@ export default async function initPlugins({ const pluginRequire = createRequire(context.siteConfigPath); const pluginConfigsNormalized = await normalizePluginConfigs( pluginConfigs, - pluginRequire, + context.siteConfigPath, ); async function doGetPluginVersion( @@ -206,6 +217,7 @@ export default async function initPlugins({ ...pluginInstance, options: pluginOptions, version: pluginVersion, + path: path.dirname(normalizedPluginConfig.entryPath), }; } diff --git a/packages/docusaurus/src/server/themes/index.ts b/packages/docusaurus/src/server/themes/index.ts index b90ec7c497bb..071acd007a40 100644 --- a/packages/docusaurus/src/server/themes/index.ts +++ b/packages/docusaurus/src/server/themes/index.ts @@ -51,7 +51,10 @@ export function loadPluginsThemeAliases({ plugins: LoadedPlugin[]; }): Promise { const pluginThemes: string[] = plugins - .map((plugin) => plugin.getThemePath?.()) + .map( + (plugin) => + plugin.getThemePath && path.resolve(plugin.path, plugin.getThemePath()), + ) .filter((x): x is string => Boolean(x)); const userTheme = path.resolve(siteDir, THEME_PATH); return loadThemeAliases([ThemeFallbackDir, ...pluginThemes], [userTheme]); diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index d626645de784..d68b1a3f8863 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -56,7 +56,7 @@ function getPluginSourceCodeFilePaths(plugin: InitializedPlugin): string[] { codePaths.push(themePath); } - return codePaths; + return codePaths.map((p) => nodePath.resolve(plugin.path, p)); } export async function globSourceCodeFilePaths( diff --git a/website/_dogfooding/dogfooding.config.js b/website/_dogfooding/dogfooding.config.js index 5b58c9aaa91d..5d7cea7670ee 100644 --- a/website/_dogfooding/dogfooding.config.js +++ b/website/_dogfooding/dogfooding.config.js @@ -6,7 +6,6 @@ */ const fs = require('fs'); -const path = require('path'); /** @type {import('@docusaurus/types').PluginConfig[]} */ const dogfoodingThemeInstances = [ @@ -14,8 +13,7 @@ const dogfoodingThemeInstances = [ function swizzleThemeTests() { return { name: 'swizzle-theme-tests', - getThemePath: () => - path.join(__dirname, '_swizzle_theme_tests/src/theme'), + getThemePath: () => './_swizzle_theme_tests/src/theme', }; }, ]; diff --git a/website/docs/api/plugin-methods/extend-infrastructure.md b/website/docs/api/plugin-methods/extend-infrastructure.md index f4a5bc89db3a..1885129b7007 100644 --- a/website/docs/api/plugin-methods/extend-infrastructure.md +++ b/website/docs/api/plugin-methods/extend-infrastructure.md @@ -61,7 +61,7 @@ module.exports = function (context, options) { ## `getThemePath()` {#getThemePath} -Returns the path to the directory where the theme components can be found. When your users call `swizzle`, `getThemePath` is called and its returned path is used to find your theme components. +Returns the path to the directory where the theme components can be found. When your users call `swizzle`, `getThemePath` is called and its returned path is used to find your theme components. Relative paths are resolved against the folder containing the entry point. For example, your `getThemePath` can be: @@ -73,7 +73,7 @@ module.exports = function (context, options) { name: 'my-theme', // highlight-start getThemePath() { - return path.resolve(__dirname, './theme'); + return './theme'; }, // highlight-end }; @@ -103,11 +103,11 @@ module.exports = function (context, options) { // highlight-start getThemePath() { // Where compiled JavaScript output lives - return path.join(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { // Where TypeScript source code lives - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, // highlight-end }; diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 437a83bbb403..7d029dbe2082 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -205,7 +205,7 @@ const config = { 'queryString', ], // swRegister: false, - swCustom: path.resolve(__dirname, 'src/sw.js'), + swCustom: require.resolve('./src/sw.js'), pwaHead: [ { tagName: 'link', diff --git a/website/src/plugins/changelog/index.js b/website/src/plugins/changelog/index.js index 310b1ebc3647..c6116d0c5851 100644 --- a/website/src/plugins/changelog/index.js +++ b/website/src/plugins/changelog/index.js @@ -146,7 +146,7 @@ async function ChangelogPlugin(context, options) { return config; }, getThemePath() { - return path.join(__dirname, './theme'); + return './theme'; }, getPathsToWatch() { // Don't watch the generated dir From da9f38b748ff27ca04cf8816ae4e20f691b393f8 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 17 Mar 2022 00:24:01 +0800 Subject: [PATCH 021/405] refactor(client-redirects): migrate validation to validateOptions lifecycle (#6924) --- .../src/index.d.ts | 4 +- .../normalizePluginOptions.test.ts.snap | 35 ----------- .../__snapshots__/options.test.ts.snap | 7 +++ .../src/__tests__/collectRedirects.test.ts | 5 +- ...ePluginOptions.test.ts => options.test.ts} | 30 ++++++---- .../src/index.ts | 7 +-- .../src/normalizePluginOptions.ts | 59 ------------------- .../src/options.ts | 52 ++++++++++++++++ 8 files changed, 86 insertions(+), 113 deletions(-) delete mode 100644 packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap create mode 100644 packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap rename packages/docusaurus-plugin-client-redirects/src/__tests__/{normalizePluginOptions.test.ts => options.test.ts} (71%) delete mode 100644 packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts create mode 100644 packages/docusaurus-plugin-client-redirects/src/options.ts diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 86c722759c05..31da0335637e 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -154,7 +154,9 @@ declare module '@docusaurus/Link' { readonly href?: string; readonly autoAddBaseUrl?: boolean; - // escape hatch in case broken links check is annoying for a specific link + /** + * escape hatch in case broken links check is annoying for a specific link + */ readonly 'data-noBrokenLinkCheck'?: boolean; }; export default function Link(props: Props): JSX.Element; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap deleted file mode 100644 index e16490337bb1..000000000000 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/normalizePluginOptions.test.ts.snap +++ /dev/null @@ -1,35 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = ` -"Invalid @docusaurus/plugin-client-redirects options: \\"createRedirects\\" must be of type function - { - \\"createRedirects\\": [ - \\"bad\\", - \\"value\\" - ] -}" -`; - -exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = ` -"Invalid @docusaurus/plugin-client-redirects options: \\"fromExtensions[0]\\" contains an invalid value - { - \\"fromExtensions\\": [ - null, - null, - 123, - true - ] -}" -`; - -exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = ` -"Invalid @docusaurus/plugin-client-redirects options: \\"toExtensions[0]\\" contains an invalid value - { - \\"toExtensions\\": [ - null, - null, - 123, - true - ] -}" -`; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap new file mode 100644 index 000000000000..83f23180a018 --- /dev/null +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = `"\\"createRedirects\\" must be of type function"`; + +exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = `"\\"fromExtensions[0]\\" contains an invalid value"`; + +exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = `"\\"toExtensions[0]\\" contains an invalid value"`; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts index 2b7d12f1aa41..3e7f47e5f853 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/collectRedirects.test.ts @@ -7,8 +7,9 @@ import type {PluginContext} from '../types'; import collectRedirects from '../collectRedirects'; -import normalizePluginOptions from '../normalizePluginOptions'; +import {validateOptions} from '../options'; import {removeTrailingSlash} from '@docusaurus/utils'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; import type {Options} from '@docusaurus/plugin-client-redirects'; function createTestPluginContext( @@ -19,7 +20,7 @@ function createTestPluginContext( outDir: '/tmp', baseUrl: 'https://docusaurus.io', relativeRoutesPaths, - options: normalizePluginOptions(options), + options: validateOptions({validate: normalizePluginOptions, options}), }; } diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts similarity index 71% rename from packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts rename to packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts index da727e4ad258..8b7fb9142312 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/normalizePluginOptions.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts @@ -5,32 +5,38 @@ * LICENSE file in the root directory of this source tree. */ -import normalizePluginOptions, { - DefaultPluginOptions, -} from '../normalizePluginOptions'; -import type {CreateRedirectsFnOption} from '@docusaurus/plugin-client-redirects'; +import {validateOptions, DEFAULT_OPTIONS} from '../options'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; +import type { + CreateRedirectsFnOption, + Options, +} from '@docusaurus/plugin-client-redirects'; + +function testValidate(options: Options) { + return validateOptions({validate: normalizePluginOptions, options}); +} describe('normalizePluginOptions', () => { it('returns default options for undefined user options', () => { - expect(normalizePluginOptions()).toEqual(DefaultPluginOptions); + expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS); }); it('returns default options for empty user options', () => { - expect(normalizePluginOptions()).toEqual(DefaultPluginOptions); + expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS); }); it('overrides one default options with valid user options', () => { expect( - normalizePluginOptions({ + testValidate({ toExtensions: ['html'], }), - ).toEqual({...DefaultPluginOptions, toExtensions: ['html']}); + ).toEqual({...DEFAULT_OPTIONS, id: 'default', toExtensions: ['html']}); }); it('overrides all default options with valid user options', () => { const createRedirects: CreateRedirectsFnOption = (_routePath: string) => []; expect( - normalizePluginOptions({ + testValidate({ fromExtensions: ['exe', 'zip'], toExtensions: ['html'], createRedirects, @@ -47,7 +53,7 @@ describe('normalizePluginOptions', () => { it('rejects bad fromExtensions user inputs', () => { expect(() => - normalizePluginOptions({ + testValidate({ fromExtensions: [null, undefined, 123, true] as unknown as string[], }), ).toThrowErrorMatchingSnapshot(); @@ -55,7 +61,7 @@ describe('normalizePluginOptions', () => { it('rejects bad toExtensions user inputs', () => { expect(() => - normalizePluginOptions({ + testValidate({ toExtensions: [null, undefined, 123, true] as unknown as string[], }), ).toThrowErrorMatchingSnapshot(); @@ -63,7 +69,7 @@ describe('normalizePluginOptions', () => { it('rejects bad createRedirects user inputs', () => { expect(() => - normalizePluginOptions({ + testValidate({ createRedirects: ['bad', 'value'] as unknown as CreateRedirectsFnOption, }), ).toThrowErrorMatchingSnapshot(); diff --git a/packages/docusaurus-plugin-client-redirects/src/index.ts b/packages/docusaurus-plugin-client-redirects/src/index.ts index 2fc739c4840a..d5a20c405935 100644 --- a/packages/docusaurus-plugin-client-redirects/src/index.ts +++ b/packages/docusaurus-plugin-client-redirects/src/index.ts @@ -9,7 +9,6 @@ import type {LoadContext, Plugin, Props} from '@docusaurus/types'; import type {PluginContext, RedirectMetadata} from './types'; import type {PluginOptions} from '@docusaurus/plugin-client-redirects'; -import normalizePluginOptions from './normalizePluginOptions'; import collectRedirects from './collectRedirects'; import writeRedirectFiles, { toRedirectFilesMetadata, @@ -19,12 +18,10 @@ import {removePrefix, addLeadingSlash} from '@docusaurus/utils'; export default function pluginClientRedirectsPages( context: LoadContext, - opts: PluginOptions, + options: PluginOptions, ): Plugin { const {trailingSlash} = context.siteConfig; - const options = normalizePluginOptions(opts); - return { name: 'docusaurus-plugin-client-redirects', async postBuild(props: Props) { @@ -53,3 +50,5 @@ export default function pluginClientRedirectsPages( }, }; } + +export {validateOptions} from './options'; diff --git a/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts b/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts deleted file mode 100644 index b838746e1efd..000000000000 --- a/packages/docusaurus-plugin-client-redirects/src/normalizePluginOptions.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type { - PluginOptions, - Options as UserPluginOptions, - RedirectOption, -} from '@docusaurus/plugin-client-redirects'; -import {Joi, PathnameSchema} from '@docusaurus/utils-validation'; -import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; - -export const DefaultPluginOptions: PluginOptions = { - id: DEFAULT_PLUGIN_ID, // TODO temporary - fromExtensions: [], - toExtensions: [], - redirects: [], -}; - -const RedirectPluginOptionValidation = Joi.object({ - to: PathnameSchema.required(), - from: Joi.alternatives().try( - PathnameSchema.required(), - Joi.array().items(PathnameSchema.required()), - ), -}); - -const isString = Joi.string().required().not(null); - -const UserOptionsSchema = Joi.object({ - id: Joi.string().optional(), // TODO remove once validation migrated to new system - fromExtensions: Joi.array().items(isString), - toExtensions: Joi.array().items(isString), - redirects: Joi.array().items(RedirectPluginOptionValidation), - createRedirects: Joi.function().arity(1), -}); - -function validateUserOptions(userOptions: UserPluginOptions) { - const {error} = UserOptionsSchema.validate(userOptions, { - abortEarly: true, - allowUnknown: false, - }); - if (error) { - throw new Error( - `Invalid @docusaurus/plugin-client-redirects options: ${error.message} - ${JSON.stringify(userOptions, null, 2)}`, - ); - } -} - -export default function normalizePluginOptions( - userPluginOptions: UserPluginOptions = {}, -): PluginOptions { - validateUserOptions(userPluginOptions); - return {...DefaultPluginOptions, ...userPluginOptions}; -} diff --git a/packages/docusaurus-plugin-client-redirects/src/options.ts b/packages/docusaurus-plugin-client-redirects/src/options.ts new file mode 100644 index 000000000000..301c1d640dbc --- /dev/null +++ b/packages/docusaurus-plugin-client-redirects/src/options.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type { + PluginOptions, + RedirectOption, +} from '@docusaurus/plugin-client-redirects'; +import type { + OptionValidationContext, + ValidationResult, +} from '@docusaurus/types'; +import {Joi, PathnameSchema} from '@docusaurus/utils-validation'; + +export const DEFAULT_OPTIONS: Partial = { + fromExtensions: [], + toExtensions: [], + redirects: [], +}; + +const RedirectPluginOptionValidation = Joi.object({ + to: PathnameSchema.required(), + from: Joi.alternatives().try( + PathnameSchema.required(), + Joi.array().items(PathnameSchema.required()), + ), +}); + +const isString = Joi.string().required().not(null); + +const UserOptionsSchema = Joi.object({ + fromExtensions: Joi.array() + .items(isString) + .default(DEFAULT_OPTIONS.fromExtensions), + toExtensions: Joi.array() + .items(isString) + .default(DEFAULT_OPTIONS.toExtensions), + redirects: Joi.array() + .items(RedirectPluginOptionValidation) + .default(DEFAULT_OPTIONS.redirects), + createRedirects: Joi.function().arity(1), +}).default(DEFAULT_OPTIONS); + +export function validateOptions({ + validate, + options: userOptions, +}: OptionValidationContext): ValidationResult { + return validate(UserOptionsSchema, userOptions); +} From 284649c7c851bb0a228cc22bbb8811eb91e5c80f Mon Sep 17 00:00:00 2001 From: Kayce Basques Date: Wed, 16 Mar 2022 16:54:18 -0700 Subject: [PATCH 022/405] docs: clarify the usage of slug (#6926) * Clarify the usage of slug As a new user it was unclear whether setting `slug` would change the URL relative to the root directory or relative to the docs directory. The example I added should make that clear without needing to test out the functionality in a Docusaurus instance (which is what I had to do). * editorial changes Co-authored-by: Joshua Chen --- website/docs/guides/docs/docs-introduction.md | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/website/docs/guides/docs/docs-introduction.md b/website/docs/guides/docs/docs-introduction.md index 426186a72bbd..02e9d76b45cd 100644 --- a/website/docs/guides/docs/docs-introduction.md +++ b/website/docs/guides/docs/docs-introduction.md @@ -37,17 +37,31 @@ id: part1 Lorem ipsum ``` -If you want more control over the last part of the document URL, it is possible to add a `slug` (defaults to the `id`). +### Customizing doc URLs {#customizing-doc-urls} + +By default, a document's URL location is its file path relative to the `docs` folder. Use the `slug` front matter to change a document's URL. + +For example, suppose your site structure looks like this: + +```bash +website # Root directory of your site +└── docs + └── guide + └── hello.md +``` + +By default `hello.md` will be available at `/docs/guide/hello`. You can change its URL location to `/docs/bonjour`: ```md --- -id: part1 -slug: part1.html +slug: /bonjour --- Lorem ipsum ``` +`slug` will be appended to the doc plugin's `routeBasePath`, which is `/docs` by default. See [Docs-only mode](#docs-only-mode) for how to remove the `/docs` part from the URL. + :::note It is possible to use: From bfe7ca6237b13ab9f4fde30fd4e54af24ad019f0 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 17 Mar 2022 12:05:23 +0800 Subject: [PATCH 023/405] chore(pwa, sitemap, client-redirects, ideal-image): JSDoc for types (#6928) * chore(pwa, sitemap, client-redirects, ideal-image): JSDoc for types * fix --- .../src/__tests__/options.test.ts | 18 ++-- .../src/createRedirectPageContent.ts | 8 +- .../src/plugin-client-redirects.d.ts | 19 ++-- .../src/types.ts | 18 ++-- .../src/plugin-ideal-image.d.ts | 15 ++-- .../src/theme/IdealImage/index.tsx | 8 +- packages/docusaurus-plugin-pwa/src/index.ts | 2 +- .../docusaurus-plugin-pwa/src/plugin-pwa.d.ts | 88 ++++++++++++++++--- .../docusaurus-plugin-sitemap/src/index.ts | 2 +- .../src/plugin-sitemap.d.ts | 2 + .../src/pluginOptionSchema.ts | 1 - 11 files changed, 129 insertions(+), 52 deletions(-) diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts index 8b7fb9142312..b5d9e24c367f 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts @@ -7,10 +7,7 @@ import {validateOptions, DEFAULT_OPTIONS} from '../options'; import {normalizePluginOptions} from '@docusaurus/utils-validation'; -import type { - CreateRedirectsFnOption, - Options, -} from '@docusaurus/plugin-client-redirects'; +import type {Options} from '@docusaurus/plugin-client-redirects'; function testValidate(options: Options) { return validateOptions({validate: normalizePluginOptions, options}); @@ -34,7 +31,9 @@ describe('normalizePluginOptions', () => { }); it('overrides all default options with valid user options', () => { - const createRedirects: CreateRedirectsFnOption = (_routePath: string) => []; + const createRedirects: Options['createRedirects'] = ( + _routePath: string, + ) => []; expect( testValidate({ fromExtensions: ['exe', 'zip'], @@ -54,7 +53,8 @@ describe('normalizePluginOptions', () => { it('rejects bad fromExtensions user inputs', () => { expect(() => testValidate({ - fromExtensions: [null, undefined, 123, true] as unknown as string[], + // @ts-expect-error: for test + fromExtensions: [null, undefined, 123, true], }), ).toThrowErrorMatchingSnapshot(); }); @@ -62,7 +62,8 @@ describe('normalizePluginOptions', () => { it('rejects bad toExtensions user inputs', () => { expect(() => testValidate({ - toExtensions: [null, undefined, 123, true] as unknown as string[], + // @ts-expect-error: for test + toExtensions: [null, undefined, 123, true], }), ).toThrowErrorMatchingSnapshot(); }); @@ -70,7 +71,8 @@ describe('normalizePluginOptions', () => { it('rejects bad createRedirects user inputs', () => { expect(() => testValidate({ - createRedirects: ['bad', 'value'] as unknown as CreateRedirectsFnOption, + // @ts-expect-error: for test + createRedirects: ['bad', 'value'], }), ).toThrowErrorMatchingSnapshot(); }); diff --git a/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts b/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts index 68d2c5a40dfa..557ea9c3816c 100644 --- a/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts +++ b/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts @@ -9,10 +9,6 @@ import * as eta from 'eta'; import redirectPageTemplate from './templates/redirectPage.template.html'; import _ from 'lodash'; -type CreateRedirectPageOptions = { - toUrl: string; -}; - const getCompiledRedirectPageTemplate = _.memoize(() => eta.compile(redirectPageTemplate.trim()), ); @@ -24,7 +20,9 @@ function renderRedirectPageTemplate(data: Record) { export default function createRedirectPageContent({ toUrl, -}: CreateRedirectPageOptions): string { +}: { + toUrl: string; +}): string { return renderRedirectPageTemplate({ toUrl: encodeURI(toUrl), }); diff --git a/packages/docusaurus-plugin-client-redirects/src/plugin-client-redirects.d.ts b/packages/docusaurus-plugin-client-redirects/src/plugin-client-redirects.d.ts index fb580bae6ad6..a943eace5e8f 100644 --- a/packages/docusaurus-plugin-client-redirects/src/plugin-client-redirects.d.ts +++ b/packages/docusaurus-plugin-client-redirects/src/plugin-client-redirects.d.ts @@ -10,18 +10,23 @@ export type RedirectOption = { from: string | string[]; }; -// For a given existing route path, -// return all the paths from which we should redirect from -export type CreateRedirectsFnOption = ( - path: string, -) => string[] | string | null | undefined; - export type PluginOptions = { + /** Plugin ID. */ id: string; + /** The extensions to be removed from the route after redirecting. */ fromExtensions: string[]; + /** The extensions to be appended to the route after redirecting. */ toExtensions: string[]; + /** The list of redirect rules, each one with multiple `from`s → one `to`. */ redirects: RedirectOption[]; - createRedirects?: CreateRedirectsFnOption; + /** + * A callback to create a redirect rule. + * @returns All the paths from which we should redirect to `path` + */ + createRedirects?: ( + /** An existing Docusaurus route path */ + path: string, + ) => string[] | string | null | undefined; }; export type Options = Partial; diff --git a/packages/docusaurus-plugin-client-redirects/src/types.ts b/packages/docusaurus-plugin-client-redirects/src/types.ts index 2affd0c6c5d3..ca0f61a6fb01 100644 --- a/packages/docusaurus-plugin-client-redirects/src/types.ts +++ b/packages/docusaurus-plugin-client-redirects/src/types.ts @@ -8,16 +8,22 @@ import type {Props} from '@docusaurus/types'; import type {PluginOptions} from '@docusaurus/plugin-client-redirects'; -// The minimal infos the plugin needs to work +/** + * The minimal infos the plugin needs to work + */ export type PluginContext = Pick & { options: PluginOptions; relativeRoutesPaths: string[]; }; -// In-memory representation of redirects we want: easier to test -// /!\ easy to be confused: "from" is the new page we should create, -// that redirects to "to": the existing Docusaurus page +/** + * In-memory representation of redirects we want: easier to test + * /!\ easy to be confused: "from" is the new page we should create, + * that redirects to "to": the existing Docusaurus page + */ export type RedirectMetadata = { - from: string; // pathname - to: string; // pathname + /** Pathname of the new page we should create */ + from: string; + /** Pathname of an existing Docusaurus page */ + to: string; }; diff --git a/packages/docusaurus-plugin-ideal-image/src/plugin-ideal-image.d.ts b/packages/docusaurus-plugin-ideal-image/src/plugin-ideal-image.d.ts index 1435d0b1d4ce..0c151f88cbf9 100644 --- a/packages/docusaurus-plugin-ideal-image/src/plugin-ideal-image.d.ts +++ b/packages/docusaurus-plugin-ideal-image/src/plugin-ideal-image.d.ts @@ -14,8 +14,7 @@ declare module '@docusaurus/plugin-ideal-image' { /** * Specify all widths you want to use; if a specified size exceeds the * original image's width, the latter will be used (i.e. images won't be - * scaled up). You may also declare a default sizes array in the loader - * options in your webpack.config.js. + * scaled up). */ sizes?: number[]; /** @@ -25,16 +24,17 @@ declare module '@docusaurus/plugin-ideal-image' { */ size?: number; /** - * As an alternative to manually specifying sizes, you can specify min, max - * and steps, and the sizes will be generated for you. + * As an alternative to manually specifying `sizes`, you can specify `min`, + * `max` and `steps`, and the `sizes` will be generated for you. */ min?: number; /** - * See min above + * @see {@link PluginOptions.min} */ max?: number; /** - * Configure the number of images generated between min and max (inclusive) + * Configure the number of images generated between `min` and `max` + * (inclusive) */ steps?: number; /** @@ -42,7 +42,8 @@ declare module '@docusaurus/plugin-ideal-image' { */ quality?: number; /** - * Just use regular images in dev mode + * You can test ideal image behavior in dev mode by setting this to `false`. + * Tip: use network throttling in your browser to simulate slow networks. */ disableInDev?: boolean; }; diff --git a/packages/docusaurus-plugin-ideal-image/src/theme/IdealImage/index.tsx b/packages/docusaurus-plugin-ideal-image/src/theme/IdealImage/index.tsx index 11f7da58f8c8..6bc259b2b1ba 100644 --- a/packages/docusaurus-plugin-ideal-image/src/theme/IdealImage/index.tsx +++ b/packages/docusaurus-plugin-ideal-image/src/theme/IdealImage/index.tsx @@ -15,7 +15,7 @@ import {translate} from '@docusaurus/Translate'; import type {Props} from '@theme/IdealImage'; // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/helpers.js#L59-L65 -const bytesToSize = (bytes: number) => { +function bytesToSize(bytes: number) { const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; if (bytes === 0) { return 'n/a'; @@ -25,10 +25,10 @@ const bytesToSize = (bytes: number) => { return `${bytes} ${sizes[scale]}`; } return `${(bytes / 1024 ** scale).toFixed(1)} ${sizes[scale]}`; -}; +} // Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/IdealImage/index.js#L43-L75 -const getMessage = (icon: IconKey, state: State) => { +function getMessage(icon: IconKey, state: State) { switch (icon) { case 'noicon': case 'loaded': @@ -78,7 +78,7 @@ const getMessage = (icon: IconKey, state: State) => { default: throw new Error(`Wrong icon: ${icon}`); } -}; +} export default function IdealImage(props: Props): JSX.Element { const {alt, className, img} = props; diff --git a/packages/docusaurus-plugin-pwa/src/index.ts b/packages/docusaurus-plugin-pwa/src/index.ts index e43af904e070..044f05c5492d 100644 --- a/packages/docusaurus-plugin-pwa/src/index.ts +++ b/packages/docusaurus-plugin-pwa/src/index.ts @@ -71,7 +71,7 @@ export default function pluginPWA( }, getClientModules() { - return isProd ? [swRegister] : []; + return isProd && swRegister ? [swRegister] : []; }, getDefaultCodeTranslationMessages() { diff --git a/packages/docusaurus-plugin-pwa/src/plugin-pwa.d.ts b/packages/docusaurus-plugin-pwa/src/plugin-pwa.d.ts index 94fe49d3503c..1e0128331039 100644 --- a/packages/docusaurus-plugin-pwa/src/plugin-pwa.d.ts +++ b/packages/docusaurus-plugin-pwa/src/plugin-pwa.d.ts @@ -6,26 +6,90 @@ */ declare module '@docusaurus/plugin-pwa' { - export type pwaHead = { - tagName: string; - href?: string; - content?: string; - [attributeName: string]: string | boolean; - }; + import type {InjectManifestOptions} from 'workbox-build'; export type PluginOptions = { + /** + * Turn debug mode on: + * + * - Workbox logs + * - Additional Docusaurus logs + * - Unoptimized SW file output + * - Source maps + */ debug?: boolean; - offlineModeActivationStrategies; - injectManifestConfig; - reloadPopup; - pwaHead: pwaHead[]; - swCustom; - swRegister; + /** + * Strategies used to turn the offline mode on: + * + * - `appInstalled`: activates for users having installed the site as an app + * (not 100% reliable) + * - `standalone`: activates for users running the app as standalone (often + * the case once a PWA is installed) + * - `queryString`: activates if queryString contains `offlineMode=true` + * (convenient for PWA debugging) + * - `mobile`: activates for mobile users (width <= 940px) + * - `saveData`: activates for users with `navigator.connection.saveData === + * true` + * - `always`: activates for all users + */ + offlineModeActivationStrategies: ( + | 'appInstalled' + | 'queryString' + | 'standalone' + | 'mobile' + | 'saveData' + | 'always' + )[]; + /** + * Workbox options to pass to `workbox.injectManifest()`. This gives you + * control over which assets will be precached, and be available offline. + * @see https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.injectManifest + */ + injectManifestConfig: InjectManifestOptions; + /** + * Module path to reload popup component. This popup is rendered when a new + * service worker is waiting to be installed, and we suggest a reload to + * the user. + * + * Passing `false` will disable the popup, but this is not recommended: + * users won't have a way to get up-to-date content. + * @see {@link @theme/PwaReloadPopup} + */ + reloadPopup: string | false; + /** + * Array of objects containing `tagName` and key-value pairs for attributes + * to inject into the `` tag. Technically you can inject any head tag + * through this, but it's ideally used for tags to make your site PWA- + * compliant. + */ + pwaHead: { + tagName: string; + href?: string; + content?: string; + [attributeName: string]: string | boolean; + }[]; + /** + * Useful for additional Workbox rules. You can do whatever a service worker + * can do here, and use the full power of workbox libraries. The code is + * transpiled, so you can use modern ES6+ syntax here. + */ + swCustom?: string; + /** + * Adds an entry before the Docusaurus app so that registration can happen + * before the app runs. The default `registerSW.js` file is enough for + * simple registration. Passing `false` will disable registration entirely. + */ + swRegister: string | false; }; } declare module '@theme/PwaReloadPopup' { export interface Props { + /** + * The popup should call this callback when the `reload` button is clicked. + * This will tell the service worker to install the waiting service worker + * and reload the page. + */ readonly onReload: () => void; } export default function PwaReloadPopup(props: Props): JSX.Element; diff --git a/packages/docusaurus-plugin-sitemap/src/index.ts b/packages/docusaurus-plugin-sitemap/src/index.ts index 7533713acadf..e394a9a19291 100644 --- a/packages/docusaurus-plugin-sitemap/src/index.ts +++ b/packages/docusaurus-plugin-sitemap/src/index.ts @@ -19,7 +19,7 @@ import type { import {PluginOptionSchema} from './pluginOptionSchema'; export default function pluginSitemap( - _context: LoadContext, + context: LoadContext, options: Options, ): Plugin { return { diff --git a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts index 0c9b4a826c95..7706a0cdd256 100644 --- a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts +++ b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts @@ -8,6 +8,8 @@ import type {EnumChangefreq} from 'sitemap'; export type Options = { + /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ changefreq?: EnumChangefreq; + /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ priority?: number; }; diff --git a/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts index 77df104d6c27..7ead9b2e8031 100644 --- a/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts @@ -15,7 +15,6 @@ export const DEFAULT_OPTIONS: Required = { }; export const PluginOptionSchema = Joi.object({ - // TODO temporary (@alpha-71) cacheTime: Joi.forbidden().messages({ 'any.unknown': 'Option `cacheTime` in sitemap config is deprecated. Please remove it.', From f70ddf7e69976338a6e2a5c993b2d9a9e9c567fa Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 17 Mar 2022 13:38:28 +0800 Subject: [PATCH 024/405] refactor(core): minor routes type improvement (#6929) --- packages/docusaurus-types/src/index.d.ts | 4 +-- packages/docusaurus/src/server/brokenLinks.ts | 26 ++++++---------- packages/docusaurus/src/server/routes.ts | 31 ++++++------------- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index cead1c6ed2d6..7d86042aeea4 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -12,6 +12,7 @@ import type {ParsedUrlQueryInput} from 'querystring'; import type Joi from 'joi'; import type {Overwrite, DeepPartial} from 'utility-types'; import type {Location} from 'history'; +import type Loadable from 'react-loadable'; export type ReportingSeverity = 'ignore' | 'log' | 'warn' | 'error' | 'throw'; @@ -378,8 +379,7 @@ export interface RouteConfig { export type Route = { readonly path: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - readonly component: any; + readonly component: ReturnType; readonly exact?: boolean; readonly routes?: Route[]; }; diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts index 8407205b1965..a085135a98da 100644 --- a/packages/docusaurus/src/server/brokenLinks.ts +++ b/packages/docusaurus/src/server/brokenLinks.ts @@ -5,10 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - matchRoutes, - type RouteConfig as RRRouteConfig, -} from 'react-router-config'; +import {matchRoutes} from 'react-router-config'; import fs from 'fs-extra'; import _ from 'lodash'; import type {RouteConfig, ReportingSeverity} from '@docusaurus/types'; @@ -23,11 +20,6 @@ import path from 'path'; import combinePromises from 'combine-promises'; import logger from '@docusaurus/logger'; -function toReactRouterRoutes(routes: RouteConfig[]): RRRouteConfig[] { - // @ts-expect-error: types incompatible??? - return routes as RRRouteConfig[]; -} - type BrokenLink = { link: string; resolvedLink: string; @@ -47,10 +39,9 @@ function getPageBrokenLinks({ pageLinks: string[]; routes: RouteConfig[]; }): BrokenLink[] { - // ReactRouter is able to support links like ./../somePath - // but matchRoutes does not do this resolving internally - // we must resolve the links before using matchRoutes - // resolvePathname is used internally by ReactRouter + // ReactRouter is able to support links like ./../somePath but `matchRoutes` + // does not do this resolution internally. We must resolve the links before + // using `matchRoutes`. `resolvePathname` is used internally by React Router function resolveLink(link: string) { const resolvedLink = resolvePathname(onlyPathname(link), pagePath); return {link, resolvedLink}; @@ -58,7 +49,10 @@ function getPageBrokenLinks({ function isBrokenLink(link: string) { const matchedRoutes = [link, decodeURI(link)] - .map((l) => matchRoutes(toReactRouterRoutes(routes), l)) + // @ts-expect-error: React router types RouteConfig with an actual React + // component, but we load route components with string paths. + // We don't actually access component here, so it's fine. + .map((l) => matchRoutes(routes, l)) .reduce((prev, cur) => prev.concat(cur)); return matchedRoutes.length === 0; } @@ -69,8 +63,8 @@ function getPageBrokenLinks({ /** * The route defs can be recursive, and have a parent match-all route. We don't * want to match broken links like /docs/brokenLink against /docs/*. For this - * reason, we only consider the "final routes", that do not have subroutes. - * We also need to remove the match all 404 route + * reason, we only consider the "final routes" that do not have subroutes. + * We also need to remove the match-all 404 route */ function filterIntermediateRoutes(routesInput: RouteConfig[]): RouteConfig[] { const routesWithout404 = routesInput.filter((route) => route.path !== '*'); diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index c2105c07ce84..ba5508bfd97c 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -119,28 +119,18 @@ function getModulePath(target: Module): string { return `${target.path}${queryStr}`; } -type LoadedRoutes = { - registry: { - [chunkName: string]: ChunkRegistry; - }; - routesConfig: string; - routesChunkNames: { - [routePath: string]: ChunkNames; - }; - routesPaths: string[]; -}; - export default async function loadRoutes( pluginsRouteConfigs: RouteConfig[], baseUrl: string, -): Promise { - const registry: { - [chunkName: string]: ChunkRegistry; - } = {}; +): Promise<{ + registry: {[chunkName: string]: ChunkRegistry}; + routesConfig: string; + routesChunkNames: {[routePath: string]: ChunkNames}; + routesPaths: string[]; +}> { + const registry: {[chunkName: string]: ChunkRegistry} = {}; const routesPaths: string[] = [normalizeUrl([baseUrl, '404.html'])]; - const routesChunkNames: { - [routePath: string]: ChunkNames; - } = {}; + const routesChunkNames: {[routePath: string]: ChunkNames} = {}; // This is the higher level overview of route code generation. function generateRouteCode(routeConfig: RouteConfig): string { @@ -254,10 +244,7 @@ function genRouteChunkNames( modulePath, )}')`; - registry[chunkName] = { - loader, - modulePath, - }; + registry[chunkName] = {loader, modulePath}; return chunkName; } From cc0bceab9c1678303f6237f5526753edc1b12fc3 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 17 Mar 2022 17:59:41 +0800 Subject: [PATCH 025/405] chore: tighten ESLint config (#6931) * chore: tighten ESLint config * more refactor * refactor push * fix --- .eslintrc.js | 27 ++++--- __tests__/validate-package-json.test.ts | 15 +++- .../functions/codesandbox.ts | 2 +- admin/new.docusaurus.io/functions/index.ts | 2 +- .../new.docusaurus.io/functions/stackblitz.ts | 2 +- admin/scripts/generateExamples.mjs | 2 - admin/scripts/image-resize.mjs | 2 - jest/snapshotPathNormalizer.ts | 1 - packages/docusaurus-mdx-loader/src/index.ts | 2 +- .../src/remark/toc/index.ts | 4 +- .../src/remark/unwrapMdxCodeBlocks/index.ts | 2 +- packages/docusaurus-migrate/src/index.ts | 2 +- .../src/__tests__/options.test.ts | 4 +- .../src/options.ts | 2 +- .../src/feed.ts | 2 +- .../src/markdownLoader.ts | 2 +- .../src/__tests__/index.test.ts | 4 +- .../src/markdown/index.ts | 4 +- .../src/translations.ts | 38 +++++----- .../src/markdownLoader.ts | 2 +- .../src/theme/DebugContent/index.tsx | 6 +- .../docusaurus-plugin-pwa/src/registerSw.js | 2 +- packages/docusaurus-plugin-pwa/src/sw.js | 2 +- .../src/theme-classic.d.ts | 9 +-- .../src/theme/DocSidebarItem/index.tsx | 4 +- .../src/theme/Footer/Copyright/index.tsx | 4 +- .../theme/Footer/Links/MultiColumn/index.tsx | 4 +- .../src/theme/Footer/Links/Simple/index.tsx | 4 +- .../theme/NavbarItem/DefaultNavbarItem.tsx | 4 +- .../theme/NavbarItem/DropdownNavbarItem.tsx | 2 +- packages/docusaurus-theme-common/src/index.ts | 55 +++++++------- .../src/utils/docsUtils.tsx | 8 +- .../src/utils/generalUtils.ts | 2 +- .../src/utils/tagsUtils.ts | 6 +- .../src/utils/useTOCHighlight.ts | 6 +- .../src/utils.ts | 1 - .../docusaurus-theme-translations/update.mjs | 1 - .../docusaurus-utils/src/dataFileUtils.ts | 1 - .../docusaurus-utils/src/markdownUtils.ts | 1 - packages/docusaurus-utils/src/urlUtils.ts | 1 - packages/docusaurus/bin/beforeCli.mjs | 3 +- .../src/client/exports/ComponentCreator.tsx | 5 +- .../docusaurus/src/commands/swizzle/tables.ts | 75 ++++++++++--------- .../server/__tests__/configValidation.test.ts | 14 +--- packages/docusaurus/src/server/brokenLinks.ts | 6 +- packages/docusaurus/src/server/index.ts | 8 +- .../translations/translationsExtractor.ts | 5 +- .../__tests__/index.test.js | 4 +- .../_dogfooding/testSwizzleThemeClassic.mjs | 1 - website/src/data/__tests__/user.test.ts | 1 - website/src/plugins/changelog/index.js | 1 - .../changelog/theme/ChangelogItem/index.tsx | 1 - website/src/utils/prismDark.mjs | 1 - website/src/utils/prismLight.mjs | 1 - 54 files changed, 177 insertions(+), 193 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d0be97ad6995..64f77872d6a1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -62,6 +62,7 @@ module.exports = { 'no-await-in-loop': OFF, 'no-case-declarations': WARNING, 'no-console': OFF, + 'no-continue': OFF, 'no-control-regex': WARNING, 'no-else-return': [WARNING, {allowElseIf: true}], 'no-empty': [WARNING, {allowEmptyCatch: true}], @@ -275,6 +276,7 @@ module.exports = { }, ], '@typescript-eslint/no-inferrable-types': OFF, + '@typescript-eslint/no-namespace': [WARNING, {allowDeclarations: true}], 'no-use-before-define': OFF, '@typescript-eslint/no-use-before-define': [ ERROR, @@ -286,14 +288,11 @@ module.exports = { 'no-shadow': OFF, '@typescript-eslint/no-shadow': ERROR, 'no-unused-vars': OFF, - '@typescript-eslint/no-unused-vars': [ - ERROR, - { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - ignoreRestSiblings: true, - }, - ], + // We don't provide any escape hatches for this rule. Rest siblings and + // function placeholder params are always ignored, and any other unused + // locals must be justified with a disable comment. + '@typescript-eslint/no-unused-vars': [ERROR, {ignoreRestSiblings: true}], + '@typescript-eslint/prefer-optional-chain': ERROR, }, overrides: [ { @@ -340,7 +339,17 @@ module.exports = { }, }, { - files: ['*.test.ts', '*.test.tsx'], + // Internal files where extraneous deps don't matter much at long as + // they run + files: [ + '*.test.ts', + '*.test.tsx', + 'admin/**', + 'jest/**', + 'website/**', + 'packages/docusaurus-theme-translations/update.mjs', + 'packages/docusaurus-theme-translations/src/utils.ts', + ], rules: { 'import/no-extraneous-dependencies': OFF, }, diff --git a/__tests__/validate-package-json.test.ts b/__tests__/validate-package-json.test.ts index b4bdd9a8b98c..5f3d605d5a35 100644 --- a/__tests__/validate-package-json.test.ts +++ b/__tests__/validate-package-json.test.ts @@ -10,8 +10,19 @@ import fs from 'fs-extra'; type PackageJsonFile = { file: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - content: any; + content: { + name?: string; + private?: boolean; + version?: string; + repository?: { + type?: string; + url?: string; + directory?: string; + }; + publishConfig?: { + access?: string; + }; + }; }; async function getPackagesJsonFiles(): Promise { diff --git a/admin/new.docusaurus.io/functions/codesandbox.ts b/admin/new.docusaurus.io/functions/codesandbox.ts index 9cb6c9b41e57..365ac26911f4 100644 --- a/admin/new.docusaurus.io/functions/codesandbox.ts +++ b/admin/new.docusaurus.io/functions/codesandbox.ts @@ -9,6 +9,6 @@ import type {Handler} from '@netlify/functions'; import {createPlaygroundResponse} from '../functionUtils/playgroundUtils'; -export const handler: Handler = async function handler(_event, _context) { +export const handler: Handler = async function handler() { return createPlaygroundResponse('codesandbox'); }; diff --git a/admin/new.docusaurus.io/functions/index.ts b/admin/new.docusaurus.io/functions/index.ts index d9bca91c359e..a137fecb41c3 100644 --- a/admin/new.docusaurus.io/functions/index.ts +++ b/admin/new.docusaurus.io/functions/index.ts @@ -13,7 +13,7 @@ import { createPlaygroundDocumentationResponse, } from '../functionUtils/playgroundUtils'; -export const handler: Handler = async (event, _context) => { +export const handler: Handler = async (event) => { const playgroundName = readPlaygroundName(event); return playgroundName ? createPlaygroundResponse(playgroundName) diff --git a/admin/new.docusaurus.io/functions/stackblitz.ts b/admin/new.docusaurus.io/functions/stackblitz.ts index 28bf7bb11fa0..e7762f20dce0 100644 --- a/admin/new.docusaurus.io/functions/stackblitz.ts +++ b/admin/new.docusaurus.io/functions/stackblitz.ts @@ -9,6 +9,6 @@ import type {Handler} from '@netlify/functions'; import {createPlaygroundResponse} from '../functionUtils/playgroundUtils'; -export const handler: Handler = async function handler(_event, _context) { +export const handler: Handler = async function handler() { return createPlaygroundResponse('stackblitz'); }; diff --git a/admin/scripts/generateExamples.mjs b/admin/scripts/generateExamples.mjs index ae1bd3e9dfb8..748640ae0dcb 100644 --- a/admin/scripts/generateExamples.mjs +++ b/admin/scripts/generateExamples.mjs @@ -5,8 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -/* eslint-disable import/no-extraneous-dependencies */ - import fs from 'fs-extra'; import shell from 'shelljs'; diff --git a/admin/scripts/image-resize.mjs b/admin/scripts/image-resize.mjs index 294289e74dae..f19b877f1be8 100644 --- a/admin/scripts/image-resize.mjs +++ b/admin/scripts/image-resize.mjs @@ -5,8 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -/* eslint-disable import/no-extraneous-dependencies */ - import sharp from 'sharp'; import fs from 'fs-extra'; import path from 'path'; diff --git a/jest/snapshotPathNormalizer.ts b/jest/snapshotPathNormalizer.ts index f9f69cc90f29..ad642a561ae3 100644 --- a/jest/snapshotPathNormalizer.ts +++ b/jest/snapshotPathNormalizer.ts @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -/* eslint-disable import/no-extraneous-dependencies */ // Forked from https://github.com/tribou/jest-serializer-path/blob/master/lib/index.js // Added some project-specific handlers diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index 4188651a0950..38c97ccc7475 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -162,7 +162,7 @@ export default async function mdxLoader( // MDX partials are MDX files starting with _ or in a folder starting with _ // Partial are not expected to have associated metadata files or front matter - const isMDXPartial = options.isMDXPartial && options.isMDXPartial(filePath); + const isMDXPartial = options.isMDXPartial?.(filePath); if (isMDXPartial && hasFrontMatter) { const errorMessage = `Docusaurus MDX partial files should not contain FrontMatter. Those partial files use the _ prefix as a convention by default, but this is configurable. diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts index 0e25a5a46226..e733d5ab93a4 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts @@ -76,7 +76,7 @@ export default function plugin(options: PluginOptions = {}): Transformer { return (root) => { const headings: TOCItem[] = []; - visit(root, 'heading', (child: Heading, _index, parent) => { + visit(root, 'heading', (child: Heading, index, parent) => { const value = toString(child); // depth:1 headings are titles and not included in the TOC @@ -93,7 +93,7 @@ export default function plugin(options: PluginOptions = {}): Transformer { const {children} = root as Parent; const targetIndex = getOrCreateExistingTargetIndex(children, name); - if (headings && headings.length) { + if (headings.length) { children[targetIndex]!.value = `export const ${name} = ${stringifyObject( headings, )};`; diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts index 82493e58c4cb..07aee3daeb89 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/index.ts @@ -17,7 +17,7 @@ import type {Code, Parent} from 'mdast'; // See https://github.com/facebook/docusaurus/pull/4278 export default function plugin(this: Processor): Transformer { return (root) => { - visit(root, 'code', (node: Code, _index, parent) => { + visit(root, 'code', (node: Code, index, parent) => { if (node.lang === 'mdx-code-block') { const newChildren = (this.parse(node.value) as Parent).children; diff --git a/packages/docusaurus-migrate/src/index.ts b/packages/docusaurus-migrate/src/index.ts index 30c20e826994..bbb05714337c 100644 --- a/packages/docusaurus-migrate/src/index.ts +++ b/packages/docusaurus-migrate/src/index.ts @@ -31,7 +31,7 @@ async function walk(dir: string): Promise { for (const file of list) { const fullPath = `${dir}/${file}`; const stat = await fs.stat(fullPath); - if (stat && stat.isDirectory()) { + if (stat.isDirectory()) { results.push(...(await walk(fullPath))); } else { results.push(fullPath); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts index b5d9e24c367f..a8e57816a396 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts @@ -31,9 +31,7 @@ describe('normalizePluginOptions', () => { }); it('overrides all default options with valid user options', () => { - const createRedirects: Options['createRedirects'] = ( - _routePath: string, - ) => []; + const createRedirects: Options['createRedirects'] = () => []; expect( testValidate({ fromExtensions: ['exe', 'zip'], diff --git a/packages/docusaurus-plugin-client-redirects/src/options.ts b/packages/docusaurus-plugin-client-redirects/src/options.ts index 301c1d640dbc..1e997227c9c7 100644 --- a/packages/docusaurus-plugin-client-redirects/src/options.ts +++ b/packages/docusaurus-plugin-client-redirects/src/options.ts @@ -41,7 +41,7 @@ const UserOptionsSchema = Joi.object({ redirects: Joi.array() .items(RedirectPluginOptionValidation) .default(DEFAULT_OPTIONS.redirects), - createRedirects: Joi.function().arity(1), + createRedirects: Joi.function().maxArity(1), }).default(DEFAULT_OPTIONS); export function validateOptions({ diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index 426f19df8db5..f9053bec3417 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -45,7 +45,7 @@ async function generateBlogFeed({ const {url: siteUrl, baseUrl, title, favicon} = siteConfig; const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]); - const updated = blogPosts[0] && blogPosts[0].metadata.date; + const updated = blogPosts[0]?.metadata.date; const feed = new Feed({ id: blogBaseUrl, diff --git a/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts b/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts index 55d2cda689dc..a5f3d4929889 100644 --- a/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts +++ b/packages/docusaurus-plugin-content-blog/src/markdownLoader.ts @@ -34,5 +34,5 @@ export default function markdownLoader( finalContent = truncate(finalContent, markdownLoaderOptions.truncateMarker); } - return callback && callback(null, finalContent); + return callback?.(null, finalContent); } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 4d62b47700ce..22c46c63725e 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -745,9 +745,7 @@ describe('site with custom sidebar items generator', () => { } it('sidebarItemsGenerator is called with appropriate data', async () => { - const customSidebarItemsGeneratorMock = jest.fn( - async (_arg: SidebarItemsGeneratorOptionArgs) => [], - ); + const customSidebarItemsGeneratorMock = jest.fn(async () => []); const {siteDir} = await loadSite(customSidebarItemsGeneratorMock); const generatorArg: SidebarItemsGeneratorOptionArgs = diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/index.ts b/packages/docusaurus-plugin-content-docs/src/markdown/index.ts index d141bfe3a3c3..5de4aae87f4d 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/index.ts @@ -16,7 +16,5 @@ export default function markdownLoader( const fileString = source; const callback = this.async(); const options = this.getOptions(); - return ( - callback && callback(null, linkify(fileString, this.resourcePath, options)) - ); + return callback?.(null, linkify(fileString, this.resourcePath, options)); } diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index c6929f795ebf..ea902a72764d 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -118,26 +118,24 @@ function getSidebarTranslationFileContent( }, ]); - if (category.link) { - if (category.link.type === 'generated-index') { - if (category.link.title) { - entries.push([ - `sidebar.${sidebarName}.category.${category.label}.link.generated-index.title`, - { - message: category.link.title, - description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`, - }, - ]); - } - if (category.link.description) { - entries.push([ - `sidebar.${sidebarName}.category.${category.label}.link.generated-index.description`, - { - message: category.link.description, - description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`, - }, - ]); - } + if (category.link?.type === 'generated-index') { + if (category.link.title) { + entries.push([ + `sidebar.${sidebarName}.category.${category.label}.link.generated-index.title`, + { + message: category.link.title, + description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`, + }, + ]); + } + if (category.link.description) { + entries.push([ + `sidebar.${sidebarName}.category.${category.label}.link.generated-index.description`, + { + message: category.link.description, + description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`, + }, + ]); } } diff --git a/packages/docusaurus-plugin-content-pages/src/markdownLoader.ts b/packages/docusaurus-plugin-content-pages/src/markdownLoader.ts index f6a82dca6c83..e8ca79a21681 100644 --- a/packages/docusaurus-plugin-content-pages/src/markdownLoader.ts +++ b/packages/docusaurus-plugin-content-pages/src/markdownLoader.ts @@ -18,5 +18,5 @@ export default function markdownLoader( // TODO provide additional md processing here? like interlinking pages? // fileString = linkify(fileString) - return callback && callback(null, fileString); + return callback?.(null, fileString); } diff --git a/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx b/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx index 122ede734cb2..362252d71958 100644 --- a/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx +++ b/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx @@ -39,9 +39,7 @@ function PluginContent({
    {Object.entries(pluginContent) // filter plugin instances with no content - .filter( - ([_pluginId, pluginInstanceContent]) => !!pluginInstanceContent, - ) + .filter(([, pluginInstanceContent]) => !!pluginInstanceContent) .map(([pluginId, pluginInstanceContent]) => ( {Object.entries(allContent) // filter plugins with no content - .filter(([_pluginName, pluginContent]) => + .filter(([, pluginContent]) => Object.values(pluginContent).some( (instanceContent) => !!instanceContent, ), diff --git a/packages/docusaurus-plugin-pwa/src/registerSw.js b/packages/docusaurus-plugin-pwa/src/registerSw.js index ec507d7a1234..36fc55c5a857 100644 --- a/packages/docusaurus-plugin-pwa/src/registerSw.js +++ b/packages/docusaurus-plugin-pwa/src/registerSw.js @@ -79,7 +79,7 @@ function isStandaloneDisplayMode() { const OfflineModeActivationStrategiesImplementations = { always: () => true, mobile: () => window.innerWidth <= MAX_MOBILE_WIDTH, - saveData: () => !!(navigator.connection && navigator.connection.saveData), + saveData: () => !!navigator.connection?.saveData, appInstalled: async () => { const installedEventFired = await isAppInstalledEventFired(); const installedRelatedApps = await isAppInstalledRelatedApps(); diff --git a/packages/docusaurus-plugin-pwa/src/sw.js b/packages/docusaurus-plugin-pwa/src/sw.js index 155228cb38fc..6c30f239616f 100644 --- a/packages/docusaurus-plugin-pwa/src/sw.js +++ b/packages/docusaurus-plugin-pwa/src/sw.js @@ -137,7 +137,7 @@ function getPossibleURLs(url) { }); } - const type = event.data && event.data.type; + const type = event.data?.type; if (type === 'SKIP_WAITING') { self.skipWaiting(); diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index f6973773c9b3..94c48ac9d3bd 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -833,11 +833,8 @@ declare module '@theme/IconExternalLink' { } declare module '@theme/TagsListByLetter' { - export type TagsListItem = Readonly<{ - name: string; - permalink: string; - count: number; - }>; + import type {TagsListItem} from '@docusaurus/theme-common'; + export interface Props { readonly tags: readonly TagsListItem[]; } @@ -853,7 +850,7 @@ declare module '@theme/TagsListInline' { } declare module '@theme/Tag' { - import type {TagsListItem} from '@theme/TagsListByLetter'; + import type {TagsListItem} from '@docusaurus/theme-common'; import type {Optional} from 'utility-types'; export interface Props extends Optional {} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index d78050a920d0..46b57ffd0a7f 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -234,9 +234,7 @@ function DocSidebarItemHtml({ )} key={index} // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{ - __html: value, - }} + dangerouslySetInnerHTML={{__html: value}} /> ); } diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx index eaa98f6ab01f..ab1657d97811 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Copyright/index.tsx @@ -14,9 +14,7 @@ export default function FooterCopyright({copyright}: Props): JSX.Element { className="footer__copyright" // Developer provided the HTML, so assume it's safe. // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{ - __html: copyright, - }} + dangerouslySetInnerHTML={{__html: copyright}} /> ); } diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx index 9616c34912ef..75c8f3a64328 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/MultiColumn/index.tsx @@ -18,9 +18,7 @@ function ColumnLinkItem({item}: {item: ColumnItemType}) { className="footer__item" // Developer provided the HTML, so assume it's safe. // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{ - __html: item.html, - }} + dangerouslySetInnerHTML={{__html: item.html}} /> ) : (
  • diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx index fc0b023f02fd..72fcc0a74a53 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx @@ -19,9 +19,7 @@ function SimpleLinkItem({item}: {item: Props['links'][number]}) { className="footer__link-item" // Developer provided the HTML, so assume it's safe. // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{ - __html: item.html, - }} + dangerouslySetInnerHTML={{__html: item.html}} /> ) : ( diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx index b2c6ff9b6710..2c5044682012 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx @@ -41,7 +41,7 @@ function DefaultNavbarItemDesktop({ function DefaultNavbarItemMobile({ className, - isDropdownItem: _isDropdownItem, + isDropdownItem, ...props }: DesktopOrMobileNavBarItemProps) { return ( @@ -53,7 +53,7 @@ function DefaultNavbarItemMobile({ export default function DefaultNavbarItem({ mobile = false, - position: _position, // Need to destructure position from props so that it doesn't get passed on. + position, // Need to destructure position from props so that it doesn't get passed on. ...props }: Props): JSX.Element { const Comp = mobile ? DefaultNavbarItemMobile : DefaultNavbarItemDesktop; diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx index 08ff0fd57a1c..6403cc8f00bb 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx @@ -124,7 +124,7 @@ function DropdownNavbarItemDesktop({ function DropdownNavbarItemMobile({ items, className, - position: _position, // Need to destructure position from props so that it doesn't get passed on. + position, // Need to destructure position from props so that it doesn't get passed on. ...props }: DesktopOrMobileNavBarItemProps) { const localPathname = useLocalPathname(); diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 50de4ea881f6..96244f043209 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -5,26 +5,25 @@ * LICENSE file in the root directory of this source tree. */ -export {useThemeConfig} from './utils/useThemeConfig'; +export { + useThemeConfig, + type ThemeConfig, + type UserThemeConfig, + type Navbar, + type NavbarItem, + type NavbarLogo, + type MultiColumnFooter, + type SimpleFooter, + type Footer, + type FooterLogo, + type FooterLinkItem, + type ColorModeConfig, +} from './utils/useThemeConfig'; export { DocSidebarItemsExpandedStateProvider, useDocSidebarItemsExpandedState, } from './utils/docSidebarItemsExpandedState'; -export type { - ThemeConfig, - UserThemeConfig, - Navbar, - NavbarItem, - NavbarLogo, - MultiColumnFooter, - SimpleFooter, - Footer, - FooterLogo, - FooterLinkItem, - ColorModeConfig, -} from './utils/useThemeConfig'; - export {createStorageSlot, listStorageKeys} from './utils/storageUtils'; export {useAlternatePageUtils} from './utils/useAlternatePageUtils'; @@ -63,14 +62,14 @@ export {useLocationChange} from './utils/useLocationChange'; export {usePrevious} from './utils/usePrevious'; -export {useCollapsible, Collapsible} from './components/Collapsible'; -export type { - UseCollapsibleConfig, - UseCollapsibleReturns, +export { + useCollapsible, + Collapsible, + type UseCollapsibleConfig, + type UseCollapsibleReturns, } from './components/Collapsible'; -export {default as Details} from './components/Details'; -export type {DetailsProps} from './components/Details'; +export {default as Details, type DetailsProps} from './components/Details'; export { MobileSecondaryMenuProvider, @@ -97,13 +96,19 @@ export { export {useLocalPathname} from './utils/useLocalPathname'; -export {translateTagsPageTitle, listTagsByLetters} from './utils/tagsUtils'; -export type {TagLetterEntry} from './utils/tagsUtils'; +export { + translateTagsPageTitle, + listTagsByLetters, + type TagLetterEntry, + type TagsListItem, +} from './utils/tagsUtils'; export {useHistoryPopHandler} from './utils/historyUtils'; -export {default as useTOCHighlight} from './utils/useTOCHighlight'; -export type {TOCHighlightConfig} from './utils/useTOCHighlight'; +export { + default as useTOCHighlight, + type TOCHighlightConfig, +} from './utils/useTOCHighlight'; export { useFilteredAndTreeifiedTOC, diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index e935af70acd9..7d51244caab3 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -199,14 +199,12 @@ function getBreadcrumbs({ function extract(items: PropSidebar) { for (const item of items) { if ( - item.type === 'category' && - (isSamePath(item.href, pathname) || extract(item.items)) + (item.type === 'category' && + (isSamePath(item.href, pathname) || extract(item.items))) || + (item.type === 'link' && isSamePath(item.href, pathname)) ) { breadcrumbs.push(item); return true; - } else if (item.type === 'link' && isSamePath(item.href, pathname)) { - breadcrumbs.push(item); - return true; } } diff --git a/packages/docusaurus-theme-common/src/utils/generalUtils.ts b/packages/docusaurus-theme-common/src/utils/generalUtils.ts index a6cc51026770..ba98a144bfa4 100644 --- a/packages/docusaurus-theme-common/src/utils/generalUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/generalUtils.ts @@ -10,7 +10,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; export function useTitleFormatter(title?: string | undefined): string { const {siteConfig} = useDocusaurusContext(); const {title: siteTitle, titleDelimiter} = siteConfig; - return title && title.trim().length + return title?.trim().length ? `${title.trim()} ${titleDelimiter} ${siteTitle}` : siteTitle; } diff --git a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts index fa51bd99a975..3c1aee95c015 100644 --- a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts @@ -14,7 +14,11 @@ export const translateTagsPageTitle = (): string => description: 'The title of the tag list page', }); -type TagsListItem = Readonly<{name: string; permalink: string; count: number}>; // TODO remove duplicated type :s +export type TagsListItem = Readonly<{ + name: string; + permalink: string; + count: number; +}>; export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>; diff --git a/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts b/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts index e46d335bf236..56f0b55d2972 100644 --- a/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts +++ b/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts @@ -8,10 +8,8 @@ import {useEffect, useRef} from 'react'; import {useThemeConfig} from './useThemeConfig'; -/* -TODO make the hardcoded theme-classic classnames configurable -(or add them to ThemeClassNames?) - */ +// TODO make the hardcoded theme-classic classnames configurable (or add them +// to ThemeClassNames?) // If the anchor has no height and is just a "marker" in the dom; we'll use the // parent (normally the link text) rect boundaries instead diff --git a/packages/docusaurus-theme-translations/src/utils.ts b/packages/docusaurus-theme-translations/src/utils.ts index 78c666db7a64..beb1370817e1 100644 --- a/packages/docusaurus-theme-translations/src/utils.ts +++ b/packages/docusaurus-theme-translations/src/utils.ts @@ -10,7 +10,6 @@ // update script has ts-check anyways) (b) the test coverage isn't destroyed by // the untested update.mjs file (c) we can ergonomically import the util // functions in the Jest test without using `await import` -/* eslint-disable import/no-extraneous-dependencies */ import path from 'path'; import fs from 'fs-extra'; diff --git a/packages/docusaurus-theme-translations/update.mjs b/packages/docusaurus-theme-translations/update.mjs index 3f5cab96034f..de7a0960ad7f 100644 --- a/packages/docusaurus-theme-translations/update.mjs +++ b/packages/docusaurus-theme-translations/update.mjs @@ -6,7 +6,6 @@ */ // @ts-check -/* eslint-disable import/no-extraneous-dependencies */ import logger from '@docusaurus/logger'; import path from 'path'; diff --git a/packages/docusaurus-utils/src/dataFileUtils.ts b/packages/docusaurus-utils/src/dataFileUtils.ts index 274cace2426f..b71693d06eca 100644 --- a/packages/docusaurus-utils/src/dataFileUtils.ts +++ b/packages/docusaurus-utils/src/dataFileUtils.ts @@ -49,7 +49,6 @@ export async function getDataFileData( const unsafeContent = Yaml.load(contentString); return validate(unsafeContent); } catch (err) { - // TODO replace later by error cause, see https://v8.dev/features/error-cause logger.error`The ${params.fileType} file at path=${filePath} looks invalid.`; throw err; } diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index 8901c26fcde9..7bc7fbafc4f2 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -38,7 +38,6 @@ export function createExcerpt(fileString: string): string | undefined { let inCode = false; let lastCodeFence = ''; - /* eslint-disable no-continue */ for (const fileLine of fileLines) { // Skip empty line. if (!fileLine.trim()) { diff --git a/packages/docusaurus-utils/src/urlUtils.ts b/packages/docusaurus-utils/src/urlUtils.ts index cf6f8aae0fd9..4aa7ebc97f03 100644 --- a/packages/docusaurus-utils/src/urlUtils.ts +++ b/packages/docusaurus-utils/src/urlUtils.ts @@ -50,7 +50,6 @@ export function normalizeUrl(rawUrls: string[]): string { if (i === urls.length - 1 && hasEndingSlash) { resultArray.push('/'); } - // eslint-disable-next-line no-continue continue; } diff --git a/packages/docusaurus/bin/beforeCli.mjs b/packages/docusaurus/bin/beforeCli.mjs index d2524c3814a2..53c5ee9e84d3 100644 --- a/packages/docusaurus/bin/beforeCli.mjs +++ b/packages/docusaurus/bin/beforeCli.mjs @@ -72,8 +72,7 @@ export default async function beforeCli() { * @param {import('update-notifier').UpdateInfo} update */ function ignoreUpdate(update) { - const isCanaryRelease = - update && update.current && update.current.startsWith('0.0.0'); + const isCanaryRelease = update?.current?.startsWith('0.0.0'); return isCanaryRelease; } diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 8dc312b8d92e..1135df89b086 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -52,8 +52,7 @@ export default function ComponentCreator( if (chunkRegistry) { // eslint-disable-next-line prefer-destructuring optsLoader[key] = chunkRegistry[0]; - optsModules.push(chunkRegistry[1]); - optsWebpack.push(chunkRegistry[2]); + optsModules.push(chunkRegistry[1], chunkRegistry[2]); } }); @@ -75,7 +74,7 @@ export default function ComponentCreator( const nonDefaultKeys = Object.keys(loaded[key]).filter( (k) => k !== 'default', ); - if (nonDefaultKeys && nonDefaultKeys.length) { + if (nonDefaultKeys?.length) { nonDefaultKeys.forEach((nonDefaultKey) => { val[keyPath[keyPath.length - 1]!][nonDefaultKey] = loaded[key][nonDefaultKey]; diff --git a/packages/docusaurus/src/commands/swizzle/tables.ts b/packages/docusaurus/src/commands/swizzle/tables.ts index 26c95880fe79..28b9b5188b42 100644 --- a/packages/docusaurus/src/commands/swizzle/tables.ts +++ b/packages/docusaurus/src/commands/swizzle/tables.ts @@ -26,20 +26,20 @@ function statusTable(): string { head: ['Status', 'CLI option', 'Description'], }); - table.push({ - [tableStatusLabel('safe')]: [ - '', - ` + table.push( + { + [tableStatusLabel('safe')]: [ + '', + ` This component is safe to swizzle and was designed for this purpose. The swizzled component is retro-compatible with minor version upgrades. `, - ], - }); - - table.push({ - [tableStatusLabel('unsafe')]: [ - logger.code('--danger'), - ` + ], + }, + { + [tableStatusLabel('unsafe')]: [ + logger.code('--danger'), + ` This component is unsafe to swizzle, but you can still do it! Warning: we may release breaking changes within minor version upgrades. You will have to upgrade your component manually and maintain it over time. @@ -49,17 +49,17 @@ ${logger.green( )}: your customization can't be done in a ${tableStatusLabel('safe')} way? Report it here: https://github.com/facebook/docusaurus/discussions/5468 `, - ], - }); - - table.push({ - [tableStatusLabel('forbidden')]: [ - '', - ` + ], + }, + { + [tableStatusLabel('forbidden')]: [ + '', + ` This component is not meant to be swizzled. `, - ], - }); + ], + }, + ); return table.toString(); } @@ -69,33 +69,34 @@ function actionsTable(): string { head: ['Actions', 'CLI option', 'Description'], }); - table.push({ - [logger.bold('Wrap')]: [ - logger.code('--wrap'), - ` + table.push( + { + [logger.bold('Wrap')]: [ + logger.code('--wrap'), + ` Creates a wrapper around the original theme component. Allows rendering other components before/after the original theme component. ${logger.green('Tip')}: prefer ${logger.code( - '--wrap', - )} whenever possible to reduce the amount of code to maintain. + '--wrap', + )} whenever possible to reduce the amount of code to maintain. `, - ], - }); - - table.push({ - [logger.bold('Eject')]: [ - logger.code('--eject'), - ` + ], + }, + { + [logger.bold('Eject')]: [ + logger.code('--eject'), + ` Ejects the full source code of the original theme component. Allows overriding of the original component entirely with your own UI and logic. ${logger.green('Tip')}: ${logger.code( - '--eject', - )} can be useful for completely redesigning a component. + '--eject', + )} can be useful for completely redesigning a component. `, - ], - }); + ], + }, + ); return table.toString(); } diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index a0cac4dbd9fd..90233c353792 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -168,13 +168,10 @@ describe('normalizeConfig', () => { ['this/should/work', {too: 'yes'}], ], ], - [ - 'should accept function for plugin', - [function plugin(_context, _options) {}], - ], + ['should accept function for plugin', [function plugin() {}]], [ 'should accept [function, object] for plugin', - [[(_context, _options) => {}, {it: 'should work'}]], + [[() => {}, {it: 'should work'}]], ], ])(`%s for the input of: %p`, (_message, plugins) => { expect(() => { @@ -209,13 +206,10 @@ describe('normalizeConfig', () => { ['this/should/work', {too: 'yes'}], ], ], - [ - 'should accept function for theme', - [function theme(_context, _options) {}], - ], + ['should accept function for theme', [function theme() {}]], [ 'should accept [function, object] for theme', - [[function theme(_context, _options) {}, {it: 'should work'}]], + [[function theme() {}, {it: 'should work'}]], ], ])(`%s for the input of: %p`, (_message, themes) => { expect(() => { diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts index a085135a98da..e156599ce61f 100644 --- a/packages/docusaurus/src/server/brokenLinks.ts +++ b/packages/docusaurus/src/server/brokenLinks.ts @@ -190,8 +190,10 @@ async function filterExistingFileLinks({ // -> /outDir/javadoc/index.html const filePathsToTry: string[] = [baseFilePath]; if (!path.extname(baseFilePath)) { - filePathsToTry.push(`${baseFilePath}.html`); - filePathsToTry.push(path.join(baseFilePath, 'index.html')); + filePathsToTry.push( + `${baseFilePath}.html`, + path.join(baseFilePath, 'index.html'), + ); } for (const file of filePathsToTry) { diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 678c5823c6af..a45418ced64c 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -277,7 +277,7 @@ function createMDXFallbackPlugin({ path.resolve(siteDir, dir), ), siteDir, - isMDXPartial: (_filename: string) => true, // External mdx files are always meant to be imported as partials + isMDXPartial: () => true, // External mdx files are always meant to be imported as partials isMDXPartialFrontMatterWarningDisabled: true, // External mdx files might have front matter, let's just disable the warning remarkPlugins: [admonitions], }, @@ -341,8 +341,10 @@ export default ${JSON.stringify(siteConfig, null, 2)}; `, ); - plugins.push(createBootstrapPlugin({siteDir, siteConfig})); - plugins.push(createMDXFallbackPlugin({siteDir, siteConfig})); + plugins.push( + createBootstrapPlugin({siteDir, siteConfig}), + createMDXFallbackPlugin({siteDir, siteConfig}), + ); // Load client modules. const clientModules = loadClientModules(plugins); diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index d68b1a3f8863..0c74a548e4ac 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -308,10 +308,9 @@ ${sourceWarningPart(path.node)}`); ), ) .pop(); - const isJSXText = singleChildren && singleChildren.isJSXText(); + const isJSXText = singleChildren?.isJSXText(); const isJSXExpressionContainer = - singleChildren && - singleChildren.isJSXExpressionContainer() && + singleChildren?.isJSXExpressionContainer() && (singleChildren.get('expression') as NodePath).evaluate().confident; if (isJSXText || isJSXExpressionContainer) { diff --git a/packages/stylelint-copyright/__tests__/index.test.js b/packages/stylelint-copyright/__tests__/index.test.js index 0d6ea8efe5eb..20de7dbae8f2 100644 --- a/packages/stylelint-copyright/__tests__/index.test.js +++ b/packages/stylelint-copyright/__tests__/index.test.js @@ -23,7 +23,7 @@ function testStylelintRule(config, tests) { const checkTestCaseContent = (testCase) => testCase.description || testCase.code || 'no description'; - if (tests.accept && tests.accept.length) { + if (tests.accept?.length) { describe('accept cases', () => { tests.accept.forEach((testCase) => { it(`${checkTestCaseContent(testCase)}`, async () => { @@ -46,7 +46,7 @@ function testStylelintRule(config, tests) { }); } - if (tests.reject && tests.reject.length) { + if (tests.reject?.length) { describe('reject cases', () => { tests.reject.forEach((testCase) => { it(`${checkTestCaseContent(testCase)}`, async () => { diff --git a/website/_dogfooding/testSwizzleThemeClassic.mjs b/website/_dogfooding/testSwizzleThemeClassic.mjs index 44fbe20bc58a..61f1162b9848 100644 --- a/website/_dogfooding/testSwizzleThemeClassic.mjs +++ b/website/_dogfooding/testSwizzleThemeClassic.mjs @@ -120,7 +120,6 @@ for (const componentName of componentNames) { logger.warn( `${componentName} is marked as forbidden for action ${action} => skipping`, ); - // eslint-disable-next-line no-continue continue; } diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index 1efe0f04da03..c0d072119350 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -13,7 +13,6 @@ import path from 'path'; import imageSize from 'image-size'; declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace namespace jest { interface Matchers { toHaveGoodDimensions: () => R; diff --git a/website/src/plugins/changelog/index.js b/website/src/plugins/changelog/index.js index c6116d0c5851..0b686271694f 100644 --- a/website/src/plugins/changelog/index.js +++ b/website/src/plugins/changelog/index.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -/* eslint-disable import/no-extraneous-dependencies */ const path = require('path'); const fs = require('fs-extra'); diff --git a/website/src/plugins/changelog/theme/ChangelogItem/index.tsx b/website/src/plugins/changelog/theme/ChangelogItem/index.tsx index c6245d29cdf5..fea34d46bcad 100644 --- a/website/src/plugins/changelog/theme/ChangelogItem/index.tsx +++ b/website/src/plugins/changelog/theme/ChangelogItem/index.tsx @@ -7,7 +7,6 @@ import React from 'react'; import clsx from 'clsx'; -// eslint-disable-next-line import/no-extraneous-dependencies import {MDXProvider} from '@mdx-js/react'; import Link from '@docusaurus/Link'; import {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; diff --git a/website/src/utils/prismDark.mjs b/website/src/utils/prismDark.mjs index 892f9451256d..2f25fa12a909 100644 --- a/website/src/utils/prismDark.mjs +++ b/website/src/utils/prismDark.mjs @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -// eslint-disable-next-line import/no-extraneous-dependencies import darkTheme from 'prism-react-renderer/themes/vsDark/index.cjs.js'; export default { diff --git a/website/src/utils/prismLight.mjs b/website/src/utils/prismLight.mjs index ac7ee2c78580..c23a4aebc3c9 100644 --- a/website/src/utils/prismLight.mjs +++ b/website/src/utils/prismLight.mjs @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -// eslint-disable-next-line import/no-extraneous-dependencies import lightTheme from 'prism-react-renderer/themes/github/index.cjs.js'; export default { From 9b4ba78f4537e496522e69eb4b478510203e2a90 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Thu, 17 Mar 2022 21:48:04 +0300 Subject: [PATCH 026/405] refactor(theme-classic): little breadcrumbs improvements (#6932) --- .../src/theme/DocBreadcrumbs/index.tsx | 5 +++-- .../theme/DocBreadcrumbs/styles.module.css | 19 ++----------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx index cdb69965ec61..780579774851 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx @@ -24,7 +24,7 @@ function BreadcrumbsItemLink({ children: ReactNode; href?: string; }): JSX.Element { - const className = clsx('breadcrumbs__link', styles.breadcrumbsItemLink); + const className = 'breadcrumbs__link'; return href ? ( {children} @@ -98,7 +98,8 @@ export default function DocBreadcrumbs(): JSX.Element | null { key={idx} active={idx === breadcrumbs.length - 1} index={idx}> - + {item.label} diff --git a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/styles.module.css index db445fbe1150..a400c5d9e622 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/styles.module.css @@ -6,21 +6,6 @@ */ .breadcrumbsContainer { - margin-bottom: 0.4rem; -} - -.breadcrumbsItemLink { - --ifm-breadcrumb-size-multiplier: 0.7 !important; - margin-bottom: 0.4rem; - background: var(--ifm-color-gray-100); -} - -html[data-theme='dark'] .breadcrumbsItemLink { - background-color: var(--ifm-color-gray-900); -} - -@media (min-width: 997px) { - .breadcrumbsItemLink { - --ifm-breadcrumb-size-multiplier: 0.8; - } + --ifm-breadcrumb-size-multiplier: 0.8; + margin-bottom: 0.8rem; } From 8a1421a93871dbdcba046e18ba462c3c5cb7ef1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 18 Mar 2022 10:57:32 +0100 Subject: [PATCH 027/405] feat(core,theme): useRouteContext + HtmlClassNameProvider (#6933) Co-authored-by: Joshua Chen --- .../src/index.d.ts | 6 ++ .../src/plugin-content-docs.d.ts | 1 + .../src/theme/DocItem/index.tsx | 10 +++- .../src/theme/DocPage/index.tsx | 11 ++-- .../src/theme/LayoutProviders/index.tsx | 5 +- packages/docusaurus-theme-common/src/index.ts | 5 ++ .../src/utils/metadataUtilsTemp.tsx | 56 ++++++++++++++++++ packages/docusaurus-types/src/index.d.ts | 18 ++++++ .../src/client/exports/ComponentCreator.tsx | 25 +++++++- .../src/client/exports/useRouteContext.tsx | 20 +++++++ .../docusaurus/src/client/routeContext.tsx | 58 +++++++++++++++++++ .../docusaurus/src/server/plugins/index.ts | 42 ++++++++++---- .../__tests__/__snapshots__/base.test.ts.snap | 2 + project-words.txt | 1 + 14 files changed, 235 insertions(+), 25 deletions(-) create mode 100644 packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx create mode 100644 packages/docusaurus/src/client/exports/useRouteContext.tsx create mode 100644 packages/docusaurus/src/client/routeContext.tsx diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 31da0335637e..d8fbaa1b4b22 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -246,6 +246,12 @@ declare module '@docusaurus/useDocusaurusContext' { export default function useDocusaurusContext(): DocusaurusContext; } +declare module '@docusaurus/useRouteContext' { + import type {PluginRouteContext} from '@docusaurus/types'; + + export default function useRouteContext(): PluginRouteContext; +} + declare module '@docusaurus/useIsBrowser' { export default function useIsBrowser(): boolean; } diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index f14be0f462a8..5d7aa1e04d21 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -191,6 +191,7 @@ declare module '@theme/DocItem' { }; export type Metadata = { + readonly unversionedId?: string; readonly description?: string; readonly title?: string; readonly permalink?: string; diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index bfea8f72f60c..45b8dd52a78f 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -17,7 +17,11 @@ import TOC from '@theme/TOC'; import TOCCollapsible from '@theme/TOCCollapsible'; import Heading from '@theme/Heading'; import styles from './styles.module.css'; -import {ThemeClassNames, useWindowSize} from '@docusaurus/theme-common'; +import { + HtmlClassNameProvider, + ThemeClassNames, + useWindowSize, +} from '@docusaurus/theme-common'; import DocBreadcrumbs from '@theme/DocBreadcrumbs'; import MDXContent from '@theme/MDXContent'; @@ -49,7 +53,7 @@ export default function DocItem(props: Props): JSX.Element { canRenderTOC && (windowSize === 'desktop' || windowSize === 'ssr'); return ( - <> +
    @@ -107,6 +111,6 @@ export default function DocItem(props: Props): JSX.Element {
    )}
  • - + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index b2d2ebbe3251..be8ef387c7ac 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -20,14 +20,15 @@ import {translate} from '@docusaurus/Translate'; import clsx from 'clsx'; import styles from './styles.module.css'; + import { + HtmlClassNameProvider, ThemeClassNames, docVersionSearchTag, DocsSidebarProvider, useDocsSidebar, DocsVersionProvider, } from '@docusaurus/theme-common'; -import Head from '@docusaurus/Head'; type DocPageContentProps = { readonly currentDocRoute: DocumentRoute; @@ -160,11 +161,7 @@ export default function DocPage(props: Props): JSX.Element { : null; return ( - <> - - {/* TODO we should add a core addRoute({htmlClassName}) action */} - - + - + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx b/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx index 5d0d2bf859d0..601bea65eaa5 100644 --- a/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/LayoutProviders/index.tsx @@ -13,6 +13,7 @@ import { DocsPreferredVersionContextProvider, MobileSecondaryMenuProvider, ScrollControllerProvider, + PluginHtmlClassNameProvider, } from '@docusaurus/theme-common'; import type {Props} from '@theme/LayoutProviders'; @@ -24,7 +25,9 @@ export default function LayoutProviders({children}: Props): JSX.Element { - {children} + + {children} + diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 96244f043209..98e215b4d78c 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -135,6 +135,11 @@ export {isRegexpStringMatch} from './utils/regexpUtils'; export {useHomePageRoute} from './utils/routesUtils'; +export { + HtmlClassNameProvider, + PluginHtmlClassNameProvider, +} from './utils/metadataUtilsTemp'; + export {useColorMode, ColorModeProvider} from './utils/colorModeUtils'; export { useTabGroupChoice, diff --git a/packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx b/packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx new file mode 100644 index 000000000000..f55899063b53 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx @@ -0,0 +1,56 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ReactNode} from 'react'; +import Head from '@docusaurus/Head'; +import clsx from 'clsx'; +import useRouteContext from '@docusaurus/useRouteContext'; + +const HtmlClassNameContext = React.createContext(undefined); + +// This wrapper is necessary because Helmet does not "merge" classes +// See https://github.com/staylor/react-helmet-async/issues/161 +export function HtmlClassNameProvider({ + className: classNameProp, + children, +}: { + className: string; + children: ReactNode; +}): JSX.Element { + const classNameContext = React.useContext(HtmlClassNameContext); + const className = clsx(classNameContext, classNameProp); + return ( + + + + + {children} + + ); +} + +function pluginNameToClassName(pluginName: string) { + return `plugin-${pluginName.replace( + /docusaurus-(?:plugin|theme)-(?:content-)?/gi, + '', + )}`; +} + +export function PluginHtmlClassNameProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const routeContext = useRouteContext(); + const nameClass = pluginNameToClassName(routeContext.plugin.name); + const idClass = `plugin-id-${routeContext.plugin.id}`; + return ( + + {children} + + ); +} diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 7d86042aeea4..e5ef1a919b25 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -377,6 +377,24 @@ export interface RouteConfig { [propName: string]: unknown; } +export interface RouteContext { + /** + * Plugin-specific context data. + */ + data?: object | undefined; +} + +/** + * Top-level plugin routes automatically add some context data to the route. + * This permits us to know which plugin is handling the current route. + */ +export interface PluginRouteContext extends RouteContext { + plugin: { + id: string; + name: string; + }; +} + export type Route = { readonly path: string; readonly component: ReturnType; diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 1135df89b086..da50d1b3cfbe 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -11,6 +11,7 @@ import Loading from '@theme/Loading'; import routesChunkNames from '@generated/routesChunkNames'; import registry from '@generated/registry'; import flat from '../flat'; +import {RouteContextProvider} from '../routeContext'; type OptsLoader = Record; @@ -22,7 +23,16 @@ export default function ComponentCreator( if (path === '*') { return Loadable({ loading: Loading, - loader: () => import('@theme/NotFound'), + loader: async () => { + const NotFound = (await import('@theme/NotFound')).default; + return (props) => ( + // Is there a better API for this? + + + + ); + }, }); } @@ -84,7 +94,18 @@ export default function ComponentCreator( const Component = loadedModules.component; delete loadedModules.component; - return ; + + /* eslint-disable no-underscore-dangle */ + const routeContextModule = loadedModules.__routeContextModule; + delete loadedModules.__routeContextModule; + /* eslint-enable no-underscore-dangle */ + + // Is there any way to put this RouteContextProvider upper in the tree? + return ( + + ; + + ); }, }); } diff --git a/packages/docusaurus/src/client/exports/useRouteContext.tsx b/packages/docusaurus/src/client/exports/useRouteContext.tsx new file mode 100644 index 000000000000..79c57fa9ae2c --- /dev/null +++ b/packages/docusaurus/src/client/exports/useRouteContext.tsx @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import type {PluginRouteContext} from '@docusaurus/types'; +import {Context} from '../routeContext'; + +export default function useRouteContext(): PluginRouteContext { + const context = React.useContext(Context); + if (!context) { + throw new Error( + 'Unexpected: no Docusaurus parent/current route context found', + ); + } + return context; +} diff --git a/packages/docusaurus/src/client/routeContext.tsx b/packages/docusaurus/src/client/routeContext.tsx new file mode 100644 index 000000000000..78e87a5a65a4 --- /dev/null +++ b/packages/docusaurus/src/client/routeContext.tsx @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {useMemo, type ReactNode} from 'react'; +import type {PluginRouteContext, RouteContext} from '@docusaurus/types'; + +export const Context = React.createContext(null); + +function mergeContexts({ + parent, + value, +}: { + parent: PluginRouteContext | null; + value: RouteContext | null; +}): PluginRouteContext { + if (!parent) { + if (!value) { + throw new Error( + 'Unexpected: no Docusaurus parent/current route context found', + ); + } else if (!('plugin' in value)) { + throw new Error( + 'Unexpected: Docusaurus parent route context has no plugin attribute', + ); + } + return value; + } + + // TODO deep merge this + const data = {...parent.data, ...value?.data}; + + return { + // nested routes are not supposed to override plugin attribute + plugin: parent.plugin, + data, + }; +} + +export function RouteContextProvider({ + children, + value, +}: { + children: ReactNode; + value: PluginRouteContext | null; +}): JSX.Element { + const parent = React.useContext(Context); + + const mergedValue = useMemo( + () => mergeContexts({parent, value}), + [parent, value], + ); + + return {children}; +} diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index b279b4d7a659..56142e8c66ae 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {generate} from '@docusaurus/utils'; +import {docuHash, generate} from '@docusaurus/utils'; import fs from 'fs-extra'; import path from 'path'; import type { @@ -18,6 +18,7 @@ import type { ThemeConfig, LoadedPlugin, InitializedPlugin, + PluginRouteContext, } from '@docusaurus/types'; import initPlugins from './init'; import logger from '@docusaurus/logger'; @@ -149,17 +150,6 @@ export async function loadPlugins({ const dataDirRoot = path.join(context.generatedFilesDir, plugin.name); const dataDir = path.join(dataDirRoot, pluginId); - const addRoute: PluginContentLoadedActions['addRoute'] = ( - initialRouteConfig, - ) => { - // Trailing slash behavior is handled in a generic way for all plugins - const finalRouteConfig = applyRouteTrailingSlash(initialRouteConfig, { - trailingSlash: context.siteConfig.trailingSlash, - baseUrl: context.siteConfig.baseUrl, - }); - pluginsRouteConfigs.push(finalRouteConfig); - }; - const createData: PluginContentLoadedActions['createData'] = async ( name, data, @@ -170,6 +160,34 @@ export async function loadPlugins({ return modulePath; }; + // TODO this would be better to do all that in the codegen phase + // TODO handle context for nested routes + const pluginRouteContext: PluginRouteContext = { + plugin: {name: plugin.name, id: pluginId}, + data: undefined, // TODO allow plugins to provide context data + }; + const pluginRouteContextModulePath = await createData( + `${docuHash('pluginRouteContextModule')}.json`, + JSON.stringify(pluginRouteContext, null, 2), + ); + + const addRoute: PluginContentLoadedActions['addRoute'] = ( + initialRouteConfig, + ) => { + // Trailing slash behavior is handled in a generic way for all plugins + const finalRouteConfig = applyRouteTrailingSlash(initialRouteConfig, { + trailingSlash: context.siteConfig.trailingSlash, + baseUrl: context.siteConfig.baseUrl, + }); + pluginsRouteConfigs.push({ + ...finalRouteConfig, + modules: { + ...finalRouteConfig.modules, + __routeContextModule: pluginRouteContextModulePath, + }, + }); + }; + // the plugins global data are namespaced to avoid data conflicts: // - by plugin name // - by plugin id (allow using multiple instances of the same plugin) diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index d0271d7c5b39..1e46aa3c5eda 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -21,6 +21,7 @@ exports[`base webpack config creates webpack aliases 1`] = ` "@docusaurus/useDocusaurusContext": "../../../../client/exports/useDocusaurusContext.ts", "@docusaurus/useGlobalData": "../../../../client/exports/useGlobalData.ts", "@docusaurus/useIsBrowser": "../../../../client/exports/useIsBrowser.ts", + "@docusaurus/useRouteContext": "../../../../client/exports/useRouteContext.tsx", "@generated": "../../../../../../..", "@site": "", "@theme-init/PluginThemeComponentEnhanced": "pluginThemeFolder/PluginThemeComponentEnhanced.js", @@ -68,5 +69,6 @@ exports[`getDocusaurusAliases() returns appropriate webpack aliases 1`] = ` "@docusaurus/useDocusaurusContext": "../../client/exports/useDocusaurusContext.ts", "@docusaurus/useGlobalData": "../../client/exports/useGlobalData.ts", "@docusaurus/useIsBrowser": "../../client/exports/useIsBrowser.ts", + "@docusaurus/useRouteContext": "../../client/exports/useRouteContext.tsx", } `; diff --git a/project-words.txt b/project-words.txt index 9e125c666550..458398a94018 100644 --- a/project-words.txt +++ b/project-words.txt @@ -40,6 +40,7 @@ chedeau cheng clément clsx +codegen codeql codesandbox codespaces From ecbe0b26c535eff3e24903342a53cf90f0a8d974 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 18 Mar 2022 17:28:35 +0300 Subject: [PATCH 028/405] refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook (#6930) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joshua Chen Co-authored-by: sebastienlorber Co-authored-by: Sébastien Lorber --- .../src/theme-classic.d.ts | 10 +- .../src/theme/ColorModeToggle/index.tsx | 99 ++++++--------- .../theme/ColorModeToggle/styles.module.css | 32 ++--- .../src/theme/Navbar/index.tsx | 20 +-- .../src/theme/ThemedImage/index.tsx | 5 +- .../src/hooks/usePrismTheme.ts | 4 +- packages/docusaurus-theme-common/src/index.ts | 7 +- .../src/utils/colorModeUtils.tsx | 117 +++++++++++------- .../docs/api/themes/theme-configuration.md | 4 +- .../src/components/ColorGenerator/index.tsx | 13 +- website/src/components/Zoom/index.tsx | 6 +- website/src/theme/ColorModeToggle.tsx | 6 +- 12 files changed, 157 insertions(+), 166 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 94c48ac9d3bd..e2256a48824e 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -746,12 +746,16 @@ declare module '@theme/TOCCollapsible' { } declare module '@theme/ColorModeToggle' { - import type {SyntheticEvent} from 'react'; + import type {ColorMode} from '@docusaurus/theme-common'; export interface Props { readonly className?: string; - readonly checked: boolean; - readonly onChange: (e: SyntheticEvent) => void; + readonly value: ColorMode; + /** + * The parameter represents the "to-be" value. For example, if currently in + * dark mode, clicking the button should call `onChange("light")` + */ + readonly onChange: (colorMode: ColorMode) => void; } export default function Toggle(props: Props): JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/index.tsx index e23c39571e78..e119f2ae33ed 100644 --- a/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useState, useRef, useEffect} from 'react'; +import React from 'react'; import type {Props} from '@theme/ColorModeToggle'; import useIsBrowser from '@docusaurus/useIsBrowser'; import {translate} from '@docusaurus/Translate'; @@ -15,78 +15,51 @@ import IconDarkMode from '@theme/IconDarkMode'; import clsx from 'clsx'; import styles from './styles.module.css'; -function ColorModeToggle({ - className, - checked: defaultChecked, - onChange, -}: Props): JSX.Element { +function ColorModeToggle({className, value, onChange}: Props): JSX.Element { const isBrowser = useIsBrowser(); - const [checked, setChecked] = useState(defaultChecked); - const [focused, setFocused] = useState(false); - const inputRef = useRef(null); - useEffect(() => { - setChecked(defaultChecked); - }, [defaultChecked]); + const title = translate( + { + message: 'Switch between dark and light mode (currently {mode})', + id: 'theme.colorToggle.ariaLabel', + description: 'The ARIA label for the navbar color mode toggle', + }, + { + mode: + value === 'dark' + ? translate({ + message: 'dark mode', + id: 'theme.colorToggle.ariaLabel.mode.dark', + description: 'The name for the dark color mode', + }) + : translate({ + message: 'light mode', + id: 'theme.colorToggle.ariaLabel.mode.light', + description: 'The name for the light color mode', + }), + }, + ); return ( -
    - {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */} -
    inputRef.current?.click()}> +
    +
    - - setChecked(!checked)} - onFocus={() => setFocused(true)} - onBlur={() => setFocused(false)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - inputRef.current?.click(); - } - }} - /> +
    ); } diff --git a/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/styles.module.css b/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/styles.module.css index a5a7bfb73799..37463e0fb330 100644 --- a/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/ColorModeToggle/styles.module.css @@ -6,28 +6,11 @@ */ .toggle { - position: relative; - width: 32px; - height: 32px; -} - -.toggleScreenReader { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - width: 1px; -} - -.toggleDisabled { - cursor: not-allowed; + width: 2rem; + height: 2rem; } .toggleButton { - cursor: pointer; - user-select: none; -webkit-tap-highlight-color: transparent; align-items: center; display: flex; @@ -35,17 +18,18 @@ width: 100%; height: 100%; border-radius: 50%; + transition: background var(--ifm-transition-fast); } .toggleButton:hover { - background-color: #00000010; -} - -[data-theme='dark'] .toggleButton:hover { - background-color: #ffffff20; + background: var(--ifm-color-emphasis-200); } [data-theme='light'] .darkToggleIcon, [data-theme='dark'] .lightToggleIcon { display: none; } + +.toggleButtonDisabled { + cursor: not-allowed; +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx index ef4c865e0073..1693bb44c7d6 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx @@ -88,12 +88,12 @@ function useColorModeToggle() { const { colorMode: {disableSwitch}, } = useThemeConfig(); - const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode(); - const toggle = useCallback( - (e) => (e.target.checked ? setDarkTheme() : setLightTheme()), - [setLightTheme, setDarkTheme], - ); - return {isDarkTheme, toggle, disabled: disableSwitch}; + const {colorMode, setColorMode} = useColorMode(); + return { + value: colorMode, + onChange: setColorMode, + disabled: disableSwitch, + }; } function useSecondaryMenu({ @@ -173,8 +173,8 @@ function NavbarMobileSidebar({ {!colorModeToggle.disabled && ( )} + ); +} + +export default function NavbarMobileSidebarHeader(): JSX.Element { + return ( +
    + + + +
    + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Layout/index.tsx new file mode 100644 index 000000000000..4fe7a4f9984c --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Layout/index.tsx @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import type {Props} from '@theme/Navbar/MobileSidebar/Layout'; +import {useNavbarSecondaryMenu} from '@docusaurus/theme-common'; + +export default function NavbarMobileSidebarLayout({ + header, + primaryMenu, + secondaryMenu, +}: Props): JSX.Element { + const {shown: secondaryMenuShown} = useNavbarSecondaryMenu(); + return ( +
    + {header} +
    +
    {primaryMenu}
    +
    {secondaryMenu}
    +
    +
    + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx new file mode 100644 index 000000000000..dbde63edb558 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {useNavbarMobileSidebar, useThemeConfig} from '@docusaurus/theme-common'; +import type {Props as NavbarItemConfig} from '@theme/NavbarItem'; +import NavbarItem from '../../../NavbarItem'; + +function useNavbarItems() { + // TODO temporary casting until ThemeConfig type is improved + return useThemeConfig().navbar.items as NavbarItemConfig[]; +} + +// The primary menu displays the navbar items +export default function NavbarMobilePrimaryMenu(): JSX.Element { + const mobileSidebar = useNavbarMobileSidebar(); + + // TODO how can the order be defined for mobile? + // Should we allow providing a different list of items? + const items = useNavbarItems(); + + return ( +
      + {items.map((item, i) => ( + mobileSidebar.toggle()} + key={i} + /> + ))} +
    + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx new file mode 100644 index 000000000000..a15ba55c5684 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ComponentProps} from 'react'; +import {useNavbarSecondaryMenu, useThemeConfig} from '@docusaurus/theme-common'; +import Translate from '@docusaurus/Translate'; + +function SecondaryMenuBackButton(props: ComponentProps<'button'>) { + return ( + + ); +} + +// The secondary menu slides from the right and shows contextual information +// such as the docs sidebar +export default function NavbarMobileSidebarSecondaryMenu(): JSX.Element | null { + const isPrimaryMenuEmpty = useThemeConfig().navbar.items.length === 0; + const secondaryMenu = useNavbarSecondaryMenu(); + return ( + <> + {/* edge-case: prevent returning to the primaryMenu when it's empty */} + {!isPrimaryMenuEmpty && ( + secondaryMenu.hide()} /> + )} + {secondaryMenu.content} + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Toggle/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Toggle/index.tsx new file mode 100644 index 000000000000..e4ac62a50584 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Toggle/index.tsx @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import IconMenu from '@theme/IconMenu'; +import {useNavbarMobileSidebar} from '@docusaurus/theme-common'; + +export default function MobileSidebarToggle(): JSX.Element { + const mobileSidebar = useNavbarMobileSidebar(); + return ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/index.tsx new file mode 100644 index 000000000000..4a29c4901525 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/index.tsx @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import NavbarMobileSidebarLayout from '@theme/Navbar/MobileSidebar/Layout'; +import NavbarMobileSidebarHeader from '@theme/Navbar/MobileSidebar/Header'; +import { + useLockBodyScroll, + useNavbarMobileSidebar, +} from '@docusaurus/theme-common'; +import NavbarMobileSidebarPrimaryMenu from '@theme/Navbar/MobileSidebar/PrimaryMenu'; +import NavbarMobileSidebarSecondaryMenu from '@theme/Navbar/MobileSidebar/SecondaryMenu'; + +export default function NavbarMobileSidebar(): JSX.Element | null { + const mobileSidebar = useNavbarMobileSidebar(); + useLockBodyScroll(mobileSidebar.shown); + + if (!mobileSidebar.shouldRender) { + return null; + } + + return ( + } + primaryMenu={} + secondaryMenu={} + /> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx index 1693bb44c7d6..878f2047ad40 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx @@ -5,300 +5,14 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useCallback, useState, useEffect} from 'react'; -import clsx from 'clsx'; -import Translate from '@docusaurus/Translate'; -import SearchBar from '@theme/SearchBar'; -import ColorModeToggle from '@theme/ColorModeToggle'; -import { - useThemeConfig, - useMobileSecondaryMenuRenderer, - usePrevious, - useHistoryPopHandler, - useHideableNavbar, - useLockBodyScroll, - useWindowSize, - useColorMode, -} from '@docusaurus/theme-common'; -import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; -import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem'; -import Logo from '@theme/Logo'; -import IconMenu from '@theme/IconMenu'; -import IconClose from '@theme/IconClose'; - -import styles from './styles.module.css'; - -// retrocompatible with v1 -const DefaultNavItemPosition = 'right'; - -function useNavbarItems() { - // TODO temporary casting until ThemeConfig type is improved - return useThemeConfig().navbar.items as NavbarItemConfig[]; -} - -// If split links by left/right -// if position is unspecified, fallback to right (as v1) -function splitNavItemsByPosition(items: NavbarItemConfig[]) { - const leftItems = items.filter( - (item) => (item.position ?? DefaultNavItemPosition) === 'left', - ); - const rightItems = items.filter( - (item) => (item.position ?? DefaultNavItemPosition) === 'right', - ); - return { - leftItems, - rightItems, - }; -} - -function useMobileSidebar() { - const windowSize = useWindowSize(); - - // Mobile sidebar not visible on hydration: can avoid SSR rendering - const shouldRender = windowSize === 'mobile'; // || windowSize === 'ssr'; - - const [shown, setShown] = useState(false); - - // Close mobile sidebar on navigation pop - // Most likely firing when using the Android back button (but not only) - useHistoryPopHandler(() => { - if (shown) { - setShown(false); - // Should we prevent the navigation here? - // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846 - return false; // prevent pop navigation - } - return undefined; - }); - - const toggle = useCallback(() => { - setShown((s) => !s); - }, []); - - useEffect(() => { - if (windowSize === 'desktop') { - setShown(false); - } - }, [windowSize]); - - return {shouldRender, toggle, shown}; -} - -function useColorModeToggle() { - const { - colorMode: {disableSwitch}, - } = useThemeConfig(); - const {colorMode, setColorMode} = useColorMode(); - return { - value: colorMode, - onChange: setColorMode, - disabled: disableSwitch, - }; -} - -function useSecondaryMenu({ - sidebarShown, - toggleSidebar, -}: NavbarMobileSidebarProps) { - const content = useMobileSecondaryMenuRenderer()?.({ - toggleSidebar, - }); - const previousContent = usePrevious(content); - - const [shown, setShown] = useState( - () => - // /!\ content is set with useEffect, - // so it's not available on mount anyway - // "return !!content" => always returns false - false, - ); - - // When content is become available for the first time (set in useEffect) - // we set this content to be shown! - useEffect(() => { - const contentBecameAvailable = content && !previousContent; - if (contentBecameAvailable) { - setShown(true); - } - }, [content, previousContent]); - - const hasContent = !!content; - - // On sidebar close, secondary menu is set to be shown on next re-opening - // (if any secondary menu content available) - useEffect(() => { - if (!hasContent) { - setShown(false); - return; - } - if (!sidebarShown) { - setShown(true); - } - }, [sidebarShown, hasContent]); - - const hide = useCallback(() => { - setShown(false); - }, []); - - return {shown, hide, content}; -} - -type NavbarMobileSidebarProps = { - sidebarShown: boolean; - toggleSidebar: () => void; -}; - -function NavbarMobileSidebar({ - sidebarShown, - toggleSidebar, -}: NavbarMobileSidebarProps) { - useLockBodyScroll(sidebarShown); - const items = useNavbarItems(); - - const colorModeToggle = useColorModeToggle(); - - const secondaryMenu = useSecondaryMenu({ - sidebarShown, - toggleSidebar, - }); - - return ( -
    -
    - - {!colorModeToggle.disabled && ( - - )} - -
    - -
    -
    -
      - {items.map((item, i) => ( - - ))} -
    -
    - -
    - {items.length > 0 && ( - - )} - {secondaryMenu.content} -
    -
    -
    - ); -} +import React from 'react'; +import NavbarLayout from '@theme/Navbar/Layout'; +import NavbarContent from '@theme/Navbar/Content'; export default function Navbar(): JSX.Element { - const { - navbar: {hideOnScroll, style}, - } = useThemeConfig(); - - const mobileSidebar = useMobileSidebar(); - const colorModeToggle = useColorModeToggle(); - const activeDocPlugin = useActivePlugin(); - const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll); - - const items = useNavbarItems(); - const hasSearchNavbarItem = items.some((item) => item.type === 'search'); - const {leftItems, rightItems} = splitNavItemsByPosition(items); - return ( - + + + ); } diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 92c394e4466b..a670df39a2b8 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -71,13 +71,6 @@ export { export {default as Details, type DetailsProps} from './components/Details'; -export { - MobileSecondaryMenuProvider, - MobileSecondaryMenuFiller, - useMobileSecondaryMenuRenderer, -} from './utils/mobileSecondaryMenu'; -export type {MobileSecondaryMenuComponent} from './utils/mobileSecondaryMenu'; - export { useDocsPreferredVersion, useDocsPreferredVersionByPluginId, @@ -151,6 +144,17 @@ export { TabGroupChoiceProvider, } from './utils/tabGroupChoiceUtils'; +export { + splitNavbarItems, + NavbarProvider, + useNavbarMobileSidebar, +} from './utils/navbarUtils'; +export { + useNavbarSecondaryMenu, + NavbarSecondaryMenuFiller, +} from './utils/navbarSecondaryMenuUtils'; +export type {NavbarSecondaryMenuComponent} from './utils/navbarSecondaryMenuUtils'; + export {default as useHideableNavbar} from './hooks/useHideableNavbar'; export { default as useKeyboardNavigation, diff --git a/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx b/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx deleted file mode 100644 index ed898a903317..000000000000 --- a/packages/docusaurus-theme-common/src/utils/mobileSecondaryMenu.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { - useState, - useContext, - useEffect, - useMemo, - type ReactNode, - type ComponentType, -} from 'react'; -import {ReactContextError} from './reactUtils'; - -/* -The idea behind all this is that a specific component must be able to fill a -placeholder in the generic layout. The doc page should be able to fill the -secondary menu of the main mobile navbar. This permits to reduce coupling -between the main layout and the specific page. - -This kind of feature is often called portal/teleport/gateway... various -unmaintained React libs exist. Most up-to-date one: https://github.com/gregberge/react-teleporter -Not sure any of those is safe regarding concurrent mode. - */ - -type ExtraProps = { - toggleSidebar: () => void; -}; - -export type MobileSecondaryMenuComponent = ComponentType< - Props & ExtraProps ->; - -type State = { - component: MobileSecondaryMenuComponent; - props: unknown; -} | null; - -function useContextValue() { - return useState(null); -} - -type ContextValue = ReturnType; - -const Context = React.createContext(null); - -export function MobileSecondaryMenuProvider({ - children, -}: { - children: ReactNode; -}): JSX.Element { - return ( - {children} - ); -} - -function useMobileSecondaryMenuContext(): ContextValue { - const value = useContext(Context); - if (value === null) { - throw new ReactContextError('MobileSecondaryMenuProvider'); - } - return value; -} - -export function useMobileSecondaryMenuRenderer(): ( - extraProps: ExtraProps, -) => ReactNode | undefined { - const [state] = useMobileSecondaryMenuContext(); - if (state) { - const Comp = state.component; - return function render(extraProps) { - return ; - }; - } - return () => undefined; -} - -function useShallowMemoizedObject>(obj: O) { - return useMemo( - () => obj, - // Is this safe? - // eslint-disable-next-line react-hooks/exhaustive-deps - [...Object.keys(obj), ...Object.values(obj)], - ); -} - -// Fill the secondary menu placeholder with some real content -export function MobileSecondaryMenuFiller< - Props extends Record, ->({ - component, - props, -}: { - component: MobileSecondaryMenuComponent; - props: Props; -}): JSX.Element | null { - const [, setState] = useMobileSecondaryMenuContext(); - - // To avoid useless context re-renders, props are memoized shallowly - const memoizedProps = useShallowMemoizedObject(props); - - useEffect(() => { - // @ts-expect-error: context is not 100% type-safe but it's ok - setState({component, props: memoizedProps}); - }, [setState, component, memoizedProps]); - - useEffect(() => () => setState(null), [setState]); - - return null; -} diff --git a/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx new file mode 100644 index 000000000000..d5bedcb8cef2 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx @@ -0,0 +1,170 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + useState, + useContext, + useEffect, + useMemo, + useCallback, + type ReactNode, + type ComponentType, +} from 'react'; +import {ReactContextError} from './reactUtils'; +import {usePrevious} from './usePrevious'; +import {useNavbarMobileSidebar} from './navbarUtils'; + +/* +The idea behind all this is that a specific component must be able to fill a +placeholder in the generic layout. The doc page should be able to fill the +secondary menu of the main mobile navbar. This permits to reduce coupling +between the main layout and the specific page. + +This kind of feature is often called portal/teleport/gateway... various +unmaintained React libs exist. Most up-to-date one: https://github.com/gregberge/react-teleporter +Not sure any of those is safe regarding concurrent mode. + */ + +export type NavbarSecondaryMenuComponent = ComponentType; + +type State = { + shown: boolean; + content: + | { + component: ComponentType; + props: object; + } + | {component: null; props: null}; +}; + +const InitialState: State = { + shown: false, + content: {component: null, props: null}, +}; + +function useContextValue() { + const mobileSidebar = useNavbarMobileSidebar(); + + const [state, setState] = useState(InitialState); + + const setShown = (shown: boolean) => setState((s) => ({...s, shown})); + + const hasContent = state.content?.component !== null; + const previousHasContent = usePrevious(state.content?.component !== null); + + // When content is become available for the first time (set in useEffect) + // we set this content to be shown! + useEffect(() => { + const contentBecameAvailable = hasContent && !previousHasContent; + if (contentBecameAvailable) { + setShown(true); + } + }, [hasContent, previousHasContent]); + + // On sidebar close, secondary menu is set to be shown on next re-opening + // (if any secondary menu content available) + useEffect(() => { + if (!hasContent) { + setShown(false); + return; + } + if (!mobileSidebar.shown) { + setShown(true); + } + }, [mobileSidebar.shown, hasContent]); + + return [state, setState] as const; +} + +type ContextValue = ReturnType; + +const Context = React.createContext(null); + +export function NavbarSecondaryMenuProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + return ( + {children} + ); +} + +function useNavbarSecondaryMenuContext(): ContextValue { + const value = useContext(Context); + if (value === null) { + throw new ReactContextError('MobileSecondaryMenuProvider'); + } + return value; +} + +function useShallowMemoizedObject>(obj: O) { + return useMemo( + () => obj, + // Is this safe? + // eslint-disable-next-line react-hooks/exhaustive-deps + [...Object.keys(obj), ...Object.values(obj)], + ); +} + +// Fill the secondary menu placeholder with some real content +export function NavbarSecondaryMenuFiller< + Props extends Record, +>({ + component, + props, +}: { + component: NavbarSecondaryMenuComponent; + props: Props; +}): JSX.Element | null { + const [, setState] = useNavbarSecondaryMenuContext(); + + // To avoid useless context re-renders, props are memoized shallowly + const memoizedProps = useShallowMemoizedObject(props); + + useEffect(() => { + // @ts-expect-error: context is not 100% type-safe but it's ok + setState((s) => ({...s, content: {component, props: memoizedProps}})); + }, [setState, component, memoizedProps]); + + useEffect( + () => () => setState((s) => ({...s, component: null, props: null})), + [setState], + ); + + return null; +} + +function renderElement(state: State): JSX.Element | undefined { + if (state.content?.component) { + const Comp = state.content.component; + return ; + } + return undefined; +} + +export function useNavbarSecondaryMenu(): { + shown: boolean; + hide: () => void; + content: JSX.Element | undefined; +} { + const [state, setState] = useNavbarSecondaryMenuContext(); + + const hide = useCallback( + () => setState((s) => ({...s, shown: false})), + [setState], + ); + + return useMemo( + () => ({ + shown: state.shown, + hide, + content: renderElement(state), + }), + [hide, state], + ); +} diff --git a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx new file mode 100644 index 000000000000..f6a1bc9d7848 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx @@ -0,0 +1,129 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + type ReactNode, + useCallback, + useEffect, + useState, + useMemo, +} from 'react'; +import useWindowSize from '../hooks/useWindowSize'; +import {useHistoryPopHandler} from './historyUtils'; +import {NavbarSecondaryMenuProvider} from './navbarSecondaryMenuUtils'; +import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; +import {useThemeConfig} from './useThemeConfig'; +import {ReactContextError} from './reactUtils'; + +const DefaultNavItemPosition = 'right'; + +// If split links by left/right +// if position is unspecified, fallback to right +export function splitNavbarItems( + items: T[], +): [leftItems: T[], rightItems: T[]] { + function isLeft(item: T): boolean { + return (item.position ?? DefaultNavItemPosition) === 'left'; + } + + const leftItems = items.filter(isLeft); + const rightItems = items.filter((item) => !isLeft(item)); + + return [leftItems, rightItems]; +} + +type NavbarMobileSidebarContextValue = { + disabled: boolean; + shouldRender: boolean; + toggle: () => void; + shown: boolean; +}; + +const NavbarMobileSidebarContext = React.createContext< + NavbarMobileSidebarContextValue | undefined +>(undefined); + +// Mobile sidebar can be disabled in case it would lead to an empty sidebar +// In this case it's not useful to display a navbar sidebar toggle button +function useNavbarMobileSidebarDisabled() { + const activeDocPlugin = useActivePlugin(); + const {items} = useThemeConfig().navbar; + return items.length === 0 && !activeDocPlugin; +} + +function useNavbarMobileSidebarContextValue(): NavbarMobileSidebarContextValue { + const disabled = useNavbarMobileSidebarDisabled(); + const windowSize = useWindowSize(); + + // Mobile sidebar not visible until user interaction: can avoid SSR rendering + const shouldRender = !disabled && windowSize === 'mobile'; // || windowSize === 'ssr'; + + const [shown, setShown] = useState(false); + + // Close mobile sidebar on navigation pop + // Most likely firing when using the Android back button (but not only) + useHistoryPopHandler(() => { + if (shown) { + setShown(false); + // Should we prevent the navigation here? + // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846 + return false; // prevent pop navigation + } + return undefined; + }); + + const toggle = useCallback(() => { + setShown((s) => !s); + }, []); + + useEffect(() => { + if (windowSize === 'desktop') { + setShown(false); + } + }, [windowSize]); + + // Return stable context value + return useMemo( + () => ({ + disabled, + shouldRender, + toggle, + shown, + }), + [disabled, shouldRender, toggle, shown], + ); +} + +function NavbarMobileSidebarProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const value = useNavbarMobileSidebarContextValue(); + return ( + + {children} + + ); +} + +export function useNavbarMobileSidebar(): NavbarMobileSidebarContextValue { + const context = React.useContext(NavbarMobileSidebarContext); + if (context == null) { + throw new ReactContextError('NavbarMobileSidebarProvider'); + } + return context; +} + +// Add all Navbar providers at once +export function NavbarProvider({children}: {children: ReactNode}): JSX.Element { + return ( + + {children} + + ); +} diff --git a/project-words.txt b/project-words.txt index 458398a94018..ae29fa0b5180 100644 --- a/project-words.txt +++ b/project-words.txt @@ -98,6 +98,7 @@ globby goss goyal gtag +hardcoding hahaha héctor héllô diff --git a/website/package.json b/website/package.json index 7a9488fcc2c0..71a07a2fb62c 100644 --- a/website/package.json +++ b/website/package.json @@ -8,7 +8,7 @@ "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", - "clear": "docusaurus clear && rimraf changelog", + "clear": "docusaurus clear && rimraf changelog && rimraf _dogfooding/_swizzle_theme_tests", "serve": "docusaurus serve", "test:css-order": "node testCSSOrder.mjs", "test:swizzle:eject:js": "cross-env SWIZZLE_ACTION='eject' SWIZZLE_TYPESCRIPT='false' node _dogfooding/testSwizzleThemeClassic.mjs", From 74e37e86ba66525dace05d09871f4aca1af573fd Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 18 Mar 2022 19:16:32 +0300 Subject: [PATCH 030/405] fix: remove semicolon from HTML output (#6936) --- packages/docusaurus/src/client/exports/ComponentCreator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index da50d1b3cfbe..80d2f585c66a 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -103,7 +103,7 @@ export default function ComponentCreator( // Is there any way to put this RouteContextProvider upper in the tree? return ( - ; + ); }, From 74f653dd82d9db9f34dc28ecc0cf4340b4e309b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 18 Mar 2022 18:53:00 +0100 Subject: [PATCH 031/405] refactor(theme-{classic,common}): change how site/page/search metadata is handled (#6925) --- .../src/index.d.ts | 6 +- .../src/theme-classic.d.ts | 38 +--- .../src/theme/BlogArchivePage/index.tsx | 22 ++- .../src/theme/BlogListPage/index.tsx | 45 +++-- .../src/theme/BlogPostPage/index.tsx | 103 +++++------ .../src/theme/BlogTagsListPage/index.tsx | 28 +-- .../src/theme/BlogTagsPostsPage/index.tsx | 71 ++++---- .../DocCategoryGeneratedIndexPage/index.tsx | 35 +++- .../src/theme/DocItem/index.tsx | 117 +++++++------ .../src/theme/DocPage/index.tsx | 162 +++++++++--------- .../src/theme/DocPage/styles.module.css | 4 - .../src/theme/DocTagDocListPage/index.tsx | 68 ++++---- .../src/theme/DocTagsListPage/index.tsx | 37 ++-- .../src/theme/Layout/index.tsx | 25 +-- .../src/theme/MDXPage/index.tsx | 58 ++++--- .../src/theme/NotFound.tsx | 71 ++++---- .../src/theme/Seo/index.tsx | 49 ------ .../{LayoutHead => SiteMetadata}/index.tsx | 36 ++-- packages/docusaurus-theme-common/src/index.ts | 3 +- ...etadataUtilsTemp.tsx => metadataUtils.tsx} | 47 +++++ .../src/theme/SearchPage/index.tsx | 13 +- packages/docusaurus/src/client/App.tsx | 4 + .../src/client/SiteMetadataDefaults.tsx | 27 +++ .../src/client/theme-fallback/Error/index.tsx | 6 +- .../client/theme-fallback/Layout/index.tsx | 27 +-- .../client/theme-fallback/NotFound/index.tsx | 30 ++-- .../src/client/theme-fallback/Root/index.tsx | 5 +- .../theme-fallback/SiteMetadata/index.tsx | 11 ++ .../__tests__/__snapshots__/base.test.ts.snap | 2 + website/_dogfooding/dogfooding.css | 22 +++ website/docs/guides/creating-pages.md | 6 +- website/docs/seo.md | 37 ++-- website/docusaurus.config.js | 5 +- website/src/css/custom.css | 4 - .../changelog/theme/ChangelogList/index.tsx | 47 +++-- .../changelog/theme/ChangelogPage/index.tsx | 150 +++++++++------- 36 files changed, 802 insertions(+), 619 deletions(-) delete mode 100644 packages/docusaurus-theme-classic/src/theme/Seo/index.tsx rename packages/docusaurus-theme-classic/src/theme/{LayoutHead => SiteMetadata}/index.tsx (76%) rename packages/docusaurus-theme-common/src/utils/{metadataUtilsTemp.tsx => metadataUtils.tsx} (54%) create mode 100644 packages/docusaurus/src/client/SiteMetadataDefaults.tsx create mode 100644 packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx create mode 100644 website/_dogfooding/dogfooding.css diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index d8fbaa1b4b22..d8d8b53f4273 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -92,8 +92,6 @@ declare module '@theme/Layout' { export interface Props { readonly children?: ReactNode; - readonly title?: string; - readonly description?: string; } export default function Layout(props: Props): JSX.Element; } @@ -117,6 +115,10 @@ declare module '@theme/Root' { export default function Root({children}: Props): JSX.Element; } +declare module '@theme/SiteMetadata' { + export default function SiteMetadata(): JSX.Element; +} + declare module '@docusaurus/constants' { export const DEFAULT_PLUGIN_ID: 'default'; } diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 8fb54747d09a..dffa79e8d3e8 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -364,31 +364,17 @@ declare module '@theme/Layout' { export interface Props { readonly children?: ReactNode; - readonly title?: string; readonly noFooter?: boolean; - readonly description?: string; - readonly image?: string; - readonly keywords?: string | string[]; - readonly permalink?: string; readonly wrapperClassName?: string; - readonly pageClassName?: string; - readonly searchMetadata?: { - readonly version?: string; - readonly tag?: string; - }; + + // Not really layout-related, but kept for convenience/retro-compatibility + readonly title?: string; + readonly description?: string; } export default function Layout(props: Props): JSX.Element; } -declare module '@theme/LayoutHead' { - import type {Props as LayoutProps} from '@theme/Layout'; - - export interface Props extends Omit {} - - export default function LayoutHead(props: Props): JSX.Element; -} - declare module '@theme/LayoutProviders' { import type {ReactNode} from 'react'; @@ -480,7 +466,7 @@ declare module '@theme/Navbar/Content' { declare module '@theme/Navbar/Layout' { export interface Props { - children: React.ReactNode; + readonly children: React.ReactNode; } export default function NavbarLayout(props: Props): JSX.Element; @@ -927,17 +913,3 @@ declare module '@theme/prism-include-languages' { PrismObject: typeof PrismNamespace, ): void; } - -declare module '@theme/Seo' { - import type {ReactNode} from 'react'; - - export interface Props { - readonly title?: string; - readonly description?: string; - readonly keywords?: readonly string[] | string; - readonly image?: string; - readonly children?: ReactNode; - } - - export default function Seo(props: Props): JSX.Element; -} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogArchivePage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogArchivePage/index.tsx index f10c59b1910e..a05afdf43fe8 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogArchivePage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogArchivePage/index.tsx @@ -10,6 +10,7 @@ import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; import type {ArchiveBlogPost, Props} from '@theme/BlogArchivePage'; import {translate} from '@docusaurus/Translate'; +import {PageMetadata} from '@docusaurus/theme-common'; type YearProp = { year: string; @@ -75,14 +76,17 @@ export default function BlogArchive({archive}: Props): JSX.Element { }); const years = listPostsByYears(archive.blogPosts); return ( - -
    -
    -

    {title}

    -

    {description}

    -
    -
    -
    {years.length > 0 && }
    -
    + <> + + +
    +
    +

    {title}

    +

    {description}

    +
    +
    +
    {years.length > 0 && }
    +
    + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx index 088d6e67f169..910328b214ce 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx @@ -12,28 +12,34 @@ import BlogLayout from '@theme/BlogLayout'; import BlogPostItem from '@theme/BlogPostItem'; import BlogListPaginator from '@theme/BlogListPaginator'; import type {Props} from '@theme/BlogListPage'; -import {ThemeClassNames} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; +import SearchMetadata from '@theme/SearchMetadata'; +import clsx from 'clsx'; -export default function BlogListPage(props: Props): JSX.Element { - const {metadata, items, sidebar} = props; +function BlogListPageMetadata(props: Props): JSX.Element { + const {metadata} = props; const { siteConfig: {title: siteTitle}, } = useDocusaurusContext(); const {blogDescription, blogTitle, permalink} = metadata; const isBlogOnlyMode = permalink === '/'; const title = isBlogOnlyMode ? siteTitle : blogTitle; + return ( + <> + + + + ); +} +function BlogListPageContent(props: Props): JSX.Element { + const {metadata, items, sidebar} = props; return ( - + {items.map(({content: BlogPostContent}) => ( ); } + +export default function BlogListPage(props: Props): JSX.Element { + return ( + + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx index 84918a3019ff..c7b9ec88e5d3 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx @@ -6,40 +6,63 @@ */ import React from 'react'; -import Seo from '@theme/Seo'; import BlogLayout from '@theme/BlogLayout'; import BlogPostItem from '@theme/BlogPostItem'; import BlogPostPaginator from '@theme/BlogPostPaginator'; import type {Props} from '@theme/BlogPostPage'; -import {ThemeClassNames} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; import TOC from '@theme/TOC'; +import clsx from 'clsx'; -export default function BlogPostPage(props: Props): JSX.Element { +function BlogPostPageMetadata(props: Props): JSX.Element { + const {content: BlogPostContents} = props; + const {assets, metadata} = BlogPostContents; + const {title, description, date, tags, authors, frontMatter} = metadata; + const {keywords} = frontMatter; + const image = assets.image ?? frontMatter.image; + return ( + + + + {/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */} + {authors.some((author) => author.url) && ( + author.url) + .filter(Boolean) + .join(',')} + /> + )} + {tags.length > 0 && ( + tag.label).join(',')} + /> + )} + + ); +} + +function BlogPostPageContent(props: Props): JSX.Element { const {content: BlogPostContents, sidebar} = props; const {assets, metadata} = BlogPostContents; - const { - title, - description, - nextItem, - prevItem, - date, - tags, - authors, - frontMatter, - } = metadata; + const {nextItem, prevItem, frontMatter} = metadata; const { hide_table_of_contents: hideTableOfContents, - keywords, toc_min_heading_level: tocMinHeadingLevel, toc_max_heading_level: tocMaxHeadingLevel, } = frontMatter; - - const image = assets.image ?? frontMatter.image; - return ( ) : undefined }> - - - - - {/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */} - {authors.some((author) => author.url) && ( - author.url) - .filter(Boolean) - .join(',')} - /> - )} - {tags.length > 0 && ( - tag.label).join(',')} - /> - )} - - ); } + +export default function BlogPostPage(props: Props): JSX.Element { + return ( + + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx index 9b354c1f71d7..1124e06aaa37 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx @@ -11,25 +11,29 @@ import BlogLayout from '@theme/BlogLayout'; import TagsListByLetter from '@theme/TagsListByLetter'; import type {Props} from '@theme/BlogTagsListPage'; import { + PageMetadata, + HtmlClassNameProvider, ThemeClassNames, translateTagsPageTitle, } from '@docusaurus/theme-common'; +import SearchMetadata from '../SearchMetadata'; +import clsx from 'clsx'; export default function BlogTagsListPage(props: Props): JSX.Element { const {tags, sidebar} = props; const title = translateTagsPageTitle(); return ( - -

    {title}

    - -
    + + + + +

    {title}

    + +
    +
    ); } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx index 6791d74f9df8..fa3bf26a2437 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx @@ -12,8 +12,15 @@ import BlogLayout from '@theme/BlogLayout'; import BlogPostItem from '@theme/BlogPostItem'; import type {Props} from '@theme/BlogTagsPostsPage'; import Translate, {translate} from '@docusaurus/Translate'; -import {ThemeClassNames, usePluralForm} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, + usePluralForm, +} from '@docusaurus/theme-common'; import BlogListPaginator from '@theme/BlogListPaginator'; +import SearchMetadata from '@theme/SearchMetadata'; +import clsx from 'clsx'; // Very simple pluralization: probably good enough for now function useBlogPostsPlural() { @@ -47,38 +54,38 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element { ); return ( - -
    -

    {title}

    + + + + +
    +

    {title}

    - - - View All Tags - - -
    + + + View All Tags + + +
    - {items.map(({content: BlogPostContent}) => ( - - - - ))} - -
    + {items.map(({content: BlogPostContent}) => ( + + + + ))} + +
    + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx index 0d6f3e5ffe7d..179839ac09cc 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx @@ -6,11 +6,13 @@ */ import React from 'react'; -import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; +import { + PageMetadata, + useCurrentSidebarCategory, +} from '@docusaurus/theme-common'; import type {Props} from '@theme/DocCategoryGeneratedIndexPage'; import DocCardList from '@theme/DocCardList'; import DocPaginator from '@theme/DocPaginator'; -import Seo from '@theme/Seo'; import DocVersionBanner from '@theme/DocVersionBanner'; import DocVersionBadge from '@theme/DocVersionBadge'; import DocBreadcrumbs from '@theme/DocBreadcrumbs'; @@ -19,13 +21,27 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; import styles from './styles.module.css'; -export default function DocCategoryGeneratedIndexPage({ +function DocCategoryGeneratedIndexPageMetadata({ + categoryGeneratedIndex, +}: Props): JSX.Element { + return ( + + ); +} + +function DocCategoryGeneratedIndexPageContent({ categoryGeneratedIndex, }: Props): JSX.Element { const category = useCurrentSidebarCategory(); return ( <> - ); } + +export default function DocCategoryGeneratedIndexPage( + props: Props, +): JSX.Element { + return ( + <> + + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index 45b8dd52a78f..aa675efa2c9b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -10,7 +10,6 @@ import clsx from 'clsx'; import DocPaginator from '@theme/DocPaginator'; import DocVersionBanner from '@theme/DocVersionBanner'; import DocVersionBadge from '@theme/DocVersionBadge'; -import Seo from '@theme/Seo'; import type {Props} from '@theme/DocItem'; import DocItemFooter from '@theme/DocItemFooter'; import TOC from '@theme/TOC'; @@ -18,6 +17,7 @@ import TOCCollapsible from '@theme/TOCCollapsible'; import Heading from '@theme/Heading'; import styles from './styles.module.css'; import { + PageMetadata, HtmlClassNameProvider, ThemeClassNames, useWindowSize, @@ -25,18 +25,26 @@ import { import DocBreadcrumbs from '@theme/DocBreadcrumbs'; import MDXContent from '@theme/MDXContent'; -export default function DocItem(props: Props): JSX.Element { +function DocItemMetadata(props: Props): JSX.Element { const {content: DocContent} = props; const {metadata, frontMatter, assets} = DocContent; + const {keywords} = frontMatter; + const {description, title} = metadata; + const image = assets.image ?? frontMatter.image; + + return ; +} + +function DocItemContent(props: Props): JSX.Element { + const {content: DocContent} = props; + const {metadata, frontMatter} = DocContent; const { - keywords, hide_title: hideTitle, hide_table_of_contents: hideTableOfContents, toc_min_heading_level: tocMinHeadingLevel, toc_max_heading_level: tocMaxHeadingLevel, } = frontMatter; - const {description, title} = metadata; - const image = assets.image ?? frontMatter.image; + const {title} = metadata; // We only add a title if: // - user asks to hide it with front matter @@ -53,64 +61,69 @@ export default function DocItem(props: Props): JSX.Element { canRenderTOC && (windowSize === 'desktop' || windowSize === 'ssr'); return ( - - - -
    -
    - -
    -
    - - +
    +
    + +
    +
    + + - {canRenderTOC && ( - - )} + {canRenderTOC && ( + + )} -
    - {/* +
    + {/* Title can be declared inside md content or declared through front matter and added manually. To make both cases consistent, the added title is added under the same div.markdown block See https://github.com/facebook/docusaurus/pull/4882#issuecomment-853021120 */} - {shouldAddTitle && ( -
    - {title} -
    - )} - - - -
    + {shouldAddTitle && ( +
    + {title} +
    + )} + + + +
    - -
    + +
    - -
    +
    - {renderTocDesktop && ( -
    - -
    - )}
    + {renderTocDesktop && ( +
    + +
    + )} + + ); +} + +export default function DocItem(props: Props): JSX.Element { + const docHtmlClassName = `docs-doc-id-${props.content.metadata.unversionedId}`; + return ( + + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index be8ef387c7ac..d75ffa55a5fe 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -29,6 +29,7 @@ import { useDocsSidebar, DocsVersionProvider, } from '@docusaurus/theme-common'; +import SearchMetadata from '@theme/SearchMetadata'; type DocPageContentProps = { readonly currentDocRoute: DocumentRoute; @@ -56,87 +57,89 @@ function DocPageContent({ }, [hiddenSidebar]); return ( - -
    - + <> + + +
    + - {sidebar && ( - + )} +
    - {children} -
    - -
    -
    +
    + {children} +
    + + + + ); } @@ -161,7 +164,12 @@ export default function DocPage(props: Props): JSX.Element { : null; return ( - + -
    -
    -
    -
    -

    {title}

    - - - View All Tags - - -
    -
    - {tag.docs.map((doc) => ( - - ))} -
    -
    + + + + +
    +
    +
    +
    +

    {title}

    + + + View All Tags + + +
    +
    + {tag.docs.map((doc) => ( + + ))} +
    +
    +
    -
    - + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx index 9443de0841f1..5ab4f5a44db9 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocTagsListPage/index.tsx @@ -9,31 +9,36 @@ import React from 'react'; import Layout from '@theme/Layout'; import { + PageMetadata, + HtmlClassNameProvider, ThemeClassNames, translateTagsPageTitle, } from '@docusaurus/theme-common'; import TagsListByLetter from '@theme/TagsListByLetter'; import type {Props} from '@theme/DocTagsListPage'; +import SearchMetadata from '@theme/SearchMetadata'; +import clsx from 'clsx'; export default function DocTagsListPage({tags}: Props): JSX.Element { const title = translateTagsPageTitle(); return ( - -
    -
    -
    -

    {title}

    - -
    + + + + +
    +
    +
    +

    {title}

    + +
    +
    -
    - + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx index ce56fe8d01ec..35592ef869f7 100644 --- a/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx @@ -13,20 +13,30 @@ import AnnouncementBar from '@theme/AnnouncementBar'; import Navbar from '@theme/Navbar'; import Footer from '@theme/Footer'; import LayoutProviders from '@theme/LayoutProviders'; -import LayoutHead from '@theme/LayoutHead'; import type {Props} from '@theme/Layout'; -import {ThemeClassNames, useKeyboardNavigation} from '@docusaurus/theme-common'; +import { + PageMetadata, + ThemeClassNames, + useKeyboardNavigation, +} from '@docusaurus/theme-common'; import ErrorPageContent from '@theme/ErrorPageContent'; import './styles.css'; export default function Layout(props: Props): JSX.Element { - const {children, noFooter, wrapperClassName, pageClassName} = props; + const { + children, + noFooter, + wrapperClassName, + // not really layout-related, but kept for convenience/retro-compatibility + title, + description, + } = props; useKeyboardNavigation(); return ( - + @@ -34,12 +44,7 @@ export default function Layout(props: Props): JSX.Element { -
    +
    {children}
    diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 7a1876a5f61a..44ba2a5c0ffa 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -11,43 +11,49 @@ import Layout from '@theme/Layout'; import MDXContent from '@theme/MDXContent'; import type {Props} from '@theme/MDXPage'; import TOC from '@theme/TOC'; -import {ThemeClassNames} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; import styles from './styles.module.css'; export default function MDXPage(props: Props): JSX.Element { const {content: MDXPageContent} = props; const { - metadata: {title, description, permalink, frontMatter}, + metadata: {title, description, frontMatter}, } = MDXPageContent; const {wrapperClassName, hide_table_of_contents: hideTableOfContents} = frontMatter; return ( - -
    -
    -
    - - - -
    - {!hideTableOfContents && MDXPageContent.toc && ( -
    - + + + +
    +
    +
    + + +
    - )} -
    -
    -
    + {!hideTableOfContents && MDXPageContent.toc && ( +
    + +
    + )} +
    +
    +
    + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx b/packages/docusaurus-theme-classic/src/theme/NotFound.tsx index 6d4b7a0706af..2213158d52a6 100644 --- a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NotFound.tsx @@ -8,42 +8,47 @@ import React from 'react'; import Layout from '@theme/Layout'; import Translate, {translate} from '@docusaurus/Translate'; +import {PageMetadata} from '@docusaurus/theme-common'; export default function NotFound(): JSX.Element { return ( - -
    -
    -
    -

    - - Page Not Found - -

    -

    - - We could not find what you were looking for. - -

    -

    - - Please contact the owner of the site that linked you to the - original URL and let them know their link is broken. - -

    + <> + + +
    +
    +
    +

    + + Page Not Found + +

    +

    + + We could not find what you were looking for. + +

    +

    + + Please contact the owner of the site that linked you to the + original URL and let them know their link is broken. + +

    +
    -
    -
    -
    + + + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/Seo/index.tsx b/packages/docusaurus-theme-classic/src/theme/Seo/index.tsx deleted file mode 100644 index 6acdbe086465..000000000000 --- a/packages/docusaurus-theme-classic/src/theme/Seo/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React from 'react'; -import Head from '@docusaurus/Head'; -import {useTitleFormatter} from '@docusaurus/theme-common'; -import {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; - -import type {Props} from '@theme/Seo'; - -export default function Seo({ - title, - description, - keywords, - image, - children, -}: Props): JSX.Element { - const pageTitle = useTitleFormatter(title); - const {withBaseUrl} = useBaseUrlUtils(); - const pageImage = image ? withBaseUrl(image, {absolute: true}) : undefined; - - return ( - - {title && {pageTitle}} - {title && } - - {description && } - {description && } - - {keywords && ( - - )} - - {pageImage && } - {pageImage && } - - {children} - - ); -} diff --git a/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx b/packages/docusaurus-theme-classic/src/theme/SiteMetadata/index.tsx similarity index 76% rename from packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx rename to packages/docusaurus-theme-classic/src/theme/SiteMetadata/index.tsx index a3f5204ce535..e21668aa90f2 100644 --- a/packages/docusaurus-theme-classic/src/theme/LayoutHead/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/SiteMetadata/index.tsx @@ -9,19 +9,18 @@ import React from 'react'; import Head from '@docusaurus/Head'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useBaseUrl from '@docusaurus/useBaseUrl'; -import type {Props} from '@theme/Layout'; import SearchMetadata from '@theme/SearchMetadata'; -import Seo from '@theme/Seo'; import { + PageMetadata, DEFAULT_SEARCH_TAG, - useTitleFormatter, useAlternatePageUtils, useThemeConfig, keyboardFocusedClassName, } from '@docusaurus/theme-common'; import {useLocation} from '@docusaurus/router'; -// Useful for SEO +// TODO move to SiteMetadataDefaults or theme-common ? +// Useful for i18n/SEO // See https://developers.google.com/search/docs/advanced/crawling/localized-versions // See https://github.com/facebook/docusaurus/issues/3317 function AlternateLangHeaders(): JSX.Element { @@ -66,6 +65,7 @@ function useDefaultCanonicalUrl() { return siteUrl + useBaseUrl(pathname); } +// TODO move to SiteMetadataDefaults or theme-common ? function CanonicalUrlHeaders({permalink}: {permalink?: string}) { const { siteConfig: {url: siteUrl}, @@ -83,45 +83,31 @@ function CanonicalUrlHeaders({permalink}: {permalink?: string}) { ); } -export default function LayoutHead(props: Props): JSX.Element { +export default function SiteMetadata(): JSX.Element { const { - siteConfig: {favicon}, - i18n: {currentLocale, localeConfigs}, + i18n: {currentLocale}, } = useDocusaurusContext(); + + // TODO maybe move these 2 themeConfig to siteConfig? + // These seems useful for other themes as well const {metadata, image: defaultImage} = useThemeConfig(); - const {title, description, image, keywords, searchMetadata} = props; - const faviconUrl = useBaseUrl(favicon); - const pageTitle = useTitleFormatter(title); - const {htmlLang, direction: htmlDir} = localeConfigs[currentLocale]!; return ( <> - - {favicon && } - {pageTitle} - {/* The keyboard focus class name need to be applied when SSR so links are outlined when JS is disabled */} - {/* image can override the default image */} - {defaultImage && } - {image && } - - + {defaultImage && } - + element here, diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index a670df39a2b8..b479c3089a07 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -129,9 +129,10 @@ export {isRegexpStringMatch} from './utils/regexpUtils'; export {useHomePageRoute} from './utils/routesUtils'; export { + PageMetadata, HtmlClassNameProvider, PluginHtmlClassNameProvider, -} from './utils/metadataUtilsTemp'; +} from './utils/metadataUtils'; export { useColorMode, diff --git a/packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx similarity index 54% rename from packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx rename to packages/docusaurus-theme-common/src/utils/metadataUtils.tsx index f55899063b53..9de31637150e 100644 --- a/packages/docusaurus-theme-common/src/utils/metadataUtilsTemp.tsx +++ b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx @@ -9,6 +9,53 @@ import React, {type ReactNode} from 'react'; import Head from '@docusaurus/Head'; import clsx from 'clsx'; import useRouteContext from '@docusaurus/useRouteContext'; +import {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; +import {useTitleFormatter} from './generalUtils'; + +interface PageMetadataProps { + readonly title?: string; + readonly description?: string; + readonly keywords?: readonly string[] | string; + readonly image?: string; + readonly children?: ReactNode; +} + +// Helper component to manipulate page metadata and override site defaults +export function PageMetadata({ + title, + description, + keywords, + image, + children, +}: PageMetadataProps): JSX.Element { + const pageTitle = useTitleFormatter(title); + const {withBaseUrl} = useBaseUrlUtils(); + const pageImage = image ? withBaseUrl(image, {absolute: true}) : undefined; + + return ( + + {title && {pageTitle}} + {title && } + + {description && } + {description && } + + {keywords && ( + + )} + + {pageImage && } + {pageImage && } + + {children} + + ); +} const HtmlClassNameContext = React.createContext(undefined); diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx index a9227bdff42d..8ce17fa12a75 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx @@ -17,6 +17,7 @@ import Head from '@docusaurus/Head'; import Link from '@docusaurus/Link'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import { + HtmlClassNameProvider, useTitleFormatter, usePluralForm, isRegexpStringMatch, @@ -149,7 +150,7 @@ type ResultDispatcher = | {type: 'update'; value: ResultDispatcherState} | {type: 'advance'; value?: undefined}; -export default function SearchPage(): JSX.Element { +function SearchPageContent(): JSX.Element { const { siteConfig: {themeConfig}, i18n: {currentLocale}, @@ -356,7 +357,7 @@ export default function SearchPage(): JSX.Element { }, [makeSearch, searchResultState.lastPage]); return ( - + {useTitleFormatter(getTitle())} {/* @@ -516,3 +517,11 @@ export default function SearchPage(): JSX.Element { ); } + +export default function SearchPage(): JSX.Element { + return ( + + + + ); +} diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 9378463a20dd..6d434b2c6161 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -13,7 +13,9 @@ import {BrowserContextProvider} from './exports/browserContext'; import {DocusaurusContextProvider} from './exports/docusaurusContext'; import PendingNavigation from './PendingNavigation'; import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner'; +import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; +import SiteMetadata from '@theme/SiteMetadata'; import './client-lifecycles-dispatcher'; @@ -27,6 +29,8 @@ export default function App(): JSX.Element { + + {renderRoutes(routes)} diff --git a/packages/docusaurus/src/client/SiteMetadataDefaults.tsx b/packages/docusaurus/src/client/SiteMetadataDefaults.tsx new file mode 100644 index 000000000000..bd2f953aab3e --- /dev/null +++ b/packages/docusaurus/src/client/SiteMetadataDefaults.tsx @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Head from '@docusaurus/Head'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +export default function SiteMetadataDefaults(): JSX.Element { + const { + siteConfig: {favicon, tagline, title}, + i18n: {currentLocale, localeConfigs}, + } = useDocusaurusContext(); + const faviconUrl = useBaseUrl(favicon); + const {htmlLang, direction: htmlDir} = localeConfigs[currentLocale]!; + + return ( + + + {favicon && } + + ); +} diff --git a/packages/docusaurus/src/client/theme-fallback/Error/index.tsx b/packages/docusaurus/src/client/theme-fallback/Error/index.tsx index 858e42c4de37..de8ded15b7df 100644 --- a/packages/docusaurus/src/client/theme-fallback/Error/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/Error/index.tsx @@ -9,6 +9,7 @@ import React from 'react'; import Layout from '@theme/Layout'; import ErrorBoundary from '@docusaurus/ErrorBoundary'; import type {Props} from '@theme/Error'; +import Head from '@docusaurus/Head'; function ErrorDisplay({error, tryAgain}: Props): JSX.Element { return ( @@ -40,7 +41,10 @@ export default function Error({error, tryAgain}: Props): JSX.Element { // Note: we display the original error here, not the error that we // captured in this extra error boundary fallback={() => }> - + + Page Error + + diff --git a/packages/docusaurus/src/client/theme-fallback/Layout/index.tsx b/packages/docusaurus/src/client/theme-fallback/Layout/index.tsx index 1c3de03a6053..e897396623b4 100644 --- a/packages/docusaurus/src/client/theme-fallback/Layout/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/Layout/index.tsx @@ -6,31 +6,8 @@ */ import React from 'react'; -import Head from '@docusaurus/Head'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import useBaseUrl from '@docusaurus/useBaseUrl'; import type {Props} from '@theme/Layout'; -export default function Layout({ - children, - title, - description, -}: Props): JSX.Element { - const context = useDocusaurusContext(); - const {siteConfig} = context; - const {favicon, tagline, title: defaultTitle} = siteConfig; - const faviconUrl = useBaseUrl(favicon); - return ( - <> - - {title && {`${title} · ${tagline}`}} - {favicon && } - {description && } - {description && ( - - )} - - {children} - - ); +export default function Layout({children}: Props): JSX.Element { + return <>{children}; } diff --git a/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx b/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx index 48e11300f7bb..15ccfaefe6ab 100644 --- a/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx @@ -7,20 +7,26 @@ import React from 'react'; import Layout from '@theme/Layout'; +import Head from '@docusaurus/Head'; export default function NotFound(): JSX.Element { return ( - -
    -

    Oops, page not found

    -
    -
    + <> + + Page Not Found + + +
    +

    Oops, page not found

    +
    +
    + ); } diff --git a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx index 0e09dc1f4294..27ef85e88a7f 100644 --- a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx @@ -5,7 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode} from 'react'; +import React from 'react'; +import type {Props} from '@theme/Root'; // Wrapper at the very top of the app, that is applied constantly // and does not depend on current route (unlike the layout) @@ -14,6 +15,6 @@ import React, {type ReactNode} from 'react'; // and these providers won't reset state when we navigate // // See https://github.com/facebook/docusaurus/issues/3919 -export default function Root({children}: {children: ReactNode}): JSX.Element { +export default function Root({children}: Props): JSX.Element { return <>{children}; } diff --git a/packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx b/packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx new file mode 100644 index 000000000000..600acae8f23e --- /dev/null +++ b/packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx @@ -0,0 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// To be implemented by the theme with +export default function SiteMetadata(): JSX.Element | null { + return null; +} diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index 1e46aa3c5eda..a0a080259f3d 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -33,6 +33,7 @@ exports[`base webpack config creates webpack aliases 1`] = ` "@theme-original/PluginThemeComponentEnhanced": "secondPluginThemeFolder/PluginThemeComponentEnhanced.js", "@theme-original/PluginThemeComponentOverriddenByUser": "pluginThemeFolder/PluginThemeComponentOverriddenByUser.js", "@theme-original/Root": "../../../../client/theme-fallback/Root/index.tsx", + "@theme-original/SiteMetadata": "../../../../client/theme-fallback/SiteMetadata/index.tsx", "@theme-original/subfolder/PluginThemeComponent2": "pluginThemeFolder/subfolder/PluginThemeComponent2.js", "@theme/Error": "../../../../client/theme-fallback/Error/index.tsx", "@theme/Layout": "../../../../client/theme-fallback/Layout/index.tsx", @@ -42,6 +43,7 @@ exports[`base webpack config creates webpack aliases 1`] = ` "@theme/PluginThemeComponentEnhanced": "src/theme/PluginThemeComponentEnhanced.js", "@theme/PluginThemeComponentOverriddenByUser": "src/theme/PluginThemeComponentOverriddenByUser.js", "@theme/Root": "../../../../client/theme-fallback/Root/index.tsx", + "@theme/SiteMetadata": "../../../../client/theme-fallback/SiteMetadata/index.tsx", "@theme/UserThemeComponent1": "src/theme/UserThemeComponent1.js", "@theme/subfolder/PluginThemeComponent2": "pluginThemeFolder/subfolder/PluginThemeComponent2.js", "@theme/subfolder/UserThemeComponent2": "src/theme/subfolder/UserThemeComponent2.js", diff --git a/website/_dogfooding/dogfooding.css b/website/_dogfooding/dogfooding.css new file mode 100644 index 000000000000..be6cf970b6f9 --- /dev/null +++ b/website/_dogfooding/dogfooding.css @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +html.plugin-docs.plugin-id-docs-tests .red > a { + color: red; +} + +html.plugin-docs.plugin-id-docs-tests .navbar { + border-bottom: solid thin cyan; +} + +html.plugin-blog.plugin-id-blog-tests .navbar { + border-bottom: solid thin lime; +} + +html.plugin-pages.plugin-id-pages-tests .navbar { + border-bottom: solid thin yellow; +} diff --git a/website/docs/guides/creating-pages.md b/website/docs/guides/creating-pages.md index bf4c277d4a15..160b4dbf1dec 100644 --- a/website/docs/guides/creating-pages.md +++ b/website/docs/guides/creating-pages.md @@ -35,9 +35,9 @@ Create a file `/src/pages/helloReact.js`: import React from 'react'; import Layout from '@theme/Layout'; -function Hello() { +export default function Hello() { return ( - +
    ); } - -export default Hello; ``` Once you save the file, the development server will automatically reload the changes. Now open `http://localhost:3000/helloReact` and you will see the new page you just created. diff --git a/website/docs/seo.md b/website/docs/seo.md index 111560af2801..3c61f7fae51b 100644 --- a/website/docs/seo.md +++ b/website/docs/seo.md @@ -42,8 +42,30 @@ Similar to [global metadata](#global-metadata), Docusaurus also allows for the a Some content... ``` +Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter: + +```md +--- +title: Title for search engines; can be different from the actual heading +description: A short description of this page +image: a thumbnail image to be shown in social media cards +keywords: [keywords, describing, the main topics] +--- +``` + +When creating your React page, adding these fields in `Layout` would also improve SEO. + +:::tip + +Prefer to use front matter for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `` tag. + +::: + +For JSX pages, you can use the Docusaurus [``](docusaurus-core.md#head) component. + ```jsx title="my-react-page.jsx" import React from 'react'; +import Layout from '@theme/Layout'; import Head from '@docusaurus/Head'; export default function page() { @@ -58,22 +80,9 @@ export default function page() { } ``` -Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter: - -```md ---- -title: Title for search engines; can be different from the actual heading -description: A short description of this page -image: a thumbnail image to be shown in social media cards -keywords: [keywords, describing, the main topics] ---- -``` - -When creating your React page, adding these fields in `Layout` would also improve SEO. - :::tip -Prefer to use front matter for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `` tag. +For convenience, the default theme `` component accept `title` and `description` as props. ::: diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 7d029dbe2082..495072183f96 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -320,7 +320,10 @@ const config = { remarkPlugins: [npm2yarn], }, theme: { - customCss: [require.resolve('./src/css/custom.css')], + customCss: [ + require.resolve('./src/css/custom.css'), + require.resolve('./_dogfooding/dogfooding.css'), + ], }, gtag: !isDeployPreview ? { diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 8c774d3fb16b..728c5d628a99 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -166,10 +166,6 @@ div[class^='announcementBar_'] { font-weight: bold; } -.red > a { - color: red; -} - .screen-reader-only { border: 0; clip: rect(0 0 0 0); diff --git a/website/src/plugins/changelog/theme/ChangelogList/index.tsx b/website/src/plugins/changelog/theme/ChangelogList/index.tsx index 1d16dda586ab..f05400ab5756 100644 --- a/website/src/plugins/changelog/theme/ChangelogList/index.tsx +++ b/website/src/plugins/changelog/theme/ChangelogList/index.tsx @@ -9,27 +9,35 @@ import React from 'react'; import BlogLayout from '@theme/BlogLayout'; import BlogListPaginator from '@theme/BlogListPaginator'; import type {Props} from '@theme/BlogListPage'; -import {ThemeClassNames} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; import Link from '@docusaurus/Link'; import ChangelogItem from '@theme/ChangelogItem'; import styles from './styles.module.css'; +import SearchMetadata from '@theme/SearchMetadata'; +import clsx from 'clsx'; -export default function ChangelogList(props: Props): JSX.Element { +function ChangelogListMetadata(props: Props): JSX.Element { + const {metadata} = props; + const {blogTitle, blogDescription} = metadata; + return ( + <> + + + + ); +} + +function ChangelogListContent(props: Props): JSX.Element { const {metadata, items, sidebar} = props; - const {blogDescription, blogTitle} = metadata; + const {blogTitle} = metadata; return ( - +

    {blogTitle}

    @@ -88,3 +96,16 @@ export default function ChangelogList(props: Props): JSX.Element { ); } + +export default function ChangelogList(props: Props): JSX.Element { + return ( + + + + + ); +} diff --git a/website/src/plugins/changelog/theme/ChangelogPage/index.tsx b/website/src/plugins/changelog/theme/ChangelogPage/index.tsx index 355bfaa58b6c..186b4aac7c26 100644 --- a/website/src/plugins/changelog/theme/ChangelogPage/index.tsx +++ b/website/src/plugins/changelog/theme/ChangelogPage/index.tsx @@ -6,96 +6,116 @@ */ import React from 'react'; -import Seo from '@theme/Seo'; import BlogLayout from '@theme/BlogLayout'; import ChangelogItem from '@theme/ChangelogItem'; import BlogPostPaginator from '@theme/BlogPostPaginator'; import type {Props} from '@theme/BlogPostPage'; -import {ThemeClassNames} from '@docusaurus/theme-common'; +import { + PageMetadata, + HtmlClassNameProvider, + ThemeClassNames, +} from '@docusaurus/theme-common'; import TOC from '@theme/TOC'; import Link from '@docusaurus/Link'; +import clsx from 'clsx'; -// This page doesn't change anything. It's just swapping BlogPostItem with our -// own ChangelogItem. We don't want to apply the swizzled item to the actual -// blog. -export default function BlogPostPage(props: Props): JSX.Element { +function ChangelogPageMetadata(props: Props): JSX.Element { + const {content: BlogPostContents} = props; + const {assets, metadata} = BlogPostContents; + const {title, description, date, tags, authors, frontMatter} = metadata; + const {keywords} = frontMatter; + + const image = assets.image ?? frontMatter.image; + return ( + + + + + {authors.some((author) => author.url) && ( + author.url) + .filter(Boolean) + .join(',')} + /> + )} + {tags.length > 0 && ( + tag.label).join(',')} + /> + )} + + ); +} + +function ChangelogPageContent(props: Props): JSX.Element { const {content: BlogPostContents, sidebar} = props; const {assets, metadata} = BlogPostContents; const { - title, - description, nextItem, prevItem, - date, - tags, - authors, frontMatter, // @ts-expect-error: we injected this listPageLink, } = metadata; const { hide_table_of_contents: hideTableOfContents, - keywords, toc_min_heading_level: tocMinHeadingLevel, toc_max_heading_level: tocMaxHeadingLevel, } = frontMatter; - const image = assets.image ?? frontMatter.image; - return ( - 0 ? ( - - ) : undefined - }> - - - + <> + + 0 ? ( + + ) : undefined + }> + ← Back to index page - {authors.some((author) => author.url) && ( - author.url) - .filter(Boolean) - .join(',')} - /> - )} - {tags.length > 0 && ( - tag.label).join(',')} - /> - )} - + + + - ← Back to index page - - - - + {(nextItem || prevItem) && ( + + )} + + + ); +} - {(nextItem || prevItem) && ( - - )} - +// This page doesn't change anything. It's just swapping BlogPostItem with our +// own ChangelogItem. We don't want to apply the swizzled item to the actual +// blog. +export default function ChangelogPage(props: Props): JSX.Element { + return ( + + + + ); } From 53f152c42d69760cbee11e6741e9542b533fd937 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 19 Mar 2022 09:30:31 +0800 Subject: [PATCH 032/405] refactor(core): improve error message when a page has no default-export (#6941) --- .../src/client/exports/ComponentCreator.tsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 80d2f585c66a..4c610305a733 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -75,21 +75,23 @@ export default function ComponentCreator( // Clone the original object since we don't want to alter the original. const loadedModules = JSON.parse(JSON.stringify(chunkNames)); Object.keys(loaded).forEach((key) => { + const newComp = loaded[key].default; + if (!newComp) { + throw new Error( + `The page component at ${path} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`, + ); + } + Object.keys(loaded[key]) + .filter((k) => k !== 'default') + .forEach((nonDefaultKey) => { + newComp[nonDefaultKey] = loaded[key][nonDefaultKey]; + }); let val = loadedModules; const keyPath = key.split('.'); keyPath.slice(0, -1).forEach((k) => { val = val[k]; }); - val[keyPath[keyPath.length - 1]!] = loaded[key].default; - const nonDefaultKeys = Object.keys(loaded[key]).filter( - (k) => k !== 'default', - ); - if (nonDefaultKeys?.length) { - nonDefaultKeys.forEach((nonDefaultKey) => { - val[keyPath[keyPath.length - 1]!][nonDefaultKey] = - loaded[key][nonDefaultKey]; - }); - } + val[keyPath[keyPath.length - 1]!] = newComp; }); const Component = loadedModules.component; From 19942f990ab3ede56a0e61b70e72e221ddce23d2 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 19 Mar 2022 20:56:30 +0800 Subject: [PATCH 033/405] chore: migrate Jest and website to SWC (#6944) * chore: migrate Jest and website to SWC * ignore template --- .eslintignore | 2 +- babel.config.js | 21 -- jest.config.mjs | 2 +- package.json | 2 + .../src/utils/reactUtils.tsx | 3 +- .../src/client/exports/ComponentCreator.tsx | 15 +- website/docusaurus.config.js | 14 +- website/package.json | 3 +- yarn.lock | 258 +++++++----------- 9 files changed, 134 insertions(+), 186 deletions(-) delete mode 100644 babel.config.js diff --git a/.eslintignore b/.eslintignore index d870ab973046..f8b4a50d08ab 100644 --- a/.eslintignore +++ b/.eslintignore @@ -16,6 +16,6 @@ packages/stylelint-copyright/lib/ copyUntypedFiles.mjs packages/create-docusaurus/lib/* -packages/create-docusaurus/templates/facebook/.eslintrc.js +packages/create-docusaurus/templates/facebook website/_dogfooding/_swizzle_theme_tests diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 67cf053df30d..000000000000 --- a/babel.config.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = { - presets: [ - [ - '@babel/env', - { - targets: { - node: 'current', - }, - }, - ], - '@babel/react', - '@babel/preset-typescript', - ], -}; diff --git a/jest.config.mjs b/jest.config.mjs index d973ca87d2de..09725a8e36c6 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -30,7 +30,7 @@ export default { testPathIgnorePatterns: ignorePatterns, coveragePathIgnorePatterns: ignorePatterns, transform: { - '^.+\\.[jt]sx?$': 'babel-jest', + '^.+\\.[jt]sx?$': '@swc/jest', }, errorOnDeprecated: true, moduleNameMapper: { diff --git a/package.json b/package.json index fb186a2b162a..894d265b87e5 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,8 @@ "@babel/core": "^7.17.7", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", + "@swc/core": "^1.2.158", + "@swc/jest": "^0.2.20", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", diff --git a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx index ae34933d1b00..e1555c17506b 100644 --- a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx @@ -47,7 +47,8 @@ export class ReactContextError extends Error { super(); this.name = 'ReactContextError'; this.message = `Hook ${ - this.stack?.split('\n')[1]?.match(/at (?\w+)/)?.groups!.name + this.stack?.split('\n')[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups! + .name } is called outside the <${providerName}>. ${additionalInfo || ''}`; } } diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 4c610305a733..b33b8cff35ed 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -62,7 +62,8 @@ export default function ComponentCreator( if (chunkRegistry) { // eslint-disable-next-line prefer-destructuring optsLoader[key] = chunkRegistry[0]; - optsModules.push(chunkRegistry[1], chunkRegistry[2]); + optsModules.push(chunkRegistry[1]); + optsWebpack.push(chunkRegistry[2]); } }); @@ -81,11 +82,13 @@ export default function ComponentCreator( `The page component at ${path} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`, ); } - Object.keys(loaded[key]) - .filter((k) => k !== 'default') - .forEach((nonDefaultKey) => { - newComp[nonDefaultKey] = loaded[key][nonDefaultKey]; - }); + if (typeof newComp === 'object' || typeof newComp === 'function') { + Object.keys(loaded[key]) + .filter((k) => k !== 'default') + .forEach((nonDefaultKey) => { + newComp[nonDefaultKey] = loaded[key][nonDefaultKey]; + }); + } let val = loadedModules; const keyPath = key.split('.'); keyPath.slice(0, -1).forEach((k) => { diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 495072183f96..775ada764646 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -94,10 +94,18 @@ const config = { }, webpack: { jsLoader: (isServer) => ({ - loader: require.resolve('esbuild-loader'), + loader: require.resolve('swc-loader'), options: { - loader: 'tsx', - target: isServer ? 'node12' : 'es2017', + jsc: { + "parser": { + "syntax": "typescript", + "tsx": true + }, + target: 'es2017', + }, + module: { + type: isServer ? 'commonjs' : 'es6', + } }, }), }, diff --git a/website/package.json b/website/package.json index 71a07a2fb62c..f5df211f8c05 100644 --- a/website/package.json +++ b/website/package.json @@ -49,9 +49,9 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-common": "2.0.0-beta.17", "@popperjs/core": "^2.11.4", + "@swc/core": "^1.2.158", "clsx": "^1.1.1", "color": "^4.2.1", - "esbuild-loader": "2.18.0", "fs-extra": "^10.0.1", "netlify-plugin-cache": "^1.0.3", "raw-loader": "^4.0.2", @@ -61,6 +61,7 @@ "react-popper": "^2.2.5", "rehype-katex": "^6.0.2", "remark-math": "^3.0.1", + "swc-loader": "^0.1.15", "unist-util-visit": "^2.0.2", "workbox-routing": "^6.5.1", "workbox-strategies": "^6.5.1" diff --git a/yarn.lock b/yarn.lock index c75c67a3a997..039857635dc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1751,6 +1751,13 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/create-cache-key-function@^27.4.2": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz#7448fae15602ea95c828f5eceed35c202a820b31" + integrity sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ== + dependencies: + "@jest/types" "^27.5.1" + "@jest/environment@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" @@ -3579,6 +3586,97 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" +"@swc/core-android-arm-eabi@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.158.tgz#c850b614854da8e58e27cf51390bee656f093cc7" + integrity sha512-8RHlMo9+N8V5EE/2VOCF9H9DU3s3rj6SIRpTnQbIaJlZNwqCHp+q8xQGfKEFTrY2GShhFa/vN+w279gl2NXA+g== + +"@swc/core-android-arm64@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.158.tgz#62764c3f509df24c6f504827d2cb7adad8a2f634" + integrity sha512-lfSUGzIjIvyj9sMtvnL6VPuC0XryfVCs3Fsvzbk4H0bi3nSDYFmVbpBvXZFhd60lcw1bcOFepBfi70LFmnhHTQ== + +"@swc/core-darwin-arm64@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.158.tgz#64ef42f32b06c64c61d2648a5bbca8766338197c" + integrity sha512-vrdITsJjbx7lVN43Aq//gT+NRSdxS1+KxC6EiOct3qLcQA+P7w1nehZnlR+4qRLCgbBmQZQeeNnInaKpm9G7+g== + +"@swc/core-darwin-x64@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.158.tgz#0ca64b3d244771e4d99a1555c4e9052dbe63d00f" + integrity sha512-+SIZgX01YEbTTClVdbc4aNR4dDsIVP+JiXxH1Zq5JYSsGxXzunRBMYcmTxnxRK2RHY1wOsLMD8AT5lZqQK6jsg== + +"@swc/core-freebsd-x64@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.158.tgz#f0609f2f4c9d5bde24f6ab4b061ee42fbaec85f5" + integrity sha512-a+dF5T+Wi95E5IrMlHdGVETUgFkeL2roFT7cfjfWokR8UudD40kYkr8dxOBFizeIvgoeQdQ0hnJJl1dASL/ydA== + +"@swc/core-linux-arm-gnueabihf@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.158.tgz#c166c42e6c07b1f1c273b4034d40ce486a23ef00" + integrity sha512-+B/WYr8RRe6YcCUAfD8r/p2rGrxEEDud2MXxbAS3OMYuSYrFzfOxqKzCd6rQ7/OTXpTpapg0yctvhzOyArtAZw== + +"@swc/core-linux-arm64-gnu@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.158.tgz#597577dda702400f5f5d4cf49b32bb3fa6017835" + integrity sha512-QNTs6g9VYMF4UxRnSCMe7TRAPgCdsaUbHeWhaRtRE2nfKN4fd0YYPOzODEi7P3mvLW5p75FlHtRWokaME/J1HA== + +"@swc/core-linux-arm64-musl@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.158.tgz#fb8e9aadace980eaa408596edb78090b20f4d982" + integrity sha512-dylgrtZQJIZ6JfRDL87sPdXlOew/hl5VQaIjjhN6hu+tuRmAHzyN50DJIioErMxqFFaxnqJCxMZUFX0AlPwEKg== + +"@swc/core-linux-x64-gnu@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.158.tgz#190113e5afa441e20db60d67ea1926ed1f9e1ae6" + integrity sha512-f+l13OggHhdlk3va4tol7KxHm3kt1QPusLZJpVh00OENqXV6Wuv3Xh1BMgv5XMy6oXfOUdrXcPi3GWWi8079XA== + +"@swc/core-linux-x64-musl@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.158.tgz#72894115ea3af335be0ec530c00aea88ce4fa298" + integrity sha512-+TuNuzCBkDfoZKaaeqUrDdEANc3iVS8TYQgutHokSu6FCcNd9OGCm81SXknmYuDMtqYGs1LwVNMwCV7YOWEsiA== + +"@swc/core-win32-arm64-msvc@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.158.tgz#5569523a0b2758d62e65319433e2228ace4cc64e" + integrity sha512-GXfOgEgqWdrol6dpseLXQL9RkRy6TSBMULtwpxwH5uf1jwAAZaMBsd+JemvhW0OjbIX0P9M19hdvQYtxuYxvrg== + +"@swc/core-win32-ia32-msvc@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.158.tgz#18f0b6cb1b6343a127b9da24904b3d1b1283db82" + integrity sha512-Z/KIIgJrI2lXm+S/vRmYLcanOTvvxWq929ggjgY93m3zWrHjsWGVFoelbn2xLRUOtI/u0qna6DovLHhC4KcuBw== + +"@swc/core-win32-x64-msvc@1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.158.tgz#1f52b172617f62892afab6bfa8d624e99fa26964" + integrity sha512-h0jGYJmcNFhOinLT9vNE95DZfGtxROv9eDD+b5vMz03rvli5EUEUSkQ2MPDMuezHmL/P+cpKfVc/WGWWWXpfuQ== + +"@swc/core@^1.2.158": + version "1.2.158" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.158.tgz#aba1421d16fc9cdda8e09872776957dcdae70917" + integrity sha512-EBTuqLC2CRd4HN2CSbe+z0QoYdMCGZV2GqUvco0s2pqcNSssrWAZj6xozcJOQ5VeUsYRVdKro2muMAWdNe7qug== + optionalDependencies: + "@swc/core-android-arm-eabi" "1.2.158" + "@swc/core-android-arm64" "1.2.158" + "@swc/core-darwin-arm64" "1.2.158" + "@swc/core-darwin-x64" "1.2.158" + "@swc/core-freebsd-x64" "1.2.158" + "@swc/core-linux-arm-gnueabihf" "1.2.158" + "@swc/core-linux-arm64-gnu" "1.2.158" + "@swc/core-linux-arm64-musl" "1.2.158" + "@swc/core-linux-x64-gnu" "1.2.158" + "@swc/core-linux-x64-musl" "1.2.158" + "@swc/core-win32-arm64-msvc" "1.2.158" + "@swc/core-win32-ia32-msvc" "1.2.158" + "@swc/core-win32-x64-msvc" "1.2.158" + +"@swc/jest@^0.2.20": + version "0.2.20" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.20.tgz#2bddb4348fb730296b86cdcd96748be131b11395" + integrity sha512-5qSUBYY1wyIMn7p0Vl9qqV4hMI69oJwZCIPUpBsTFWN2wlwn6RDugzdgCn+bLXVYh+Cxi8bJcZ1uumDgsoL+FA== + dependencies: + "@jest/create-cache-key-function" "^27.4.2" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -8160,144 +8258,6 @@ es6-promisify@^6.0.0: resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621" integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg== -esbuild-android-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.27.tgz#b868bbd9955a92309c69df628d8dd1945478b45c" - integrity sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ== - -esbuild-android-arm64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.27.tgz#e7d6430555e8e9c505fd87266bbc709f25f1825c" - integrity sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ== - -esbuild-darwin-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.27.tgz#4dc7484127564e89b4445c0a560a3cb50b3d68e1" - integrity sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g== - -esbuild-darwin-arm64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.27.tgz#469e59c665f84a8ed323166624c5e7b9b2d22ac1" - integrity sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ== - -esbuild-freebsd-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.27.tgz#895df03bf5f87094a56c9a5815bf92e591903d70" - integrity sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA== - -esbuild-freebsd-arm64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.27.tgz#0b72a41a6b8655e9a8c5608f2ec1afdcf6958441" - integrity sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA== - -esbuild-linux-32@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.27.tgz#43b8ba3803b0bbe7f051869c6a8bf6de1e95de28" - integrity sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw== - -esbuild-linux-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.27.tgz#dc8072097327ecfadba1735562824ce8c05dd0bd" - integrity sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg== - -esbuild-linux-arm64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.27.tgz#c52b58cbe948426b1559910f521b0a3f396f10b8" - integrity sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ== - -esbuild-linux-arm@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.27.tgz#df869dbd67d4ee3a04b3c7273b6bd2b233e78a18" - integrity sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw== - -esbuild-linux-mips64le@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.27.tgz#a2b646d9df368b01aa970a7b8968be6dd6b01d19" - integrity sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A== - -esbuild-linux-ppc64le@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.27.tgz#9a21af766a0292578a3009c7408b8509cac7cefd" - integrity sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA== - -esbuild-linux-riscv64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.27.tgz#344a27f91568056a5903ad5841b447e00e78d740" - integrity sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg== - -esbuild-linux-s390x@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.27.tgz#73a7309bd648a07ef58f069658f989a5096130db" - integrity sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg== - -esbuild-loader@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.18.0.tgz#7b9548578ab954574fd94655693d22aa5ec74120" - integrity sha512-AKqxM3bI+gvGPV8o6NAhR+cBxVO8+dh+O0OXBHIXXwuSGumckbPWHzZ17subjBGI2YEGyJ1STH7Haj8aCrwL/w== - dependencies: - esbuild "^0.14.6" - joycon "^3.0.1" - json5 "^2.2.0" - loader-utils "^2.0.0" - tapable "^2.2.0" - webpack-sources "^2.2.0" - -esbuild-netbsd-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.27.tgz#482a587cdbd18a6c264a05136596927deb46c30a" - integrity sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q== - -esbuild-openbsd-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.27.tgz#e99f8cdc63f1628747b63edd124d53cf7796468d" - integrity sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw== - -esbuild-sunos-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.27.tgz#8611d825bcb8239c78d57452e83253a71942f45c" - integrity sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg== - -esbuild-windows-32@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.27.tgz#c06374206d4d92dd31d4fda299b09f51a35e82f6" - integrity sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw== - -esbuild-windows-64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.27.tgz#756631c1d301dfc0d1a887deed2459ce4079582f" - integrity sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg== - -esbuild-windows-arm64@0.14.27: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.27.tgz#ad7e187193dcd18768b16065a950f4441d7173f4" - integrity sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg== - -esbuild@^0.14.6: - version "0.14.27" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.27.tgz#41fe0f1b6b68b9f77cac025009bc54bb96e616f1" - integrity sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q== - optionalDependencies: - esbuild-android-64 "0.14.27" - esbuild-android-arm64 "0.14.27" - esbuild-darwin-64 "0.14.27" - esbuild-darwin-arm64 "0.14.27" - esbuild-freebsd-64 "0.14.27" - esbuild-freebsd-arm64 "0.14.27" - esbuild-linux-32 "0.14.27" - esbuild-linux-64 "0.14.27" - esbuild-linux-arm "0.14.27" - esbuild-linux-arm64 "0.14.27" - esbuild-linux-mips64le "0.14.27" - esbuild-linux-ppc64le "0.14.27" - esbuild-linux-riscv64 "0.14.27" - esbuild-linux-s390x "0.14.27" - esbuild-netbsd-64 "0.14.27" - esbuild-openbsd-64 "0.14.27" - esbuild-sunos-64 "0.14.27" - esbuild-windows-32 "0.14.27" - esbuild-windows-64 "0.14.27" - esbuild-windows-arm64 "0.14.27" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -11825,11 +11785,6 @@ joi@^17.6.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" -joycon@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - jpeg-js@0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" @@ -17352,7 +17307,7 @@ sort-keys@^4.0.0: dependencies: is-plain-obj "^2.0.0" -source-list-map@^2.0.0, source-list-map@^2.0.1: +source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -18040,6 +17995,13 @@ svgo@^2.5.0, svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" +swc-loader@^0.1.15: + version "0.1.15" + resolved "https://registry.yarnpkg.com/swc-loader/-/swc-loader-0.1.15.tgz#cb9c630ccfbb46dabc5aebc5560cced658e32992" + integrity sha512-cn1WPIeQJvXM4bbo3OwdEIapsQ4uUGOfyFj0h2+2+brT0k76DCGnZXDE2KmcqTd2JSQ+b61z2NPMib7eEwMYYw== + dependencies: + loader-utils "^2.0.0" + symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -19490,14 +19452,6 @@ webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" - integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" From 92fcc0ddc5011252b9333e91b7f6eb10a75a8161 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Sat, 19 Mar 2022 21:21:11 +0800 Subject: [PATCH 034/405] docs: add SeaORM docs to showcase (#6943) * Add SeaORM docs to showcase * minor tweak Co-authored-by: Joshua Chen --- website/src/data/showcase/SeaORM.png | Bin 0 -> 37393 bytes website/src/data/users.tsx | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 website/src/data/showcase/SeaORM.png diff --git a/website/src/data/showcase/SeaORM.png b/website/src/data/showcase/SeaORM.png new file mode 100644 index 0000000000000000000000000000000000000000..4afe4e5bd2eecd680de367ee2a4972a59af3c9cd GIT binary patch literal 37393 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 Date: Mon, 21 Mar 2022 07:45:29 +0800 Subject: [PATCH 035/405] chore: upgrade dependencies (#6946) * chore: upgrade dependencies * reformat --- admin/new.docusaurus.io/package.json | 2 +- package.json | 18 +- .../templates/classic/package.json | 2 +- .../templates/facebook/package.json | 4 +- .../docusaurus-cssnano-preset/package.json | 4 +- packages/docusaurus-mdx-loader/package.json | 2 +- packages/docusaurus-plugin-pwa/package.json | 2 +- .../docusaurus-theme-classic/package.json | 2 +- .../package.json | 2 +- packages/docusaurus-utils/package.json | 2 +- packages/docusaurus/package.json | 10 +- .../docusaurus/src/client/LinksCollector.tsx | 2 +- .../docusaurus/src/client/serverEntry.tsx | 6 +- packages/stylelint-copyright/package.json | 2 +- website/package.json | 2 +- website/src/data/tweets.tsx | 6 +- yarn.lock | 507 +++++++++--------- 17 files changed, 294 insertions(+), 281 deletions(-) diff --git a/admin/new.docusaurus.io/package.json b/admin/new.docusaurus.io/package.json index 0bb4203a14e0..7da6bb95baca 100644 --- a/admin/new.docusaurus.io/package.json +++ b/admin/new.docusaurus.io/package.json @@ -9,6 +9,6 @@ "@netlify/functions": "^1.0.0" }, "devDependencies": { - "netlify-cli": "^9.13.1" + "netlify-cli": "^9.13.3" } } diff --git a/package.json b/package.json index 894d265b87e5..792f0c0d76e6 100644 --- a/package.json +++ b/package.json @@ -61,10 +61,10 @@ }, "devDependencies": { "@babel/cli": "^7.17.6", - "@babel/core": "^7.17.7", + "@babel/core": "^7.17.8", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", - "@swc/core": "^1.2.158", + "@swc/core": "^1.2.159", "@swc/jest": "^0.2.20", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", @@ -72,7 +72,7 @@ "@types/lodash": "^4.14.180", "@types/node": "^17.0.21", "@types/prompts": "^2.0.14", - "@types/react": "^17.0.40", + "@types/react": "^17.0.41", "@types/react-dev-utils": "^9.0.10", "@types/react-test-renderer": "^17.0.1", "@types/semver": "^7.3.9", @@ -87,27 +87,27 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^26.1.1", + "eslint-plugin-jest": "^26.1.2", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-regexp": "^1.5.1", + "eslint-plugin-regexp": "^1.6.0", "husky": "^7.0.4", "image-size": "^1.0.1", "jest": "^27.5.1", "lerna": "^4.0.0", "lerna-changelog": "^2.2.0", - "lint-staged": "^12.3.5", - "netlify-cli": "^9.13.1", + "lint-staged": "^12.3.7", + "netlify-cli": "^9.13.3", "nodemon": "^2.0.15", - "prettier": "^2.5.1", + "prettier": "^2.6.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-test-renderer": "^17.0.2", "remark-parse": "^8.0.2", "rimraf": "^3.0.2", "sharp": "^0.30.3", - "stylelint": "^14.5.3", + "stylelint": "^14.6.0", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard": "^25.0.0", "typescript": "^4.6.2", diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index b70d0a701a9c..b2e3ecb8df4c 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -18,7 +18,7 @@ "@docusaurus/preset-classic": "2.0.0-beta.17", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "prism-react-renderer": "^1.2.1", + "prism-react-renderer": "^1.3.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/create-docusaurus/templates/facebook/package.json b/packages/create-docusaurus/templates/facebook/package.json index 5941d4e692a6..2c547bd44f61 100644 --- a/packages/create-docusaurus/templates/facebook/package.json +++ b/packages/create-docusaurus/templates/facebook/package.json @@ -35,8 +35,8 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", - "prettier": "^2.5.1", - "stylelint": "^14.5.3" + "prettier": "^2.6.0", + "stylelint": "^14.6.0" }, "browserslist": { "production": [ diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index e5e13b73ce26..cbf900d5c1aa 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -13,8 +13,8 @@ "directory": "packages/docusaurus-cssnano-preset" }, "dependencies": { - "cssnano-preset-advanced": "^5.2.5", - "postcss": "^8.4.8", + "cssnano-preset-advanced": "^5.3.0", + "postcss": "^8.4.12", "postcss-sort-media-queries": "^4.2.1" }, "devDependencies": { diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 9ad42c9bd073..0472d7bfefb8 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -18,7 +18,7 @@ }, "license": "MIT", "dependencies": { - "@babel/parser": "^7.17.7", + "@babel/parser": "^7.17.8", "@babel/traverse": "^7.17.3", "@docusaurus/logger": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json index b66eea65c0f0..13559f33a9c8 100644 --- a/packages/docusaurus-plugin-pwa/package.json +++ b/packages/docusaurus-plugin-pwa/package.json @@ -20,7 +20,7 @@ }, "license": "MIT", "dependencies": { - "@babel/core": "^7.17.7", + "@babel/core": "^7.17.8", "@babel/preset-env": "^7.16.11", "@docusaurus/core": "2.0.0-beta.17", "@docusaurus/theme-common": "2.0.0-beta.17", diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index ae8f256083ee..5abc72141fc9 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -35,7 +35,7 @@ "copy-text-to-clipboard": "^3.0.1", "infima": "0.2.0-alpha.37", "lodash": "^4.17.21", - "postcss": "^8.4.8", + "postcss": "^8.4.12", "prism-react-renderer": "^1.3.1", "prismjs": "^1.27.0", "react-router-dom": "^5.2.0", diff --git a/packages/docusaurus-theme-search-algolia/package.json b/packages/docusaurus-theme-search-algolia/package.json index 72fd74d48ec2..272032d0cb24 100644 --- a/packages/docusaurus-theme-search-algolia/package.json +++ b/packages/docusaurus-theme-search-algolia/package.json @@ -34,7 +34,7 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-validation": "2.0.0-beta.17", "algoliasearch": "^4.13.0", - "algoliasearch-helper": "^3.7.0", + "algoliasearch-helper": "^3.7.3", "clsx": "^1.1.1", "eta": "^1.12.3", "fs-extra": "^10.0.1", diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index 92139190d892..1988edc6155c 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -42,7 +42,7 @@ "@types/dedent": "^0.7.0", "@types/github-slugger": "^1.3.0", "@types/micromatch": "^4.0.2", - "@types/react-dom": "^17.0.13", + "@types/react-dom": "^17.0.14", "dedent": "^0.7.0" } } diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 763c9fd1d8c7..ecd5ad45236c 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -31,14 +31,14 @@ "url": "https://github.com/facebook/docusaurus/issues" }, "dependencies": { - "@babel/core": "^7.17.7", + "@babel/core": "^7.17.8", "@babel/generator": "^7.17.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", - "@babel/runtime": "^7.17.7", + "@babel/runtime": "^7.17.8", "@babel/runtime-corejs3": "^7.17.7", "@babel/traverse": "^7.17.3", "@docusaurus/cssnano-preset": "2.0.0-beta.17", @@ -50,7 +50,7 @@ "@docusaurus/utils-validation": "2.0.0-beta.17", "@slorber/static-site-generator-webpack-plugin": "^4.0.1", "@svgr/webpack": "^6.2.1", - "autoprefixer": "^10.4.2", + "autoprefixer": "^10.4.4", "babel-loader": "^8.2.3", "babel-plugin-dynamic-import-node": "2.3.0", "boxen": "^6.2.1", @@ -79,7 +79,7 @@ "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.6.0", "nprogress": "^0.2.0", - "postcss": "^8.4.8", + "postcss": "^8.4.12", "postcss-loader": "^6.2.1", "prompts": "^2.4.2", "react-dev-utils": "^12.0.0", @@ -110,7 +110,7 @@ "@docusaurus/types": "2.0.0-beta.17", "@types/detect-port": "^1.3.2", "@types/nprogress": "^0.2.0", - "@types/react-dom": "^17.0.13", + "@types/react-dom": "^17.0.14", "@types/react-router-config": "^5.0.6", "@types/rtl-detect": "^1.0.0", "@types/serve-handler": "^6.1.1", diff --git a/packages/docusaurus/src/client/LinksCollector.tsx b/packages/docusaurus/src/client/LinksCollector.tsx index 33580a6e8240..2df9a8618a2a 100644 --- a/packages/docusaurus/src/client/LinksCollector.tsx +++ b/packages/docusaurus/src/client/LinksCollector.tsx @@ -35,7 +35,7 @@ const Context = React.createContext({ export const useLinksCollector = (): LinksCollector => useContext(Context); -export function ProvideLinksCollector({ +export function LinksCollectorProvider({ children, linksCollector, }: { diff --git a/packages/docusaurus/src/client/serverEntry.tsx b/packages/docusaurus/src/client/serverEntry.tsx index f35df05ca5bb..5c6bccdc2474 100644 --- a/packages/docusaurus/src/client/serverEntry.tsx +++ b/packages/docusaurus/src/client/serverEntry.tsx @@ -21,7 +21,7 @@ import preload from './preload'; import App from './App'; import { createStatefulLinksCollector, - ProvideLinksCollector, + LinksCollectorProvider, } from './LinksCollector'; import logger from '@docusaurus/logger'; // eslint-disable-next-line no-restricted-imports @@ -86,9 +86,9 @@ async function doRender(locals: Locals & {path: string}) { modules.add(moduleName)}> - + - + , diff --git a/packages/stylelint-copyright/package.json b/packages/stylelint-copyright/package.json index 820fa9449f91..f3413ee227f8 100644 --- a/packages/stylelint-copyright/package.json +++ b/packages/stylelint-copyright/package.json @@ -11,6 +11,6 @@ "directory": "packages/stylelint-copyright" }, "dependencies": { - "stylelint": "^14.5.3" + "stylelint": "^14.6.0" } } diff --git a/website/package.json b/website/package.json index f5df211f8c05..aeb0c1f833da 100644 --- a/website/package.json +++ b/website/package.json @@ -49,7 +49,7 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-common": "2.0.0-beta.17", "@popperjs/core": "^2.11.4", - "@swc/core": "^1.2.158", + "@swc/core": "^1.2.159", "clsx": "^1.1.1", "color": "^4.2.1", "fs-extra": "^10.0.1", diff --git a/website/src/data/tweets.tsx b/website/src/data/tweets.tsx index d2f12cbcb6a2..9656e1a5747b 100644 --- a/website/src/data/tweets.tsx +++ b/website/src/data/tweets.tsx @@ -336,9 +336,9 @@ const TWEETS: TweetItem[] = [ content: ( <> The new website has landed 🚀 powered by @docusaurus v2 and made - by @_semoal kudos to him 👏 #verdaccio #nodejs awesome contribution - ❤️‍🔥 (video made with react remotion @JNYBGR ) all Open Source and - hosted on @Netlify https://verdaccio.org + by @_semoal kudos to him 👏 #verdaccio #nodejs awesome contribution ❤️‍🔥 + (video made with react remotion @JNYBGR ) all Open Source and hosted on + @Netlify https://verdaccio.org ), showOnHomepage: false, diff --git a/yarn.lock b/yarn.lock index 039857635dc6..71562635423e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -197,18 +197,18 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.4", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.15.5", "@babel/core@^7.17.7", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.7.tgz#f7c28228c83cdf2dbd1b9baa06eaf9df07f0c2f9" - integrity sha512-djHlEfFHnSnTAcPb7dATbiM5HxGOP98+3JLBZtjRb5I7RXrw7kFRoG2dXM8cm3H+o11A8IFH/uprmJpwFynRNQ== +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.4", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.15.5", "@babel/core@^7.17.8", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" "@babel/generator" "^7.17.7" "@babel/helper-compilation-targets" "^7.17.7" "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.7" - "@babel/parser" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -439,10 +439,10 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.7.tgz#6fc0a24280fd00026e85424bbfed4650e76d7127" - integrity sha512-TKsj9NkjJfTBxM7Phfy7kv6yYc4ZcOo+AaWGqQOKTPDOmcGkIFb5xNA746eKisQkm4yavUYh4InYM9S+VnO01w== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" @@ -462,10 +462,10 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw== -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.7.tgz#fc19b645a5456c8d6fdb6cecd3c66c0173902800" - integrity sha512-bm3AQf45vR4gKggRfvJdYJ0gFLoCbsPxiFLSH6hTVYABptNHY6l9NrhnucVjQ/X+SPtLANT9lc0fFhikj+VBRA== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -899,12 +899,12 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" - integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== dependencies: "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" @@ -1212,17 +1212,17 @@ source-map-support "^0.5.16" "@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.7.tgz#cf914f474c490ef1aa8661d47adaa0a993636e7e" - integrity sha512-TvliGJjhxis5m7xIMvlXH/xG8Oa/LK0SCUCyfKD6nLi42n5fB4WibDJ0g9trmmBB6hwpMNx+Lzbxy9/4gpMaVw== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" + integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== dependencies: core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.7", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" - integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" @@ -2750,10 +2750,10 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@netlify/build@^26.4.0": - version "26.4.0" - resolved "https://registry.yarnpkg.com/@netlify/build/-/build-26.4.0.tgz#ae18c0117a28e3cd837b1fd215b69de5457939c3" - integrity sha512-Xr4HR7gr+B34x8WwFcFU8+AOVoaPkWBchhPH9K+hJggzFf9CyCodMMwHo5+obkg6aNJtVcGQZTmZXtI9Tu8twQ== +"@netlify/build@^26.5.0": + version "26.5.0" + resolved "https://registry.yarnpkg.com/@netlify/build/-/build-26.5.0.tgz#f5fa412e917a348c70bce6e0c19fab33ea20dfd4" + integrity sha512-aF6H6CnWcggf5ObDYMzreGq9tKtny95Ys9GhxCMxoQxfhcw3kab984Xj1epk3wlKNt1vJbZ3bndlme3LDG/cOg== dependencies: "@bugsnag/js" "^7.0.0" "@netlify/cache-utils" "^4.0.0" @@ -3004,10 +3004,10 @@ rollup-plugin-node-polyfills "^0.2.1" rollup-plugin-terser "^7.0.2" -"@netlify/plugins-list@^6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.16.0.tgz#9a7b917af5a741f5145ed1bf480bffec895468b6" - integrity sha512-wfPmtfHW7WY6oivVfkHY6yo2hiMjvsP97/vKIn+mzpjmua+nCC3aIfbU+JJGnH8HwKq7UAbC2bwLNQhvQdYsuQ== +"@netlify/plugins-list@^6.16.0", "@netlify/plugins-list@^6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.16.1.tgz#6e8ba9fad984133c4492959a054b93e5a61537f8" + integrity sha512-DCgAJvCniSmXghDVvWSa5dgAWYVpOUfRLTVvv0V/GXDd1VkvpHtmZ0FD+AE8hxqSfmY8FLuagh6USi8xeBfwaA== "@netlify/routing-local-proxy-darwin-arm64@^0.34.1": version "0.34.1" @@ -3586,89 +3586,89 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" -"@swc/core-android-arm-eabi@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.158.tgz#c850b614854da8e58e27cf51390bee656f093cc7" - integrity sha512-8RHlMo9+N8V5EE/2VOCF9H9DU3s3rj6SIRpTnQbIaJlZNwqCHp+q8xQGfKEFTrY2GShhFa/vN+w279gl2NXA+g== - -"@swc/core-android-arm64@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.158.tgz#62764c3f509df24c6f504827d2cb7adad8a2f634" - integrity sha512-lfSUGzIjIvyj9sMtvnL6VPuC0XryfVCs3Fsvzbk4H0bi3nSDYFmVbpBvXZFhd60lcw1bcOFepBfi70LFmnhHTQ== - -"@swc/core-darwin-arm64@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.158.tgz#64ef42f32b06c64c61d2648a5bbca8766338197c" - integrity sha512-vrdITsJjbx7lVN43Aq//gT+NRSdxS1+KxC6EiOct3qLcQA+P7w1nehZnlR+4qRLCgbBmQZQeeNnInaKpm9G7+g== - -"@swc/core-darwin-x64@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.158.tgz#0ca64b3d244771e4d99a1555c4e9052dbe63d00f" - integrity sha512-+SIZgX01YEbTTClVdbc4aNR4dDsIVP+JiXxH1Zq5JYSsGxXzunRBMYcmTxnxRK2RHY1wOsLMD8AT5lZqQK6jsg== - -"@swc/core-freebsd-x64@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.158.tgz#f0609f2f4c9d5bde24f6ab4b061ee42fbaec85f5" - integrity sha512-a+dF5T+Wi95E5IrMlHdGVETUgFkeL2roFT7cfjfWokR8UudD40kYkr8dxOBFizeIvgoeQdQ0hnJJl1dASL/ydA== - -"@swc/core-linux-arm-gnueabihf@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.158.tgz#c166c42e6c07b1f1c273b4034d40ce486a23ef00" - integrity sha512-+B/WYr8RRe6YcCUAfD8r/p2rGrxEEDud2MXxbAS3OMYuSYrFzfOxqKzCd6rQ7/OTXpTpapg0yctvhzOyArtAZw== - -"@swc/core-linux-arm64-gnu@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.158.tgz#597577dda702400f5f5d4cf49b32bb3fa6017835" - integrity sha512-QNTs6g9VYMF4UxRnSCMe7TRAPgCdsaUbHeWhaRtRE2nfKN4fd0YYPOzODEi7P3mvLW5p75FlHtRWokaME/J1HA== - -"@swc/core-linux-arm64-musl@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.158.tgz#fb8e9aadace980eaa408596edb78090b20f4d982" - integrity sha512-dylgrtZQJIZ6JfRDL87sPdXlOew/hl5VQaIjjhN6hu+tuRmAHzyN50DJIioErMxqFFaxnqJCxMZUFX0AlPwEKg== - -"@swc/core-linux-x64-gnu@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.158.tgz#190113e5afa441e20db60d67ea1926ed1f9e1ae6" - integrity sha512-f+l13OggHhdlk3va4tol7KxHm3kt1QPusLZJpVh00OENqXV6Wuv3Xh1BMgv5XMy6oXfOUdrXcPi3GWWi8079XA== - -"@swc/core-linux-x64-musl@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.158.tgz#72894115ea3af335be0ec530c00aea88ce4fa298" - integrity sha512-+TuNuzCBkDfoZKaaeqUrDdEANc3iVS8TYQgutHokSu6FCcNd9OGCm81SXknmYuDMtqYGs1LwVNMwCV7YOWEsiA== - -"@swc/core-win32-arm64-msvc@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.158.tgz#5569523a0b2758d62e65319433e2228ace4cc64e" - integrity sha512-GXfOgEgqWdrol6dpseLXQL9RkRy6TSBMULtwpxwH5uf1jwAAZaMBsd+JemvhW0OjbIX0P9M19hdvQYtxuYxvrg== - -"@swc/core-win32-ia32-msvc@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.158.tgz#18f0b6cb1b6343a127b9da24904b3d1b1283db82" - integrity sha512-Z/KIIgJrI2lXm+S/vRmYLcanOTvvxWq929ggjgY93m3zWrHjsWGVFoelbn2xLRUOtI/u0qna6DovLHhC4KcuBw== - -"@swc/core-win32-x64-msvc@1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.158.tgz#1f52b172617f62892afab6bfa8d624e99fa26964" - integrity sha512-h0jGYJmcNFhOinLT9vNE95DZfGtxROv9eDD+b5vMz03rvli5EUEUSkQ2MPDMuezHmL/P+cpKfVc/WGWWWXpfuQ== - -"@swc/core@^1.2.158": - version "1.2.158" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.158.tgz#aba1421d16fc9cdda8e09872776957dcdae70917" - integrity sha512-EBTuqLC2CRd4HN2CSbe+z0QoYdMCGZV2GqUvco0s2pqcNSssrWAZj6xozcJOQ5VeUsYRVdKro2muMAWdNe7qug== +"@swc/core-android-arm-eabi@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.159.tgz#020b3a018ba912d90f0630ca8171cb1993377433" + integrity sha512-OIHGUjHIgow0TRWQpoKzAKAzdOmZPK/aVSkctWdMJvAc0Oj6yxlj35UfOtdifJJxRej/KEMZpFeQTJ69ezycuQ== + +"@swc/core-android-arm64@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.159.tgz#438c396b01d4371e36ac4ff2f917e425df927a7b" + integrity sha512-zKMq4/a62usmD+CTEpyNNN57LBGHJMK2s2KDcU7Vu/tHoHKGkFYQi7PYBw3t6+tCyPfwoo20NONOiYZv6dm36Q== + +"@swc/core-darwin-arm64@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.159.tgz#58eb17200621c29ff5757f43478c87bab5166e0b" + integrity sha512-vZJmK7Baph2UCUIrArEt4RxnvK87OF8TSUe8VNgYPIFtoCEA6ttKXnndCI5kUKPvakpAg4NoHs1mm/x7gVZVVQ== + +"@swc/core-darwin-x64@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.159.tgz#fcf7ce53024c16255e91d10980fbda6799cc3476" + integrity sha512-hhJ336eq9QMv8PTnrCfY99xhdf8LH8RquLLfVV+XwbeXGF23fJJrsjQgv9rTC5aadIh6AxR2cHgCm4CGU/Xs0w== + +"@swc/core-freebsd-x64@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.159.tgz#84411aa22ac584e2141cfb8de249cd9e52204084" + integrity sha512-ZwJcA38AEmQp4OCkYOZD/5FjSU1VEMX/iMISEGUwDEE7d4CypFFP3mCpk5JAVEWJIhdYjgfo2SY8v9PfoSmBDg== + +"@swc/core-linux-arm-gnueabihf@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.159.tgz#744fad70e871ac045867b5a4eb76d216d86b6b69" + integrity sha512-M1QF8BBrbuXkw+T8U4xjMhGvjog83pA40PfZknGk+czQFJcNo4mq5hxMPalRbLN6olMoZNI6EM5a6zSocoDXEg== + +"@swc/core-linux-arm64-gnu@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.159.tgz#ab324d79871ba4414e84a9e7e1c7399483079c39" + integrity sha512-1uCMSEfzXtJHnuQoYHuHvzmBQ4/YlEcPydRMpc8/nO/svRGAHUZPKIz887tNk0nVtlF4Kil/LTrG+Wqxrp9z7A== + +"@swc/core-linux-arm64-musl@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.159.tgz#a9f957666ea2603ce7865cf9ff91ce63c1ffbe7c" + integrity sha512-FE+LyayWD55ESq0bV40x+Lmse7UyI/hhfrO/wvEs3v97z+fRhzPvcPAw38MoW2DVazPw3GotuBIf6Y5XkFO+fg== + +"@swc/core-linux-x64-gnu@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.159.tgz#36d5483673a96649ac5898a3b4b864b3b036f536" + integrity sha512-O7pH2A+ENjCuvMuKjv6UoIBsmwAbrTi+45WFL1snqCDZw+4p3WutFUSlhEW72uI6CEdb4kfZG0lajW2/Qbkuvg== + +"@swc/core-linux-x64-musl@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.159.tgz#a74d026cdd59118b348c0cd2c2d889d2bea67ec5" + integrity sha512-Se1EccOiN4h8/SaTZFVp7VoSUNR7ENmAmpVNROKnfZGb589THpLlC5MZtp5EFYDaLjpLHypVeqw0OO4tgwsL4w== + +"@swc/core-win32-arm64-msvc@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.159.tgz#18488c44e09ad659cc9696ccd481f2dfd013ba61" + integrity sha512-nKv1ksT3+V3xhPRXFr5Eeg0b93dqpGzKIoC13WwC0jRYbD0/SZwwcTU/XUZcm4MWQI8CG+PwwhO3SLMo747eqw== + +"@swc/core-win32-ia32-msvc@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.159.tgz#2c22f15303a133f6651f6b89e360e00a7f23eb17" + integrity sha512-24khotmSwFF2rEUeXPdqaTSOrIylroEx8MfuyG1BxfYfol+B9QyG8YqDyz713YM9dJYgs7JKuSfkK8qGQ2MbYA== + +"@swc/core-win32-x64-msvc@1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.159.tgz#f6c052ea50cb026c3af0993a46e018c3cbc42da8" + integrity sha512-Z/hcfe1DRcOQgnxZcnYy8d4lxZi1IHI2FeeRwDWtKn28cSaPca1acZVb4qA0hSfqsftKo0zTgLro6oh9gWxFng== + +"@swc/core@^1.2.159": + version "1.2.159" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.159.tgz#e4c884a00c34c9b0ce4d2669d75b3f5d1c87aea9" + integrity sha512-y+z+c4IelqaxvpQrc8hYdEpuvP1BVS9Fe5t8P8/yyP1oSrJkrLibROX4dHujg4EekFQhPCUjA29NawC4D08IQA== optionalDependencies: - "@swc/core-android-arm-eabi" "1.2.158" - "@swc/core-android-arm64" "1.2.158" - "@swc/core-darwin-arm64" "1.2.158" - "@swc/core-darwin-x64" "1.2.158" - "@swc/core-freebsd-x64" "1.2.158" - "@swc/core-linux-arm-gnueabihf" "1.2.158" - "@swc/core-linux-arm64-gnu" "1.2.158" - "@swc/core-linux-arm64-musl" "1.2.158" - "@swc/core-linux-x64-gnu" "1.2.158" - "@swc/core-linux-x64-musl" "1.2.158" - "@swc/core-win32-arm64-msvc" "1.2.158" - "@swc/core-win32-ia32-msvc" "1.2.158" - "@swc/core-win32-x64-msvc" "1.2.158" + "@swc/core-android-arm-eabi" "1.2.159" + "@swc/core-android-arm64" "1.2.159" + "@swc/core-darwin-arm64" "1.2.159" + "@swc/core-darwin-x64" "1.2.159" + "@swc/core-freebsd-x64" "1.2.159" + "@swc/core-linux-arm-gnueabihf" "1.2.159" + "@swc/core-linux-arm64-gnu" "1.2.159" + "@swc/core-linux-arm64-musl" "1.2.159" + "@swc/core-linux-x64-gnu" "1.2.159" + "@swc/core-linux-x64-musl" "1.2.159" + "@swc/core-win32-arm64-msvc" "1.2.159" + "@swc/core-win32-ia32-msvc" "1.2.159" + "@swc/core-win32-x64-msvc" "1.2.159" "@swc/jest@^0.2.20": version "0.2.20" @@ -3738,9 +3738,9 @@ integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": - version "7.1.18" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" - integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -4065,9 +4065,9 @@ recast "^0.20.3" "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.10" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" + integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== "@types/json5@^0.0.29": version "0.0.29" @@ -4080,9 +4080,9 @@ integrity sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg== "@types/keyv@*", "@types/keyv@^3.1.1": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.3.tgz#1c9aae32872ec1f20dcdaee89a9f3ba88f465e41" - integrity sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg== + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: "@types/node" "*" @@ -4140,6 +4140,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== +"@types/node@16.9.1": + version "16.9.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" + integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== + "@types/node@^10.11.7": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -4223,10 +4228,10 @@ "@types/webpack" "^4" "@types/webpack-dev-server" "3" -"@types/react-dom@>=16.9.0", "@types/react-dom@^17.0.13": - version "17.0.13" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.13.tgz#a3323b974ee4280070982b3112351bb1952a7809" - integrity sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ== +"@types/react-dom@>=16.9.0", "@types/react-dom@^17.0.14": + version "17.0.14" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.14.tgz#c8f917156b652ddf807711f5becbd2ab018dea9f" + integrity sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ== dependencies: "@types/react" "*" @@ -4263,10 +4268,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.40": - version "17.0.40" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad" - integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ== +"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.41": + version "17.0.41" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.41.tgz#6e179590d276394de1e357b3f89d05d7d3da8b85" + integrity sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -4912,10 +4917,10 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.6.0, ajv@^8.8.0: require-from-string "^2.0.2" uri-js "^4.2.2" -algoliasearch-helper@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz#c0a0493df84d850360f664ad7a9d4fc78a94fd78" - integrity sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w== +algoliasearch-helper@^3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.3.tgz#4da9e68591e02bf6accb6a77b0c2d2ecefab5c07" + integrity sha512-ra+SYf+R9bFdnBVMDYxjzdX246k4LtaeTPxww9EodnQcOSKn35TOb1/LOj1nIPZla/LjDr7wczVFqeH85O9kpg== dependencies: "@algolia/events" "^4.0.1" @@ -5365,14 +5370,14 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^10.3.7, autoprefixer@^10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" - integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== +autoprefixer@^10.3.7, autoprefixer@^10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: - browserslist "^4.19.1" - caniuse-lite "^1.0.30001297" - fraction.js "^4.1.2" + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" @@ -5792,13 +5797,13 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1: - version "4.20.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9" - integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== dependencies: - caniuse-lite "^1.0.30001313" - electron-to-chromium "^1.4.76" + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" escalade "^3.1.1" node-releases "^2.0.2" picocolors "^1.0.0" @@ -6074,10 +6079,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001313: - version "1.0.30001317" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" - integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: + version "1.0.30001319" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz#eb4da4eb3ecdd409f7ba1907820061d56096e88f" + integrity sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw== caseless@~0.12.0: version "0.12.0" @@ -6135,7 +6140,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -6642,9 +6647,9 @@ commander@^8.0.0, commander@^8.3.0: integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== commander@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.0.0.tgz#86d58f24ee98126568936bd1d3574e0308a99a40" - integrity sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw== + version "9.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.1.0.tgz#a6b263b2327f2e188c6402c42623327909f2dbec" + integrity sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w== comment-json@^4.2.2: version "4.2.2" @@ -6658,9 +6663,9 @@ comment-json@^4.2.2: repeat-string "^1.6.1" comment-parser@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.0.tgz#68beb7dbe0849295309b376406730cd16c719c44" - integrity sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA== + version "1.3.1" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" + integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== common-path-prefix@^3.0.0: version "3.0.0" @@ -7290,10 +7295,10 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.2.5: - version "5.2.5" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.5.tgz#bf1564b0702bbad6f55dc2b6717346eeeab090ff" - integrity sha512-Zjq42GtsRN1gw1LcgY7PHsXlw/k65Ps3uc9cG8jKY1uNqux6eDqt6Fdc/vTWb/Z6ZhnDyecul8cdCHImbU6E5g== +cssnano-preset-advanced@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.0.tgz#c3a0d9ad38a61fa6966feaa9281bf438530c8207" + integrity sha512-sPqGL/9BZo4cEI3r+ENfF9442uth8XaEX1oZ6wOGdMErFSwjEip5PM+lEP/snZIMCUVR3PfU1w8cL9WzB7bN4A== dependencies: autoprefixer "^10.3.7" cssnano-preset-default "^*" @@ -7446,9 +7451,9 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: ms "2.0.0" debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -7966,9 +7971,9 @@ domhandler@^2.3.0: domelementtype "1" domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" @@ -8097,10 +8102,10 @@ ejs@^3.1.6: dependencies: jake "^10.6.1" -electron-to-chromium@^1.4.76: - version "1.4.84" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.84.tgz#2700befbcb49c42c4ee162e137ff392c07658249" - integrity sha512-b+DdcyOiZtLXHdgEG8lncYJdxbdJWJvclPNMg0eLUDcSOSO876WA/pYjdSblUTd7eJdIs4YdIxHWGazx7UPSJw== +electron-to-chromium@^1.4.84: + version "1.4.88" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.88.tgz#ebe6a2573b563680c7a7bf3a51b9e465c9c501db" + integrity sha512-oA7mzccefkvTNi9u7DXmT0LqvhnOiN2BhSrKerta7HeUC1cLoIwtbf2wL+Ah2ozh5KQd3/1njrGrwDBXx6d14Q== elegant-spinner@^1.0.1: version "1.0.1" @@ -8369,10 +8374,10 @@ eslint-plugin-import@^2.25.4: resolve "^1.20.0" tsconfig-paths "^3.12.0" -eslint-plugin-jest@^26.1.1: - version "26.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.1.tgz#7176dd745ef8bca3070263f62cdf112f2dfc9aa1" - integrity sha512-HRKOuPi5ADhza4ZBK5ufyNXy28bXXkib87w+pQqdvBhSTsamndh6sIAKPAUl8y0/n9jSWBdTPslrwtKWqkp8dA== +eslint-plugin-jest@^26.1.2: + version "26.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.2.tgz#0f1a15c62889fffc3f78a773749d672f1bedb15f" + integrity sha512-1bXCoRODPkGN06n9KAMls4Jm0eyS+0Q/LWcIxhqWR2ycV0Z7lnx2c10idk4dtFIJY5xStgiIr5snC6/rxcXpbw== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -8419,10 +8424,10 @@ eslint-plugin-react@^7.29.4: semver "^6.3.0" string.prototype.matchall "^4.0.6" -eslint-plugin-regexp@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-regexp/-/eslint-plugin-regexp-1.5.1.tgz#982ea8936283035897d6bb1ba32c0ea5d9a4dee0" - integrity sha512-5v0rQIi54m2KycQHqmOAHrZhvI56GHmI2acr6zEffAqfeifTtobAEapv9Uf4o8//lGvwVkHKyjLoSbBNEFcfOA== +eslint-plugin-regexp@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-regexp/-/eslint-plugin-regexp-1.6.0.tgz#d757e40e53b51b67b84194387495e346774eca86" + integrity sha512-xkaQOzyY4PUukRd8b6zTq+QTtg0dePlCP2dZiM+XGSmvlpDeYiPJHfRDpAfS/sP9YtK6q7DGes1smCyPTD3Lkg== dependencies: comment-parser "^1.1.2" eslint-utils "^3.0.0" @@ -8936,9 +8941,9 @@ feed@^4.2.2: xml-js "^1.6.11" fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.4.tgz#e8c6567f80ad7fc22fd302e7dcb72bafde9c1717" - integrity sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA== + version "3.1.5" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.5.tgz#0077bf5f3fcdbd9d75a0b5362f77dbb743489863" + integrity sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg== dependencies: node-domexception "^1.0.0" web-streams-polyfill "^3.0.3" @@ -9186,9 +9191,9 @@ flatten@^1.0.2: integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== flow-parser@0.*: - version "0.173.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.173.0.tgz#992539fe87b4448a660ac1c54ffa358301e7110b" - integrity sha512-gikomjo+jzdehhOCHP2Ca5y1HGK3jkODhUdTxk4a3SdyLAMBsEwb7KJETHzB4KQs7HhHcqhyT7mGmd9iT8B5Hg== + version "0.174.1" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.174.1.tgz#bb81e17fe45a1e64d9752090e819a6744a539fa0" + integrity sha512-nDMOvlFR+4doLpB3OJpseHZ7uEr3ENptlF6qMas/kzQmNcLzMwfQeFX0gGJ/+em7UdldB/nGsk55tDTOvjbCuw== flush-write-stream@^2.0.0: version "2.0.0" @@ -9287,7 +9292,7 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.1.2: +fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== @@ -9558,11 +9563,11 @@ gh-release-fetch@^3.0.0: semver "^7.0.0" gifwrap@^0.9.2: - version "0.9.3" - resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.3.tgz#66d939219bb038d19745abf6024a8ab231786bdb" - integrity sha512-HSLpe3qhAdAoIBbwuTjKnxMGemj80uRpr55IhDv1Xf25h1E0SrKr8nIBFXysKUlYm8ZCkDhAuvX7/hRQnE9rLw== + version "0.9.4" + resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.4.tgz#f4eb6169ba027d61df64aafbdcb1f8ae58ccc0c5" + integrity sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ== dependencies: - image-q "^1.1.1" + image-q "^4.0.0" omggif "^1.0.10" git-clone@^0.2.0: @@ -9737,9 +9742,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.12.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.1.tgz#ec206be932e6c77236677127577aa8e50bf1c5cb" - integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw== + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== dependencies: type-fest "^0.20.2" @@ -9983,7 +9988,7 @@ has-symbol-support-x@^1.4.1: resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== -has-symbols@^1.0.1, has-symbols@^1.0.2: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -10519,10 +10524,12 @@ ignore@^5.1.8, ignore@^5.1.9, ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -image-q@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056" - integrity sha512-zgWEeg+5KV7fILRUxkmPr/Sykz9wP22n2OfBtuzURc7jZ0D5esuw6xFfKWug3fYUEZ78+ECNKjjYmEUqxFtk+Q== +image-q@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/image-q/-/image-q-4.0.0.tgz#31e075be7bae3c1f42a85c469b4732c358981776" + integrity sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw== + dependencies: + "@types/node" "16.9.1" image-size@^1.0.1: version "1.0.1" @@ -11334,12 +11341,12 @@ isurl@^1.0.0-alpha5: is-object "^1.0.1" jake@^10.6.1: - version "10.8.2" - resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" - integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + version "10.8.4" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.4.tgz#f6a8b7bf90c6306f768aa82bb7b98bf4ca15e84a" + integrity sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA== dependencies: async "0.9.x" - chalk "^2.4.2" + chalk "^4.0.2" filelist "^1.0.1" minimatch "^3.0.4" @@ -12251,10 +12258,10 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@^12.3.5: - version "12.3.5" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.5.tgz#8048ce048c3cac12f57200a06344a54dc91c8fa9" - integrity sha512-oOH36RUs1It7b9U/C7Nl/a0sLfoIBcMB8ramiB3nuJ6brBqzsWiUAFSR5DQ3yyP/OR7XKMpijtgKl2DV1lQ3lA== +lint-staged@^12.3.7: + version "12.3.7" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.7.tgz#ad0e2014302f704f9cf2c0ebdb97ac63d0f17be0" + integrity sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ== dependencies: cli-truncate "^3.1.0" colorette "^2.0.16" @@ -12266,6 +12273,7 @@ lint-staged@^12.3.5: micromatch "^4.0.4" normalize-path "^3.0.0" object-inspect "^1.12.0" + pidtree "^0.5.0" string-argv "^0.3.1" supports-color "^9.2.1" yaml "^1.10.2" @@ -13464,17 +13472,17 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== -netlify-cli@^9.13.1: - version "9.13.1" - resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.1.tgz#f5c272c4c66888a622f8c5daea211fc109cc4e4b" - integrity sha512-l2MUAG53jZvWWB6uAcL1pU28Daty2Kq5hjE5qIKPXO8db5c9Dn28WbqPKEH39X5JOBGqcibDGHQSTWYMBi9wvQ== +netlify-cli@^9.13.3: + version "9.13.3" + resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.3.tgz#61183a7e2d780fc6ec44ef35f377a7fed0afb9b2" + integrity sha512-kxaRPiVUikPXmmOX+w8qAqN69zC0Wqe12xhDfcKntS5GbMp1BpDwzqAlQCB76n36HJxzsBTjDR5KRM2Vo86HvA== dependencies: - "@netlify/build" "^26.4.0" + "@netlify/build" "^26.5.0" "@netlify/config" "^17.0.18" "@netlify/framework-info" "^9.0.2" "@netlify/local-functions-proxy" "^1.1.1" "@netlify/plugin-edge-handlers" "^3.0.7" - "@netlify/plugins-list" "^6.16.0" + "@netlify/plugins-list" "^6.16.1" "@netlify/routing-local-proxy" "^0.34.1" "@netlify/zip-it-and-ship-it" "^5.9.0" "@octokit/rest" "^18.0.0" @@ -13698,9 +13706,9 @@ node-fetch@^3.0.0: formdata-polyfill "^4.0.10" node-forge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" - integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" + integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== node-gyp-build@^4.2.2: version "4.3.0" @@ -14887,6 +14895,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.5.0.tgz#ad5fbc1de78b8a5f99d6fbdd4f6e4eee21d1aca1" + integrity sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA== + pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -15217,9 +15230,9 @@ postcss-ordered-values@^*: postcss-value-parser "^4.2.0" postcss-reduce-idents@^*: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.1.0.tgz#386b65cf861a9045663bd349d572027ab138ca4a" - integrity sha512-2xDoPTzv98D/HFDrGTgVEBlcuS47wvua2oc4g2WoZdYPwzPWMWb2TCRruCyN7vbl+HAtVLGvEOMZIZb3wYgv7w== + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" + integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" @@ -15305,10 +15318,10 @@ postcss@^7.0.18, postcss@^7.0.39: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.7, postcss@^8.2.x, postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.6, postcss@^8.4.7, postcss@^8.4.8: - version "8.4.8" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.8.tgz#dad963a76e82c081a0657d3a2f3602ce10c2e032" - integrity sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ== +postcss@^8.1.7, postcss@^8.2.x, postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: nanoid "^3.3.1" picocolors "^1.0.0" @@ -15372,10 +15385,10 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.0.tgz#12f8f504c4d8ddb76475f441337542fa799207d4" + integrity sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A== pretty-bytes@^5.3.0, pretty-bytes@^5.6.0: version "5.6.0" @@ -15434,7 +15447,7 @@ printj@~1.3.1: resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== -prism-react-renderer@^1.0.1, prism-react-renderer@^1.2.1, prism-react-renderer@^1.3.1: +prism-react-renderer@^1.0.1, prism-react-renderer@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== @@ -16247,7 +16260,7 @@ regexp-ast-analysis@^0.3.0: refa "^0.9.0" regexpp "^3.2.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== @@ -17656,17 +17669,17 @@ string-width@^5.0.0, string-width@^5.0.1: strip-ansi "^7.0.1" string.prototype.matchall@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -17871,10 +17884,10 @@ stylelint-config-standard@^25.0.0: dependencies: stylelint-config-recommended "^7.0.0" -stylelint@^14.5.3: - version "14.5.3" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.5.3.tgz#103b6670128ba3dea69fe3a1a07c4a5d3e0e3450" - integrity sha512-omHETL+kGHR+fCXFK1SkZD/A+emCP9esggAdWEl8GPjTNeyRYj+H6uetRDcU+7E451zwWiUYGVAX+lApsAZgsQ== +stylelint@^14.6.0: + version "14.6.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.0.tgz#bf577103c8a1d47cd8818469e27db77b83ab3cc1" + integrity sha512-Xk2sqXYPi9nXgq70nBiZkbQm/QOOKd83NBTaBE1fXEWAEeRlgHnKC/E7kJFlT6K0SaNDOK5yIvR7GFPGsNLuOg== dependencies: balanced-match "^2.0.0" colord "^2.9.2" @@ -17901,7 +17914,7 @@ stylelint@^14.5.3: normalize-path "^3.0.0" normalize-selector "^0.2.0" picocolors "^1.0.0" - postcss "^8.4.6" + postcss "^8.4.12" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^6.0.0" @@ -18648,9 +18661,9 @@ type-fest@^1.0.2: integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== type-fest@^2.0.0, type-fest@^2.11.2, type-fest@^2.5.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.0.tgz#ce342f58cab9114912f54b493d60ab39c3fc82b6" - integrity sha512-Qe5GRT+n/4GoqCNGGVp5Snapg1Omq3V7irBJB3EaKsp7HWDo5Gv2d/67gfNyV+d5EXD+x/RF5l1h4yJ7qNkcGA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" + integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== type-is@~1.6.18: version "1.6.18" @@ -20019,9 +20032,9 @@ yargs@^16.0.0, yargs@^16.2.0: yargs-parser "^20.2.2" yargs@^17.1.0, yargs@^17.3.1: - version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + version "17.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" + integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== dependencies: cliui "^7.0.2" escalade "^3.1.1" From e19a4e23e757087509193a393fb52fc1171a29e9 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 20 Mar 2022 21:42:36 -0300 Subject: [PATCH 036/405] fix(content-docs): warn when files are not tracked (#6937) * fix(docs): warn when files are not tracked * chore(devcontainer): use non-root user * test: fix jest in vscode * test(docs): improve existing test * chore(devcontainer): fix jest error on startup * chore: fix comments * chore: remove "probably" from error message --- .devcontainer/devcontainer.json | 33 ++++++++++++++++--- .eslintrc.js | 1 + jest.config.mjs | 2 ++ package.json | 2 +- .../src/blogUtils.ts | 2 +- .../src/__tests__/lastUpdate.test.ts | 11 +++++-- .../src/lastUpdate.ts | 17 ++++++++-- packages/docusaurus-utils/src/gitUtils.ts | 9 +++++ packages/docusaurus-utils/src/index.ts | 6 +++- project-words.txt | 7 +++- 10 files changed, 77 insertions(+), 13 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 80716af9c10f..1d41847172f3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,10 +1,33 @@ { - "name": "Docusaurus Dev Container", - "image": "mcr.microsoft.com/vscode/devcontainers/typescript-node:14-buster", + "image": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu-20.04", "settings": { - "terminal.integrated.shell.linux": "/bin/bash" + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + } }, - "extensions": ["dbaeumer.vscode-eslint", "orta.vscode-jest"], + "extensions": [ + "dbaeumer.vscode-eslint", + "orta.vscode-jest", + "esbenp.prettier-vscode", + "streetsidesoftware.code-spell-checker" + ], "forwardPorts": [3000], - "postCreateCommand": "yarn install" + "containerUser": "vscode", + "postCreateCommand": "yarn install", + "waitFor": "postCreateCommand", // otherwise automated jest tests fail + "features": { + "node": { + "version": "14" + }, + "github-cli": "latest" + } } diff --git a/.eslintrc.js b/.eslintrc.js index 64f77872d6a1..d31aec2e0a19 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -49,6 +49,7 @@ module.exports = { curly: [WARNING, 'all'], 'global-require': WARNING, 'lines-between-class-members': OFF, + 'max-classes-per-file': OFF, 'max-len': [ WARNING, { diff --git a/jest.config.mjs b/jest.config.mjs index 09725a8e36c6..bd194757810d 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -7,6 +7,8 @@ import {fileURLToPath} from 'url'; +process.env.TZ = 'UTC'; + const ignorePatterns = [ '/node_modules/', '__fixtures__', diff --git a/package.json b/package.json index 792f0c0d76e6..6b0b2dc0acab 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "lint:spelling": "cspell \"**\" --no-progress", "lint:style": "stylelint \"**/*.css\"", "lerna": "lerna", - "test": "cross-env TZ=UTC jest", + "test": "jest", "test:build:website": "./admin/scripts/test-release.sh", "watch": "yarn lerna run --parallel watch", "clear": "(yarn workspace website clear || echo 'Failure while running docusaurus clear') && yarn lerna exec --ignore docusaurus yarn rimraf lib lib-next", diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index ab24aa34ab92..a19f55d641fd 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -247,7 +247,7 @@ async function processBlogSourceFile( }); return result.date; } catch (err) { - logger.error(err); + logger.warn(err); return (await fs.stat(blogSourceAbsolute)).birthtime; } } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts index 61e27d9014bd..17cfaba48e9f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts @@ -47,7 +47,7 @@ describe('getFileLastUpdate', () => { it('non-existing file', async () => { const consoleMock = jest - .spyOn(console, 'error') + .spyOn(console, 'warn') .mockImplementation(() => {}); const nonExistingFileName = '.nonExisting'; const nonExistingFilePath = path.join( @@ -65,10 +65,17 @@ describe('getFileLastUpdate', () => { consoleMock.mockRestore(); }); - it('temporary created file that has no git timestamp', async () => { + it('temporary created file that is not tracked by git', async () => { + const consoleMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); const tempFilePath = path.join(__dirname, '__fixtures__', '.temp'); await fs.writeFile(tempFilePath, 'Lorem ipsum :)'); await expect(getFileLastUpdate(tempFilePath)).resolves.toBeNull(); + expect(consoleMock).toHaveBeenCalledTimes(1); + expect(consoleMock).toHaveBeenLastCalledWith( + expect.stringMatching(/not tracked by git./), + ); await fs.unlink(tempFilePath); }); diff --git a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts index e62cfe309360..ae12fb244b1d 100644 --- a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts +++ b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts @@ -6,11 +6,16 @@ */ import logger from '@docusaurus/logger'; -import {getFileCommitDate, GitNotFoundError} from '@docusaurus/utils'; +import { + getFileCommitDate, + FileNotTrackedError, + GitNotFoundError, +} from '@docusaurus/utils'; type FileLastUpdateData = {timestamp?: number; author?: string}; let showedGitRequirementError = false; +let showedFileNotTrackedError = false; export async function getFileLastUpdate( filePath?: string, @@ -31,8 +36,16 @@ export async function getFileLastUpdate( if (err instanceof GitNotFoundError && !showedGitRequirementError) { logger.warn('Sorry, the docs plugin last update options require Git.'); showedGitRequirementError = true; + } else if ( + err instanceof FileNotTrackedError && + !showedFileNotTrackedError + ) { + logger.warn( + 'Cannot infer the update date for some files, as they are not tracked by git.', + ); + showedFileNotTrackedError = true; } else { - logger.error(err); + logger.warn(err); } return null; } diff --git a/packages/docusaurus-utils/src/gitUtils.ts b/packages/docusaurus-utils/src/gitUtils.ts index 7325964b6dd4..204b3f564d88 100644 --- a/packages/docusaurus-utils/src/gitUtils.ts +++ b/packages/docusaurus-utils/src/gitUtils.ts @@ -10,6 +10,8 @@ import shell from 'shelljs'; export class GitNotFoundError extends Error {} +export class FileNotTrackedError extends Error {} + export const getFileCommitDate = ( file: string, { @@ -70,6 +72,13 @@ export const getFileCommitDate = ( } const output = result.stdout.trim(); + + if (!output) { + throw new FileNotTrackedError( + `Failed to retrieve the git history for file "${file}" because the file is not tracked by git.`, + ); + } + const match = output.match(regex); if ( diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 26cb7ae65756..c3e246ce8d5c 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -21,7 +21,11 @@ export { WEBPACK_URL_LOADER_LIMIT, } from './constants'; export {generate, genChunkName, readOutputHTMLFile} from './emitUtils'; -export {getFileCommitDate, GitNotFoundError} from './gitUtils'; +export { + getFileCommitDate, + FileNotTrackedError, + GitNotFoundError, +} from './gitUtils'; export { mergeTranslations, updateTranslationFileMessages, diff --git a/project-words.txt b/project-words.txt index ae29fa0b5180..f71fab6a6ca2 100644 --- a/project-words.txt +++ b/project-words.txt @@ -53,11 +53,13 @@ customizability daishi datagit datas +dbaeumer décembre dedup deduplicated déja deps +devcontainers devspace devto dmitry @@ -78,6 +80,7 @@ endilie endiliey entrypoints errnametoolong +esbenp esbuild eslintcache evaluable @@ -98,8 +101,8 @@ globby goss goyal gtag -hardcoding hahaha +hardcoding héctor héllô heuristical @@ -184,6 +187,7 @@ opensearch opensearchdescription optimizt optind +orta overrideable pageview palenight @@ -296,6 +300,7 @@ typesense unflat unist unlocalized +unmatch unnormalized unoptimized unprefixed From 4536c20455cf117d73893b92e39e195f04433156 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Mon, 21 Mar 2022 12:27:56 +0800 Subject: [PATCH 037/405] fix(content-blog): only create archive route if there are blog posts (#6947) --- packages/docusaurus-plugin-content-blog/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index fca3a7d81b30..754aee6b11d1 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -219,7 +219,7 @@ export default async function pluginContentBlog( ? blogPosts : blogPosts.slice(0, options.blogSidebarCount); - if (archiveBasePath) { + if (archiveBasePath && blogPosts.length) { const archiveUrl = normalizeUrl([ baseUrl, routeBasePath, From 3c7b39b739eaefe8cf58be21804b64c87ac468b5 Mon Sep 17 00:00:00 2001 From: Kyohei Fukuda Date: Mon, 21 Mar 2022 18:25:14 +0900 Subject: [PATCH 038/405] docs: add pdfme docs to showcase (#6948) * Add pdfme docs to showcase * minor tweaks Co-authored-by: Joshua Chen --- website/src/data/showcase/pdfme.png | Bin 0 -> 23772 bytes website/src/data/users.tsx | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 website/src/data/showcase/pdfme.png diff --git a/website/src/data/showcase/pdfme.png b/website/src/data/showcase/pdfme.png new file mode 100644 index 0000000000000000000000000000000000000000..e273ad914dc3737fdd8a11bd7c8a429dc45f9632 GIT binary patch literal 23772 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%0DDW!yL? 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 FV1m2W*f0P9 literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index b19617e07a11..18fac7918773 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -1100,6 +1100,15 @@ const Users: User[] = [ source: 'https://github.com/PcapPlusPlus/pcapplusplus.github.io', tags: ['opensource', 'versioning'], }, + { + title: 'pdfme', + description: + 'Free and Open source PDF generator library fully written in TypeScript coming with a React based UI template editor', + preview: require('./showcase/pdfme.png'), + website: 'https://pdfme.com/', + source: 'https://github.com/pdfme/pdfme/tree/main/website', + tags: ['opensource', 'design', 'product'], + }, { title: 'Pearl UI', description: From 5ee7e8c48eb5d954a5587138844556ba43f72fa2 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Mon, 21 Mar 2022 18:40:20 +0800 Subject: [PATCH 039/405] test: add tests for gitUtils (#6949) * test: add tests for gitUtils * debug test * try fix --- .../src/lastUpdate.ts | 4 +- .../src/__tests__/gitUtils.test.ts | 170 ++++++++++++++++++ packages/docusaurus-utils/src/gitUtils.ts | 39 ++-- 3 files changed, 194 insertions(+), 19 deletions(-) create mode 100644 packages/docusaurus-utils/src/__tests__/gitUtils.test.ts diff --git a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts index ae12fb244b1d..c77ccae4efed 100644 --- a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts +++ b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts @@ -12,14 +12,12 @@ import { GitNotFoundError, } from '@docusaurus/utils'; -type FileLastUpdateData = {timestamp?: number; author?: string}; - let showedGitRequirementError = false; let showedFileNotTrackedError = false; export async function getFileLastUpdate( filePath?: string, -): Promise { +): Promise<{timestamp: number; author: string} | null> { if (!filePath) { return null; } diff --git a/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts new file mode 100644 index 000000000000..1915ca2e6a53 --- /dev/null +++ b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts @@ -0,0 +1,170 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {FileNotTrackedError, getFileCommitDate} from '../gitUtils'; +import fs from 'fs-extra'; +import path from 'path'; +import os from 'os'; +import shell from 'shelljs'; + +// This function is sync so the same mock repo can be shared across tests +/* eslint-disable no-restricted-properties */ +function createTempRepo() { + const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-test-repo')); + class Git { + constructor(private dir: string) { + const res = shell.exec('git init', {cwd: dir, silent: true}); + if (res.code !== 0) { + throw new Error(`git init exited with code ${res.code}. +stderr: ${res.stderr} +stdout: ${res.stdout}`); + } + } + commit(msg: string, date: string, author: string) { + const addRes = shell.exec('git add .', {cwd: this.dir, silent: true}); + const commitRes = shell.exec( + `git commit -m "${msg}" --date "${date}T00:00:00Z" --author "${author}"`, + { + cwd: this.dir, + env: { + GIT_COMMITTER_DATE: `${date}T00:00:00Z`, + GIT_COMMITTER_NAME: author, + }, + silent: true, + }, + ); + if (addRes.code !== 0) { + throw new Error(`git add exited with code ${addRes.code}. +stderr: ${addRes.stderr} +stdout: ${addRes.stdout}`); + } + if (commitRes.code !== 0) { + throw new Error(`git commit exited with code ${commitRes.code}. +stderr: ${commitRes.stderr} +stdout: ${commitRes.stdout}`); + } + } + } + const git = new Git(repoDir); + fs.writeFileSync(path.join(repoDir, 'test.txt'), 'Some content'); + git.commit( + 'Create test.txt', + '2020-06-19', + 'Caroline ', + ); + fs.writeFileSync(path.join(repoDir, 'test.txt'), 'Updated content'); + git.commit( + 'Update test.txt', + '2020-06-20', + 'Josh-Cena ', + ); + fs.writeFileSync(path.join(repoDir, 'test.txt'), 'Updated content (2)'); + fs.writeFileSync(path.join(repoDir, 'moved.txt'), 'This file is moved'); + git.commit( + 'Update test.txt again, create moved.txt', + '2020-09-13', + 'Caroline ', + ); + fs.moveSync(path.join(repoDir, 'moved.txt'), path.join(repoDir, 'dest.txt')); + git.commit( + 'Rename moved.txt to dest.txt', + '2020-11-13', + 'Josh-Cena ', + ); + fs.writeFileSync(path.join(repoDir, 'untracked.txt'), "I'm untracked"); + return repoDir; +} + +describe('getFileCommitDate', () => { + const repoDir = createTempRepo(); + it('returns earliest commit date', async () => { + expect(getFileCommitDate(path.join(repoDir, 'test.txt'), {})).toEqual({ + date: new Date('2020-06-19'), + timestamp: new Date('2020-06-19').getTime() / 1000, + }); + expect(getFileCommitDate(path.join(repoDir, 'dest.txt'), {})).toEqual({ + date: new Date('2020-09-13'), + timestamp: new Date('2020-09-13').getTime() / 1000, + }); + }); + it('returns latest commit date', async () => { + expect( + getFileCommitDate(path.join(repoDir, 'test.txt'), {age: 'newest'}), + ).toEqual({ + date: new Date('2020-09-13'), + timestamp: new Date('2020-09-13').getTime() / 1000, + }); + expect( + getFileCommitDate(path.join(repoDir, 'dest.txt'), {age: 'newest'}), + ).toEqual({ + date: new Date('2020-11-13'), + timestamp: new Date('2020-11-13').getTime() / 1000, + }); + }); + it('returns latest commit date with author', async () => { + expect( + getFileCommitDate(path.join(repoDir, 'test.txt'), { + age: 'oldest', + includeAuthor: true, + }), + ).toEqual({ + date: new Date('2020-06-19'), + timestamp: new Date('2020-06-19').getTime() / 1000, + author: 'Caroline', + }); + expect( + getFileCommitDate(path.join(repoDir, 'dest.txt'), { + age: 'oldest', + includeAuthor: true, + }), + ).toEqual({ + date: new Date('2020-09-13'), + timestamp: new Date('2020-09-13').getTime() / 1000, + author: 'Caroline', + }); + }); + it('returns earliest commit date with author', async () => { + expect( + getFileCommitDate(path.join(repoDir, 'test.txt'), { + age: 'newest', + includeAuthor: true, + }), + ).toEqual({ + date: new Date('2020-09-13'), + timestamp: new Date('2020-09-13').getTime() / 1000, + author: 'Caroline', + }); + expect( + getFileCommitDate(path.join(repoDir, 'dest.txt'), { + age: 'newest', + includeAuthor: true, + }), + ).toEqual({ + date: new Date('2020-11-13'), + timestamp: new Date('2020-11-13').getTime() / 1000, + author: 'Josh-Cena', + }); + }); + it('throws custom error when file is not tracked', async () => { + expect(() => + getFileCommitDate(path.join(repoDir, 'untracked.txt'), { + age: 'newest', + includeAuthor: true, + }), + ).toThrowError(FileNotTrackedError); + }); + it('throws when file not found', async () => { + expect(() => + getFileCommitDate(path.join(repoDir, 'nonexistent.txt'), { + age: 'newest', + includeAuthor: true, + }), + ).toThrowError( + /Failed to retrieve git history for ".*nonexistent.txt" because the file does not exist./, + ); + }); +}); diff --git a/packages/docusaurus-utils/src/gitUtils.ts b/packages/docusaurus-utils/src/gitUtils.ts index 204b3f564d88..06f0e8f29508 100644 --- a/packages/docusaurus-utils/src/gitUtils.ts +++ b/packages/docusaurus-utils/src/gitUtils.ts @@ -12,7 +12,22 @@ export class GitNotFoundError extends Error {} export class FileNotTrackedError extends Error {} -export const getFileCommitDate = ( +export function getFileCommitDate( + file: string, + args: {age?: 'oldest' | 'newest'; includeAuthor?: false}, +): { + date: Date; + timestamp: number; +}; +export function getFileCommitDate( + file: string, + args: {age?: 'oldest' | 'newest'; includeAuthor: true}, +): { + date: Date; + timestamp: number; + author: string; +}; +export function getFileCommitDate( file: string, { age = 'oldest', @@ -25,7 +40,7 @@ export const getFileCommitDate = ( date: Date; timestamp: number; author?: string; -} => { +} { if (!shell.which('git')) { throw new GitNotFoundError( `Failed to retrieve git history for "${file}" because git is not installed.`, @@ -38,9 +53,6 @@ export const getFileCommitDate = ( ); } - const fileBasename = path.basename(file); - const fileDirname = path.dirname(file); - let formatArg = '--format=%ct'; if (includeAuthor) { formatArg += ',%an'; @@ -54,10 +66,10 @@ export const getFileCommitDate = ( } const result = shell.exec( - `git log ${extraArgs} ${formatArg} -- "${fileBasename}"`, + `git log ${extraArgs} ${formatArg} -- "${path.basename(file)}"`, { // cwd is important, see: https://github.com/facebook/docusaurus/pull/5048 - cwd: fileDirname, + cwd: path.dirname(file), silent: true, }, ); @@ -81,22 +93,17 @@ export const getFileCommitDate = ( const match = output.match(regex); - if ( - !match || - !match.groups || - !match.groups.timestamp || - (includeAuthor && !match.groups.author) - ) { + if (!match) { throw new Error( `Failed to retrieve the git history for file "${file}" with unexpected output: ${output}`, ); } - const timestamp = Number(match.groups.timestamp); + const timestamp = Number(match.groups!.timestamp); const date = new Date(timestamp * 1000); if (includeAuthor) { - return {date, timestamp, author: match.groups.author}; + return {date, timestamp, author: match.groups!.author!}; } return {date, timestamp}; -}; +} From c696dc2cd6b763fc2f3d83cba330d5e5518ef47e Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Mon, 21 Mar 2022 20:13:40 +0800 Subject: [PATCH 040/405] test: fix Windows test for gitUtils (#6951) * test: fix Windows test for gitUtils * change this * fix --- .../docusaurus-utils/src/__tests__/gitUtils.test.ts | 11 +++++++---- packages/docusaurus-utils/src/gitUtils.ts | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts index 1915ca2e6a53..64bbf62a4824 100644 --- a/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts @@ -23,6 +23,12 @@ function createTempRepo() { stderr: ${res.stderr} stdout: ${res.stdout}`); } + // Doesn't matter currently + shell.exec('git config user.email "test@jc-verse.com"', { + cwd: dir, + silent: true, + }); + shell.exec('git config user.name "Test"', {cwd: dir, silent: true}); } commit(msg: string, date: string, author: string) { const addRes = shell.exec('git add .', {cwd: this.dir, silent: true}); @@ -30,10 +36,7 @@ stdout: ${res.stdout}`); `git commit -m "${msg}" --date "${date}T00:00:00Z" --author "${author}"`, { cwd: this.dir, - env: { - GIT_COMMITTER_DATE: `${date}T00:00:00Z`, - GIT_COMMITTER_NAME: author, - }, + env: {GIT_COMMITTER_DATE: `${date}T00:00:00Z`}, silent: true, }, ); diff --git a/packages/docusaurus-utils/src/gitUtils.ts b/packages/docusaurus-utils/src/gitUtils.ts index 06f0e8f29508..9902c720b914 100644 --- a/packages/docusaurus-utils/src/gitUtils.ts +++ b/packages/docusaurus-utils/src/gitUtils.ts @@ -53,6 +53,8 @@ export function getFileCommitDate( ); } + // Commit time and author name; not using author time so that amended commits + // can have their dates updated let formatArg = '--format=%ct'; if (includeAuthor) { formatArg += ',%an'; From 1777fc4d76f3b43adf7ce4f516a6f743895221ae Mon Sep 17 00:00:00 2001 From: Alessandro Festa Date: Mon, 21 Mar 2022 16:47:37 +0100 Subject: [PATCH 041/405] docs: add K3ai to showcase (#6952) * Add files via upload * Update users.tsx * Delete logo.jpg * Add files via upload * Update users.tsx * Delete k3ai.jpg * Add files via upload * Update users.tsx * k3ai website PR * lots of changes (!) Co-authored-by: Joshua Chen --- website/src/data/showcase/k3ai.png | Bin 0 -> 17654 bytes website/src/data/users.tsx | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 website/src/data/showcase/k3ai.png diff --git a/website/src/data/showcase/k3ai.png b/website/src/data/showcase/k3ai.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a997ffecc1e2d93dab3f369069dd8a320dc0ed GIT binary patch literal 17654 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 Date: Tue, 22 Mar 2022 11:53:11 +0800 Subject: [PATCH 042/405] feat(core): allow configureWebpack to return undefined (#6784) * plugin: not acquire configureWebpack to return * type fix * add test * remove type Co-authored-by: Joshua Chen --- packages/docusaurus/src/webpack/__tests__/utils.test.ts | 2 +- packages/docusaurus/src/webpack/utils.ts | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index 3b58b57d22e6..85a80f2ca5de 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -74,7 +74,7 @@ describe('extending generated webpack config', () => { filename: 'new.bundle.js', }; } - return {}; + // Implicitly returning undefined to test null-safety }; config = applyConfigureWebpack(configureWebpack, config, false, undefined, { diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 14568c890d42..f9626b819604 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -184,12 +184,8 @@ export function applyConfigureWebpack( getJSLoader: getCustomizableJSLoader(jsLoader), }; if (typeof configureWebpack === 'function') { - const {mergeStrategy, ...res} = configureWebpack( - config, - isServer, - utils, - content, - ); + const {mergeStrategy, ...res} = + configureWebpack(config, isServer, utils, content) ?? {}; if (res && typeof res === 'object') { const customizeRules = mergeStrategy ?? {}; return mergeWithCustomize({ From 0a5354dc329d60b318aacc2fde46e9ce26399c82 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 22 Mar 2022 14:30:14 +0800 Subject: [PATCH 043/405] refactor(core): move browserContext and docusaurusContext out of client exports (#6955) --- jest.config.mjs | 4 +++- .../src/utils/__tests__/docsUtils.test.tsx | 2 +- .../src/utils/__tests__/generalUtils.test.tsx | 2 +- .../src/utils/__tests__/useAlternatePageUtils.test.tsx | 2 +- .../src/utils/__tests__/useLocalPathname.test.tsx | 2 +- .../src/utils/__tests__/usePluralForm.test.tsx | 2 +- packages/docusaurus/src/client/App.tsx | 4 ++-- .../client/{exports => }/__tests__/browserContext.test.tsx | 2 +- .../client/{exports => }/__tests__/docusaurusContext.test.tsx | 2 +- .../docusaurus/src/client/{exports => }/browserContext.tsx | 0 .../docusaurus/src/client/{exports => }/docusaurusContext.tsx | 0 .../src/client/exports/__tests__/BrowserOnly.test.tsx | 2 +- .../src/client/exports/__tests__/useBaseUrl.test.tsx | 2 +- .../src/client/exports/__tests__/useGlobalData.test.tsx | 2 +- .../docusaurus/src/client/exports/useDocusaurusContext.ts | 2 +- packages/docusaurus/src/client/exports/useIsBrowser.ts | 2 +- .../src/webpack/__tests__/__snapshots__/base.test.ts.snap | 4 ---- 17 files changed, 17 insertions(+), 19 deletions(-) rename packages/docusaurus/src/client/{exports => }/__tests__/browserContext.test.tsx (94%) rename packages/docusaurus/src/client/{exports => }/__tests__/docusaurusContext.test.tsx (95%) rename packages/docusaurus/src/client/{exports => }/browserContext.tsx (100%) rename packages/docusaurus/src/client/{exports => }/docusaurusContext.tsx (100%) diff --git a/jest.config.mjs b/jest.config.mjs index bd194757810d..c927d764c522 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -40,8 +40,10 @@ export default { '^.+\\.(css|jpe?g|png|svg|webp)$': '/jest/emptyModule.ts', // Using src instead of lib, so we always get fresh source - '@docusaurus/(browserContext|BrowserOnly|ComponentCreator|constants|docusaurusContext|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)': + '@docusaurus/(BrowserOnly|ComponentCreator|constants|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)': '@docusaurus/core/src/client/exports/$1', + + // TODO create dedicated testing utility for mocking contexts // Maybe point to a fixture? '@generated/.*': '/jest/emptyModule.ts', // TODO use "projects" + multiple configs if we work on another theme? diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index 8c76436c9cc5..f0cc92830c1e 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -20,7 +20,7 @@ import { useSidebarBreadcrumbs, } from '../docsUtils'; import {StaticRouter} from 'react-router-dom'; -import {Context} from '@docusaurus/docusaurusContext'; +import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type { PropSidebar, PropSidebarItem, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx index 661069efe4cc..71c49527abad 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/generalUtils.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import {useTitleFormatter} from '../generalUtils'; import {renderHook} from '@testing-library/react-hooks'; -import {Context} from '@docusaurus/docusaurusContext'; +import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; describe('useTitleFormatter', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx index 24f35e70b5ff..79ebd6cbca7f 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/useAlternatePageUtils.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import {useAlternatePageUtils} from '../useAlternatePageUtils'; import {renderHook} from '@testing-library/react-hooks'; import {StaticRouter} from 'react-router-dom'; -import {Context} from '@docusaurus/docusaurusContext'; +import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; describe('useAlternatePageUtils', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx index c8298c5c640d..163e2f69bdb7 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/useLocalPathname.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import {useLocalPathname} from '../useLocalPathname'; import {renderHook} from '@testing-library/react-hooks'; import {StaticRouter} from 'react-router-dom'; -import {Context} from '@docusaurus/docusaurusContext'; +import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; describe('useLocalPathname', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx index d7ab24b9ebcb..13777535a6e4 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx @@ -9,7 +9,7 @@ import {jest} from '@jest/globals'; import React from 'react'; import {usePluralForm} from '../usePluralForm'; import {renderHook} from '@testing-library/react-hooks'; -import {Context} from '@docusaurus/docusaurusContext'; +import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; describe('usePluralForm', () => { diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 6d434b2c6161..01d74bb1cdd3 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -9,8 +9,8 @@ import React from 'react'; import routes from '@generated/routes'; import renderRoutes from './exports/renderRoutes'; -import {BrowserContextProvider} from './exports/browserContext'; -import {DocusaurusContextProvider} from './exports/docusaurusContext'; +import {BrowserContextProvider} from './browserContext'; +import {DocusaurusContextProvider} from './docusaurusContext'; import PendingNavigation from './PendingNavigation'; import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; diff --git a/packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx b/packages/docusaurus/src/client/__tests__/browserContext.test.tsx similarity index 94% rename from packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx rename to packages/docusaurus/src/client/__tests__/browserContext.test.tsx index 2802f91532f1..bfb8c211cf03 100644 --- a/packages/docusaurus/src/client/exports/__tests__/browserContext.test.tsx +++ b/packages/docusaurus/src/client/__tests__/browserContext.test.tsx @@ -12,7 +12,7 @@ import React from 'react'; import {renderHook} from '@testing-library/react-hooks/server'; import {BrowserContextProvider} from '../browserContext'; -import useIsBrowser from '../useIsBrowser'; +import useIsBrowser from '../exports/useIsBrowser'; describe('BrowserContextProvider', () => { const {result, hydrate} = renderHook(() => useIsBrowser(), { diff --git a/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx b/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx similarity index 95% rename from packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx rename to packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx index 1fa41bed0483..d11bb52a68aa 100644 --- a/packages/docusaurus/src/client/exports/__tests__/docusaurusContext.test.tsx +++ b/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx @@ -12,7 +12,7 @@ import React from 'react'; import {renderHook} from '@testing-library/react-hooks/server'; import {DocusaurusContextProvider} from '../docusaurusContext'; -import useDocusaurusContext from '../useDocusaurusContext'; +import useDocusaurusContext from '../exports/useDocusaurusContext'; // This test currently isn't quite useful because the @generated aliases point // to the empty modules. Maybe we can point that to fixtures in the future. diff --git a/packages/docusaurus/src/client/exports/browserContext.tsx b/packages/docusaurus/src/client/browserContext.tsx similarity index 100% rename from packages/docusaurus/src/client/exports/browserContext.tsx rename to packages/docusaurus/src/client/browserContext.tsx diff --git a/packages/docusaurus/src/client/exports/docusaurusContext.tsx b/packages/docusaurus/src/client/docusaurusContext.tsx similarity index 100% rename from packages/docusaurus/src/client/exports/docusaurusContext.tsx rename to packages/docusaurus/src/client/docusaurusContext.tsx diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index 14a12b8d06e0..e836cfc855b2 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -12,7 +12,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import BrowserOnly from '../BrowserOnly'; -import {Context} from '../browserContext'; +import {Context} from '../../browserContext'; describe('', () => { const originalEnv = process.env; diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx index 228a6cd483ae..4cca965759fb 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import {renderHook} from '@testing-library/react-hooks'; import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl'; -import {Context} from '../docusaurusContext'; +import {Context} from '../../docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; import type {BaseUrlOptions} from '@docusaurus/useBaseUrl'; diff --git a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx index 670a7e3bcc8f..3e5d370c4e0c 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx @@ -11,7 +11,7 @@ import useGlobalData, { useAllPluginInstancesData, usePluginData, } from '../useGlobalData'; -import {Context} from '../docusaurusContext'; +import {Context} from '../../docusaurusContext'; describe('useGlobalData', () => { it('returns global data from context', () => { diff --git a/packages/docusaurus/src/client/exports/useDocusaurusContext.ts b/packages/docusaurus/src/client/exports/useDocusaurusContext.ts index 132d8c0b4fe2..0f1cb4b3af9b 100644 --- a/packages/docusaurus/src/client/exports/useDocusaurusContext.ts +++ b/packages/docusaurus/src/client/exports/useDocusaurusContext.ts @@ -6,7 +6,7 @@ */ import {useContext} from 'react'; -import {Context} from './docusaurusContext'; +import {Context} from '../docusaurusContext'; import type {DocusaurusContext} from '@docusaurus/types'; export default function useDocusaurusContext(): DocusaurusContext { diff --git a/packages/docusaurus/src/client/exports/useIsBrowser.ts b/packages/docusaurus/src/client/exports/useIsBrowser.ts index e1e7caff51ed..ce1ebb739296 100644 --- a/packages/docusaurus/src/client/exports/useIsBrowser.ts +++ b/packages/docusaurus/src/client/exports/useIsBrowser.ts @@ -6,7 +6,7 @@ */ import {useContext} from 'react'; -import {Context} from './browserContext'; +import {Context} from '../browserContext'; export default function useIsBrowser(): boolean { return useContext(Context); diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index a0a080259f3d..cfad026638f5 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -11,9 +11,7 @@ exports[`base webpack config creates webpack aliases 1`] = ` "@docusaurus/Link": "../../../../client/exports/Link.tsx", "@docusaurus/Noop": "../../../../client/exports/Noop.ts", "@docusaurus/Translate": "../../../../client/exports/Translate.tsx", - "@docusaurus/browserContext": "../../../../client/exports/browserContext.tsx", "@docusaurus/constants": "../../../../client/exports/constants.ts", - "@docusaurus/docusaurusContext": "../../../../client/exports/docusaurusContext.tsx", "@docusaurus/isInternalUrl": "../../../../client/exports/isInternalUrl.ts", "@docusaurus/renderRoutes": "../../../../client/exports/renderRoutes.ts", "@docusaurus/router": "../../../../client/exports/router.ts", @@ -61,9 +59,7 @@ exports[`getDocusaurusAliases() returns appropriate webpack aliases 1`] = ` "@docusaurus/Link": "../../client/exports/Link.tsx", "@docusaurus/Noop": "../../client/exports/Noop.ts", "@docusaurus/Translate": "../../client/exports/Translate.tsx", - "@docusaurus/browserContext": "../../client/exports/browserContext.tsx", "@docusaurus/constants": "../../client/exports/constants.ts", - "@docusaurus/docusaurusContext": "../../client/exports/docusaurusContext.tsx", "@docusaurus/isInternalUrl": "../../client/exports/isInternalUrl.ts", "@docusaurus/renderRoutes": "../../client/exports/renderRoutes.ts", "@docusaurus/router": "../../client/exports/router.ts", From 948271a0ff070c80c3bdd6d69efd9ede89009a55 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 22 Mar 2022 15:33:55 +0800 Subject: [PATCH 044/405] test: improve test coverage; reorder theme-common files (#6956) * test: improve test coverage; reorder theme-common files * no need for this --- jest.config.mjs | 14 ++- package.json | 1 + .../src/components/Details/index.tsx | 2 +- .../announcementBar.tsx} | 6 +- .../colorMode.tsx} | 10 +- .../docSidebarItemsExpandedState.tsx | 2 +- .../docsPreferredVersion.tsx} | 93 ++++++++++++++- .../src/contexts/navbarMobileSidebar.tsx | 98 ++++++++++++++++ .../tabGroupChoice.tsx} | 4 +- .../src/hooks/useHideableNavbar.ts | 8 +- .../src/hooks/useKeyboardNavigation.ts | 8 +- .../src/hooks/useLockBodyScroll.ts | 2 +- .../src/hooks/usePrismTheme.ts | 4 +- .../src/hooks/useSearchPage.ts | 6 +- .../src/{utils => hooks}/useTOCHighlight.ts | 6 +- .../src/hooks/useWindowSize.ts | 2 +- packages/docusaurus-theme-common/src/index.ts | 46 ++++---- .../src/utils/__tests__/reactUtils.test.ts | 22 ++++ .../DocsPreferredVersionStorage.ts | 33 ------ .../useDocsPreferredVersion.ts | 70 ----------- ...yMenuUtils.tsx => navbarSecondaryMenu.tsx} | 5 +- .../src/utils/navbarUtils.tsx | 109 ++---------------- .../src/utils/pathUtils.ts | 4 +- .../src/utils/reactUtils.tsx | 18 ++- .../src/utils/routesUtils.ts | 7 +- .../src/utils/useContextualSearchFilters.ts | 2 +- .../src/utils/useLocalPathname.ts | 8 +- .../src/utils/useLocationChange.ts | 3 +- .../src/utils/usePluralForm.ts | 14 +-- .../src/utils/usePrevious.ts | 19 --- .../client/__tests__/routeContext.test.tsx | 89 ++++++++++++++ .../client/exports/__tests__/Head.test.tsx | 44 +++++++ .../__snapshots__/Head.test.tsx.snap | 40 +++++++ .../__tests__/useRouteContext.test.tsx | 38 ++++++ .../src/client/exports/useRouteContext.tsx | 4 +- .../docusaurus/src/client/routeContext.tsx | 9 +- website/src/utils/__tests__/jsUtils.test.ts | 17 +++ yarn.lock | 5 + 38 files changed, 555 insertions(+), 317 deletions(-) rename packages/docusaurus-theme-common/src/{utils/announcementBarUtils.tsx => contexts/announcementBar.tsx} (94%) rename packages/docusaurus-theme-common/src/{utils/colorModeUtils.tsx => contexts/colorMode.tsx} (95%) rename packages/docusaurus-theme-common/src/{utils => contexts}/docSidebarItemsExpandedState.tsx (95%) rename packages/docusaurus-theme-common/src/{utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx => contexts/docsPreferredVersion.tsx} (63%) create mode 100644 packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx rename packages/docusaurus-theme-common/src/{utils/tabGroupChoiceUtils.tsx => contexts/tabGroupChoice.tsx} (94%) rename packages/docusaurus-theme-common/src/{utils => hooks}/useTOCHighlight.ts (97%) create mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/reactUtils.test.ts delete mode 100644 packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts delete mode 100644 packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts rename packages/docusaurus-theme-common/src/utils/{navbarSecondaryMenuUtils.tsx => navbarSecondaryMenu.tsx} (96%) delete mode 100644 packages/docusaurus-theme-common/src/utils/usePrevious.ts create mode 100644 packages/docusaurus/src/client/__tests__/routeContext.test.tsx create mode 100644 packages/docusaurus/src/client/exports/__tests__/Head.test.tsx create mode 100644 packages/docusaurus/src/client/exports/__tests__/__snapshots__/Head.test.tsx.snap create mode 100644 packages/docusaurus/src/client/exports/__tests__/useRouteContext.test.tsx create mode 100644 website/src/utils/__tests__/jsUtils.test.ts diff --git a/jest.config.mjs b/jest.config.mjs index c927d764c522..6a012fdadb5c 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -14,13 +14,16 @@ const ignorePatterns = [ '__fixtures__', '/testUtils.ts', '/packages/docusaurus/lib', + '/packages/docusaurus-logger/lib', '/packages/docusaurus-utils/lib', + '/packages/docusaurus-utils-common/lib', '/packages/docusaurus-utils-validation/lib', '/packages/docusaurus-plugin-content-blog/lib', '/packages/docusaurus-plugin-content-docs/lib', '/packages/docusaurus-plugin-content-pages/lib', '/packages/docusaurus-theme-classic/lib', '/packages/docusaurus-theme-classic/lib-next', + '/packages/docusaurus-theme-common/lib', '/packages/docusaurus-migrate/lib', ]; @@ -30,7 +33,11 @@ export default { testURL: 'https://docusaurus.io/', testEnvironment: 'node', testPathIgnorePatterns: ignorePatterns, - coveragePathIgnorePatterns: ignorePatterns, + coveragePathIgnorePatterns: [ + ...ignorePatterns, + // We also ignore all package entry points + '/packages/docusaurus-utils/src/index.ts', + ], transform: { '^.+\\.[jt]sx?$': '@swc/jest', }, @@ -54,7 +61,10 @@ export default { '@docusaurus/plugin-content-docs/client': '@docusaurus/plugin-content-docs/src/client/index.ts', }, - snapshotSerializers: ['/jest/snapshotPathNormalizer.ts'], + snapshotSerializers: [ + '/jest/snapshotPathNormalizer.ts', + 'jest-serializer-react-helmet-async', + ], snapshotFormat: { printBasicPrototype: false, }, diff --git a/package.json b/package.json index 6b0b2dc0acab..8a79ccd54c04 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "husky": "^7.0.4", "image-size": "^1.0.1", "jest": "^27.5.1", + "jest-serializer-react-helmet-async": "^1.0.21", "lerna": "^4.0.0", "lerna-changelog": "^2.2.0", "lint-staged": "^12.3.7", diff --git a/packages/docusaurus-theme-common/src/components/Details/index.tsx b/packages/docusaurus-theme-common/src/components/Details/index.tsx index d5b1b77f5a15..b8e172d62a4b 100644 --- a/packages/docusaurus-theme-common/src/components/Details/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Details/index.tsx @@ -34,7 +34,7 @@ export type DetailsProps = { summary?: ReactElement; } & ComponentProps<'details'>; -export default function Details({ +export function Details({ summary, children, ...props diff --git a/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx similarity index 94% rename from packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx rename to packages/docusaurus-theme-common/src/contexts/announcementBar.tsx index 93eb7cbeff2e..01fe0ac84852 100644 --- a/packages/docusaurus-theme-common/src/utils/announcementBarUtils.tsx +++ b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx @@ -14,9 +14,9 @@ import React, { type ReactNode, } from 'react'; import useIsBrowser from '@docusaurus/useIsBrowser'; -import {createStorageSlot} from './storageUtils'; -import {ReactContextError} from './reactUtils'; -import {useThemeConfig} from './useThemeConfig'; +import {createStorageSlot} from '../utils/storageUtils'; +import {ReactContextError} from '../utils/reactUtils'; +import {useThemeConfig} from '../utils/useThemeConfig'; export const AnnouncementBarDismissStorageKey = 'docusaurus.announcement.dismiss'; diff --git a/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx similarity index 95% rename from packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx rename to packages/docusaurus-theme-common/src/contexts/colorMode.tsx index cc6da81807d7..7fe480d32b5b 100644 --- a/packages/docusaurus-theme-common/src/utils/colorModeUtils.tsx +++ b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx @@ -14,11 +14,11 @@ import React, { useRef, type ReactNode, } from 'react'; -import {ReactContextError} from './reactUtils'; +import {ReactContextError} from '../utils/reactUtils'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; -import {createStorageSlot} from './storageUtils'; -import {useThemeConfig} from './useThemeConfig'; +import {createStorageSlot} from '../utils/storageUtils'; +import {useThemeConfig} from '../utils/useThemeConfig'; type ColorModeContextValue = { readonly colorMode: ColorMode; @@ -171,9 +171,7 @@ export function ColorModeProvider({ } export function useColorMode(): ColorModeContextValue { - const context = useContext( - ColorModeContext, - ); + const context = useContext(ColorModeContext); if (context == null) { throw new ReactContextError( 'ColorModeProvider', diff --git a/packages/docusaurus-theme-common/src/utils/docSidebarItemsExpandedState.tsx b/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx similarity index 95% rename from packages/docusaurus-theme-common/src/utils/docSidebarItemsExpandedState.tsx rename to packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx index e3f040db6c66..72687024808e 100644 --- a/packages/docusaurus-theme-common/src/utils/docSidebarItemsExpandedState.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx @@ -6,7 +6,7 @@ */ import React, {type ReactNode, useMemo, useState, useContext} from 'react'; -import {ReactContextError} from './reactUtils'; +import {ReactContextError} from '../utils/reactUtils'; const EmptyContext: unique symbol = Symbol('EmptyContext'); const Context = React.createContext< diff --git a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx similarity index 63% rename from packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx rename to packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx index e425d86d533f..a1c95d592190 100644 --- a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx @@ -10,18 +10,47 @@ import React, { useEffect, useMemo, useState, + useCallback, type ReactNode, } from 'react'; -import {useThemeConfig, type DocsVersionPersistence} from '../useThemeConfig'; -import {isDocsPluginEnabled} from '../docsUtils'; -import {ReactContextError} from '../reactUtils'; +import { + useThemeConfig, + type DocsVersionPersistence, +} from '../utils/useThemeConfig'; +import {isDocsPluginEnabled} from '../utils/docsUtils'; +import {ReactContextError} from '../utils/reactUtils'; +import {createStorageSlot} from '../utils/storageUtils'; import { useAllDocsData, + useDocsData, type GlobalPluginData, + type GlobalVersion, } from '@docusaurus/plugin-content-docs/client'; -import DocsPreferredVersionStorage from './DocsPreferredVersionStorage'; +import {DEFAULT_PLUGIN_ID} from '@docusaurus/constants'; + +const storageKey = (pluginId: string) => `docs-preferred-version-${pluginId}`; + +const DocsPreferredVersionStorage = { + save: ( + pluginId: string, + persistence: DocsVersionPersistence, + versionName: string, + ): void => { + createStorageSlot(storageKey(pluginId), {persistence}).set(versionName); + }, + + read: ( + pluginId: string, + persistence: DocsVersionPersistence, + ): string | null => + createStorageSlot(storageKey(pluginId), {persistence}).get(), + + clear: (pluginId: string, persistence: DocsVersionPersistence): void => { + createStorageSlot(storageKey(pluginId), {persistence}).del(); + }, +}; type DocsPreferredVersionName = string | null; @@ -158,10 +187,64 @@ function DocsPreferredVersionContextProviderUnsafe({ return {children}; } -export function useDocsPreferredVersionContext(): DocsPreferredVersionContextValue { +function useDocsPreferredVersionContext(): DocsPreferredVersionContextValue { const value = useContext(Context); if (!value) { throw new ReactContextError('DocsPreferredVersionContextProvider'); } return value; } + +// Note, the preferredVersion attribute will always be null before mount +export function useDocsPreferredVersion( + pluginId: string | undefined = DEFAULT_PLUGIN_ID, +): { + preferredVersion: GlobalVersion | null | undefined; + savePreferredVersionName: (versionName: string) => void; +} { + const docsData = useDocsData(pluginId); + const [state, api] = useDocsPreferredVersionContext(); + + const {preferredVersionName} = state[pluginId]!; + + const preferredVersion = preferredVersionName + ? docsData.versions.find((version) => version.name === preferredVersionName) + : null; + + const savePreferredVersionName = useCallback( + (versionName: string) => { + api.savePreferredVersion(pluginId, versionName); + }, + [api, pluginId], + ); + + return {preferredVersion, savePreferredVersionName} as const; +} + +export function useDocsPreferredVersionByPluginId(): Record< + string, + GlobalVersion | null | undefined +> { + const allDocsData = useAllDocsData(); + const [state] = useDocsPreferredVersionContext(); + + function getPluginIdPreferredVersion(pluginId: string) { + const docsData = allDocsData[pluginId]!; + const {preferredVersionName} = state[pluginId]!; + + return preferredVersionName + ? docsData.versions.find( + (version) => version.name === preferredVersionName, + ) + : null; + } + + const pluginIds = Object.keys(allDocsData); + + const result: Record = {}; + pluginIds.forEach((pluginId) => { + result[pluginId] = getPluginIdPreferredVersion(pluginId); + }); + + return result; +} diff --git a/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx new file mode 100644 index 000000000000..76f77974e6d6 --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx @@ -0,0 +1,98 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + type ReactNode, + useCallback, + useEffect, + useState, + useMemo, +} from 'react'; +import {useWindowSize} from '../hooks/useWindowSize'; +import {useHistoryPopHandler} from '../utils/historyUtils'; +import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; +import {useThemeConfig} from '../utils/useThemeConfig'; +import {ReactContextError} from '../utils/reactUtils'; + +type NavbarMobileSidebarContextValue = { + disabled: boolean; + shouldRender: boolean; + toggle: () => void; + shown: boolean; +}; + +const Context = React.createContext< + NavbarMobileSidebarContextValue | undefined +>(undefined); + +// Mobile sidebar can be disabled in case it would lead to an empty sidebar +// In this case it's not useful to display a navbar sidebar toggle button +function useNavbarMobileSidebarDisabled() { + const activeDocPlugin = useActivePlugin(); + const {items} = useThemeConfig().navbar; + return items.length === 0 && !activeDocPlugin; +} + +function useNavbarMobileSidebarContextValue(): NavbarMobileSidebarContextValue { + const disabled = useNavbarMobileSidebarDisabled(); + const windowSize = useWindowSize(); + + // Mobile sidebar not visible until user interaction: can avoid SSR rendering + const shouldRender = !disabled && windowSize === 'mobile'; // || windowSize === 'ssr'; + + const [shown, setShown] = useState(false); + + // Close mobile sidebar on navigation pop + // Most likely firing when using the Android back button (but not only) + useHistoryPopHandler(() => { + if (shown) { + setShown(false); + // Should we prevent the navigation here? + // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846 + return false; // prevent pop navigation + } + return undefined; + }); + + const toggle = useCallback(() => { + setShown((s) => !s); + }, []); + + useEffect(() => { + if (windowSize === 'desktop') { + setShown(false); + } + }, [windowSize]); + + // Return stable context value + return useMemo( + () => ({ + disabled, + shouldRender, + toggle, + shown, + }), + [disabled, shouldRender, toggle, shown], + ); +} + +export function NavbarMobileSidebarProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const value = useNavbarMobileSidebarContextValue(); + return {children}; +} + +export function useNavbarMobileSidebar(): NavbarMobileSidebarContextValue { + const context = React.useContext(Context); + if (context == null) { + throw new ReactContextError('NavbarMobileSidebarProvider'); + } + return context; +} diff --git a/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx similarity index 94% rename from packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx rename to packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx index 02ad080f8c19..3b0f14d90cf9 100644 --- a/packages/docusaurus-theme-common/src/utils/tabGroupChoiceUtils.tsx +++ b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx @@ -13,8 +13,8 @@ import React, { useContext, type ReactNode, } from 'react'; -import {createStorageSlot, listStorageKeys} from './storageUtils'; -import {ReactContextError} from './reactUtils'; +import {createStorageSlot, listStorageKeys} from '../utils/storageUtils'; +import {ReactContextError} from '../utils/reactUtils'; const TAB_CHOICE_PREFIX = 'docusaurus.tab.'; diff --git a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts index f83486f2c1b6..62e9b3740585 100644 --- a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts +++ b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts @@ -9,14 +9,10 @@ import {useState, useCallback, useRef} from 'react'; import {useLocationChange} from '../utils/useLocationChange'; import {useScrollPosition} from '../utils/scrollUtils'; -type UseHideableNavbarReturns = { +export function useHideableNavbar(hideOnScroll: boolean): { readonly navbarRef: (node: HTMLElement | null) => void; readonly isNavbarVisible: boolean; -}; - -export default function useHideableNavbar( - hideOnScroll: boolean, -): UseHideableNavbarReturns { +} { const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll); const isFocusedAnchor = useRef(false); const navbarHeight = useRef(0); diff --git a/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts b/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts index 5d9180a355a4..be6bfe8ecbf6 100644 --- a/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts +++ b/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts @@ -11,9 +11,11 @@ import './styles.css'; export const keyboardFocusedClassName = 'navigation-with-keyboard'; -// This hook detect keyboard focus indicator to not show outline for mouse users -// Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 -export default function useKeyboardNavigation(): void { +/** + * Detect keyboard focus indicator to not show outline for mouse users + * Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 + */ +export function useKeyboardNavigation(): void { useEffect(() => { function handleOutlineStyles(e: MouseEvent | KeyboardEvent) { if (e.type === 'keydown' && (e as KeyboardEvent).key === 'Tab') { diff --git a/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts b/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts index 2ac498d69e5f..c35e127fcf67 100644 --- a/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts +++ b/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts @@ -7,7 +7,7 @@ import {useEffect} from 'react'; -export default function useLockBodyScroll(lock: boolean = true): void { +export function useLockBodyScroll(lock: boolean = true): void { useEffect(() => { document.body.style.overflow = lock ? 'hidden' : 'visible'; diff --git a/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts b/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts index 94bacfff051f..3c8f84760172 100644 --- a/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts +++ b/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts @@ -6,10 +6,10 @@ */ import defaultTheme from 'prism-react-renderer/themes/palenight'; -import {useColorMode} from '../utils/colorModeUtils'; +import {useColorMode} from '../contexts/colorMode'; import {useThemeConfig} from '../utils/useThemeConfig'; -export default function usePrismTheme(): typeof defaultTheme { +export function usePrismTheme(): typeof defaultTheme { const {prism} = useThemeConfig(); const {colorMode} = useColorMode(); const lightModeTheme = prism.theme || defaultTheme; diff --git a/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts b/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts index 62271f89a04f..f97c43c97cdb 100644 --- a/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts +++ b/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts @@ -11,13 +11,11 @@ import {useCallback, useEffect, useState} from 'react'; const SEARCH_PARAM_QUERY = 'q'; -interface UseSearchPageReturn { +export function useSearchPage(): { searchQuery: string; setSearchQuery: (newSearchQuery: string) => void; generateSearchPageLink: (targetSearchQuery: string) => string; -} - -export default function useSearchPage(): UseSearchPageReturn { +} { const history = useHistory(); const { siteConfig: {baseUrl}, diff --git a/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts b/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts similarity index 97% rename from packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts rename to packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts index 56f0b55d2972..aca25bf8311e 100644 --- a/packages/docusaurus-theme-common/src/utils/useTOCHighlight.ts +++ b/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts @@ -6,7 +6,7 @@ */ import {useEffect, useRef} from 'react'; -import {useThemeConfig} from './useThemeConfig'; +import {useThemeConfig} from '../utils/useThemeConfig'; // TODO make the hardcoded theme-classic classnames configurable (or add them // to ThemeClassNames?) @@ -120,9 +120,7 @@ export type TOCHighlightConfig = { maxHeadingLevel: number; }; -export default function useTOCHighlight( - config: TOCHighlightConfig | undefined, -): void { +export function useTOCHighlight(config: TOCHighlightConfig | undefined): void { const lastActiveLinkRef = useRef(undefined); const anchorTopOffsetRef = useAnchorTopOffsetRef(); diff --git a/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts b/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts index 1106e11e8f0a..b867cf4fd95a 100644 --- a/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts +++ b/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts @@ -41,7 +41,7 @@ const DevSimulateSSR = process.env.NODE_ENV === 'development' && true; // This hook returns an enum value on purpose! // We don't want it to return the actual width value, for resize perf reasons // We only want to re-render once a breakpoint is crossed -export default function useWindowSize(): WindowSize { +export function useWindowSize(): WindowSize { const [windowSize, setWindowSize] = useState(() => { if (DevSimulateSSR) { return 'ssr'; diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index b479c3089a07..4d0a02ef1058 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -22,7 +22,7 @@ export { export { DocSidebarItemsExpandedStateProvider, useDocSidebarItemsExpandedState, -} from './utils/docSidebarItemsExpandedState'; +} from './contexts/docSidebarItemsExpandedState'; export {createStorageSlot, listStorageKeys} from './utils/storageUtils'; @@ -60,8 +60,6 @@ export {usePluralForm} from './utils/usePluralForm'; export {useLocationChange} from './utils/useLocationChange'; -export {usePrevious} from './utils/usePrevious'; - export { useCollapsible, Collapsible, @@ -69,23 +67,22 @@ export { type UseCollapsibleReturns, } from './components/Collapsible'; -export {default as Details, type DetailsProps} from './components/Details'; +export {Details, type DetailsProps} from './components/Details'; export { useDocsPreferredVersion, useDocsPreferredVersionByPluginId, -} from './utils/docsPreferredVersion/useDocsPreferredVersion'; + DocsPreferredVersionContextProvider, +} from './contexts/docsPreferredVersion'; export {duplicates, uniq} from './utils/jsUtils'; -export {DocsPreferredVersionContextProvider} from './utils/docsPreferredVersion/DocsPreferredVersionProvider'; - export {ThemeClassNames} from './utils/ThemeClassNames'; export { AnnouncementBarProvider, useAnnouncementBar, -} from './utils/announcementBarUtils'; +} from './contexts/announcementBar'; export {useLocalPathname} from './utils/useLocalPathname'; @@ -99,9 +96,9 @@ export { export {useHistoryPopHandler} from './utils/historyUtils'; export { - default as useTOCHighlight, + useTOCHighlight, type TOCHighlightConfig, -} from './utils/useTOCHighlight'; +} from './hooks/useTOCHighlight'; export { useFilteredAndTreeifiedTOC, @@ -121,6 +118,7 @@ export { export { useIsomorphicLayoutEffect, useDynamicCallback, + usePrevious, ReactContextError, } from './utils/reactUtils'; @@ -138,30 +136,28 @@ export { useColorMode, ColorModeProvider, type ColorMode, -} from './utils/colorModeUtils'; +} from './contexts/colorMode'; + +export {splitNavbarItems, NavbarProvider} from './utils/navbarUtils'; export { useTabGroupChoice, TabGroupChoiceProvider, -} from './utils/tabGroupChoiceUtils'; +} from './contexts/tabGroupChoice'; -export { - splitNavbarItems, - NavbarProvider, - useNavbarMobileSidebar, -} from './utils/navbarUtils'; +export {useNavbarMobileSidebar} from './contexts/navbarMobileSidebar'; export { useNavbarSecondaryMenu, NavbarSecondaryMenuFiller, -} from './utils/navbarSecondaryMenuUtils'; -export type {NavbarSecondaryMenuComponent} from './utils/navbarSecondaryMenuUtils'; +} from './utils/navbarSecondaryMenu'; +export type {NavbarSecondaryMenuComponent} from './utils/navbarSecondaryMenu'; -export {default as useHideableNavbar} from './hooks/useHideableNavbar'; +export {useHideableNavbar} from './hooks/useHideableNavbar'; export { - default as useKeyboardNavigation, + useKeyboardNavigation, keyboardFocusedClassName, } from './hooks/useKeyboardNavigation'; -export {default as usePrismTheme} from './hooks/usePrismTheme'; -export {default as useLockBodyScroll} from './hooks/useLockBodyScroll'; -export {default as useWindowSize} from './hooks/useWindowSize'; -export {default as useSearchPage} from './hooks/useSearchPage'; +export {usePrismTheme} from './hooks/usePrismTheme'; +export {useLockBodyScroll} from './hooks/useLockBodyScroll'; +export {useWindowSize} from './hooks/useWindowSize'; +export {useSearchPage} from './hooks/useSearchPage'; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/reactUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/reactUtils.test.ts new file mode 100644 index 000000000000..0b3e11fa1d43 --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/__tests__/reactUtils.test.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {usePrevious} from '../reactUtils'; +import {renderHook} from '@testing-library/react-hooks'; + +describe('usePrevious', () => { + it('returns the previous value of a variable', () => { + const {result, rerender} = renderHook((val) => usePrevious(val), { + initialProps: 1, + }); + expect(result.current).toBeUndefined(); + rerender(2); + expect(result.current).toBe(1); + rerender(3); + expect(result.current).toBe(2); + }); +}); diff --git a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts deleted file mode 100644 index 6e063446f330..000000000000 --- a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {createStorageSlot} from '../storageUtils'; -import type {DocsVersionPersistence} from '../useThemeConfig'; - -const storageKey = (pluginId: string) => `docs-preferred-version-${pluginId}`; - -const DocsPreferredVersionStorage = { - save: ( - pluginId: string, - persistence: DocsVersionPersistence, - versionName: string, - ): void => { - createStorageSlot(storageKey(pluginId), {persistence}).set(versionName); - }, - - read: ( - pluginId: string, - persistence: DocsVersionPersistence, - ): string | null => - createStorageSlot(storageKey(pluginId), {persistence}).get(), - - clear: (pluginId: string, persistence: DocsVersionPersistence): void => { - createStorageSlot(storageKey(pluginId), {persistence}).del(); - }, -}; - -export default DocsPreferredVersionStorage; diff --git a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts b/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts deleted file mode 100644 index e035374012ee..000000000000 --- a/packages/docusaurus-theme-common/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {useCallback} from 'react'; -import {useDocsPreferredVersionContext} from './DocsPreferredVersionProvider'; -import { - useAllDocsData, - useDocsData, - type GlobalVersion, -} from '@docusaurus/plugin-content-docs/client'; - -import {DEFAULT_PLUGIN_ID} from '@docusaurus/constants'; - -// Note, the preferredVersion attribute will always be null before mount -export function useDocsPreferredVersion( - pluginId: string | undefined = DEFAULT_PLUGIN_ID, -): { - preferredVersion: GlobalVersion | null | undefined; - savePreferredVersionName: (versionName: string) => void; -} { - const docsData = useDocsData(pluginId); - const [state, api] = useDocsPreferredVersionContext(); - - const {preferredVersionName} = state[pluginId]!; - - const preferredVersion = preferredVersionName - ? docsData.versions.find((version) => version.name === preferredVersionName) - : null; - - const savePreferredVersionName = useCallback( - (versionName: string) => { - api.savePreferredVersion(pluginId, versionName); - }, - [api, pluginId], - ); - - return {preferredVersion, savePreferredVersionName} as const; -} - -export function useDocsPreferredVersionByPluginId(): Record< - string, - GlobalVersion | null | undefined -> { - const allDocsData = useAllDocsData(); - const [state] = useDocsPreferredVersionContext(); - - function getPluginIdPreferredVersion(pluginId: string) { - const docsData = allDocsData[pluginId]!; - const {preferredVersionName} = state[pluginId]!; - - return preferredVersionName - ? docsData.versions.find( - (version) => version.name === preferredVersionName, - ) - : null; - } - - const pluginIds = Object.keys(allDocsData); - - const result: Record = {}; - pluginIds.forEach((pluginId) => { - result[pluginId] = getPluginIdPreferredVersion(pluginId); - }); - - return result; -} diff --git a/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx similarity index 96% rename from packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx rename to packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx index d5bedcb8cef2..3e983234f961 100644 --- a/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenuUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx @@ -14,9 +14,8 @@ import React, { type ReactNode, type ComponentType, } from 'react'; -import {ReactContextError} from './reactUtils'; -import {usePrevious} from './usePrevious'; -import {useNavbarMobileSidebar} from './navbarUtils'; +import {ReactContextError, usePrevious} from './reactUtils'; +import {useNavbarMobileSidebar} from '../contexts/navbarMobileSidebar'; /* The idea behind all this is that a specific component must be able to fill a diff --git a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx index f6a1bc9d7848..b9433574caae 100644 --- a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx @@ -5,24 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -import React, { - type ReactNode, - useCallback, - useEffect, - useState, - useMemo, -} from 'react'; -import useWindowSize from '../hooks/useWindowSize'; -import {useHistoryPopHandler} from './historyUtils'; -import {NavbarSecondaryMenuProvider} from './navbarSecondaryMenuUtils'; -import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; -import {useThemeConfig} from './useThemeConfig'; -import {ReactContextError} from './reactUtils'; +import React, {type ReactNode} from 'react'; +import {NavbarMobileSidebarProvider} from '../contexts/navbarMobileSidebar'; +import {NavbarSecondaryMenuProvider} from './navbarSecondaryMenu'; const DefaultNavItemPosition = 'right'; -// If split links by left/right -// if position is unspecified, fallback to right +/** + * Split links by left/right. If position is unspecified, fallback to right. + */ export function splitNavbarItems( items: T[], ): [leftItems: T[], rightItems: T[]] { @@ -36,90 +27,10 @@ export function splitNavbarItems( return [leftItems, rightItems]; } -type NavbarMobileSidebarContextValue = { - disabled: boolean; - shouldRender: boolean; - toggle: () => void; - shown: boolean; -}; - -const NavbarMobileSidebarContext = React.createContext< - NavbarMobileSidebarContextValue | undefined ->(undefined); - -// Mobile sidebar can be disabled in case it would lead to an empty sidebar -// In this case it's not useful to display a navbar sidebar toggle button -function useNavbarMobileSidebarDisabled() { - const activeDocPlugin = useActivePlugin(); - const {items} = useThemeConfig().navbar; - return items.length === 0 && !activeDocPlugin; -} - -function useNavbarMobileSidebarContextValue(): NavbarMobileSidebarContextValue { - const disabled = useNavbarMobileSidebarDisabled(); - const windowSize = useWindowSize(); - - // Mobile sidebar not visible until user interaction: can avoid SSR rendering - const shouldRender = !disabled && windowSize === 'mobile'; // || windowSize === 'ssr'; - - const [shown, setShown] = useState(false); - - // Close mobile sidebar on navigation pop - // Most likely firing when using the Android back button (but not only) - useHistoryPopHandler(() => { - if (shown) { - setShown(false); - // Should we prevent the navigation here? - // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846 - return false; // prevent pop navigation - } - return undefined; - }); - - const toggle = useCallback(() => { - setShown((s) => !s); - }, []); - - useEffect(() => { - if (windowSize === 'desktop') { - setShown(false); - } - }, [windowSize]); - - // Return stable context value - return useMemo( - () => ({ - disabled, - shouldRender, - toggle, - shown, - }), - [disabled, shouldRender, toggle, shown], - ); -} - -function NavbarMobileSidebarProvider({ - children, -}: { - children: ReactNode; -}): JSX.Element { - const value = useNavbarMobileSidebarContextValue(); - return ( - - {children} - - ); -} - -export function useNavbarMobileSidebar(): NavbarMobileSidebarContextValue { - const context = React.useContext(NavbarMobileSidebarContext); - if (context == null) { - throw new ReactContextError('NavbarMobileSidebarProvider'); - } - return context; -} - -// Add all Navbar providers at once +/** + * Composes the `NavbarMobileSidebarProvider` and `NavbarSecondaryMenuProvider`. + * Because the latter depends on the former, they can't be re-ordered. + */ export function NavbarProvider({children}: {children: ReactNode}): JSX.Element { return ( diff --git a/packages/docusaurus-theme-common/src/utils/pathUtils.ts b/packages/docusaurus-theme-common/src/utils/pathUtils.ts index 9441add949c4..a3eacf47238b 100644 --- a/packages/docusaurus-theme-common/src/utils/pathUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/pathUtils.ts @@ -5,7 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -// Compare the 2 paths, case insensitive and ignoring trailing slash +/** + * Compare the 2 paths, case insensitive and ignoring trailing slash + */ export const isSamePath = ( path1: string | undefined, path2: string | undefined, diff --git a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx index e1555c17506b..b2e5d5c0436b 100644 --- a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx @@ -6,6 +6,7 @@ */ import {useCallback, useEffect, useLayoutEffect, useRef} from 'react'; +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; /** * This hook is like useLayoutEffect, but without the SSR warning @@ -14,12 +15,13 @@ import {useCallback, useEffect, useLayoutEffect, useRef} from 'react'; * It is useful when you need to update a ref as soon as possible after a React * render (before `useEffect`) */ -export const useIsomorphicLayoutEffect = - typeof window !== 'undefined' ? useLayoutEffect : useEffect; +export const useIsomorphicLayoutEffect = ExecutionEnvironment.canUseDOM + ? useLayoutEffect + : useEffect; /** * Permits to transform an unstable callback (like an arrow function provided as - * props) to a "stable" callback that is safe to use in a useEffect dependency + * props) to a "stable" callback that is safe to use in a `useEffect` dependency * array. Useful to avoid React stale closure problems + avoid useless effect * re-executions * @@ -42,6 +44,16 @@ export function useDynamicCallback unknown>( return useCallback((...args) => ref.current(...args), []); } +export function usePrevious(value: T): T | undefined { + const ref = useRef(); + + useIsomorphicLayoutEffect(() => { + ref.current = value; + }); + + return ref.current; +} + export class ReactContextError extends Error { constructor(providerName: string, additionalInfo?: string) { super(); diff --git a/packages/docusaurus-theme-common/src/utils/routesUtils.ts b/packages/docusaurus-theme-common/src/utils/routesUtils.ts index ceb76dd2b294..e826771119c6 100644 --- a/packages/docusaurus-theme-common/src/utils/routesUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/routesUtils.ts @@ -10,8 +10,11 @@ import {useMemo} from 'react'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import type {Route} from '@docusaurus/types'; -// Note that all sites don't always have a homepage in practice -// See https://github.com/facebook/docusaurus/pull/6517#issuecomment-1048709116 +/** + * Note that sites don't always have a homepage in practice, so we can't assume + * that linking to '/' is always safe. + * @see https://github.com/facebook/docusaurus/pull/6517#issuecomment-1048709116 + */ export function findHomePageRoute({ baseUrl, routes: initialRoutes, diff --git a/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts b/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts index 3461777f7e15..28f9231a371a 100644 --- a/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts +++ b/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts @@ -9,7 +9,7 @@ import { useAllDocsData, useActivePluginAndVersion, } from '@docusaurus/plugin-content-docs/client'; -import {useDocsPreferredVersionByPluginId} from './docsPreferredVersion/useDocsPreferredVersion'; +import {useDocsPreferredVersionByPluginId} from '../contexts/docsPreferredVersion'; import {docVersionSearchTag, DEFAULT_SEARCH_TAG} from './searchUtils'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; diff --git a/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts b/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts index 8e1615824216..a7097b13b56f 100644 --- a/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts +++ b/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts @@ -8,9 +8,11 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import {useLocation} from '@docusaurus/router'; -// Get the pathname of current route, without the optional site baseUrl -// - /docs/myDoc => /docs/myDoc -// - /baseUrl/docs/myDoc => /docs/myDoc +/** + * Get the pathname of current route, without the optional site baseUrl + * - /docs/myDoc => /docs/myDoc + * - /baseUrl/docs/myDoc => /docs/myDoc + */ export function useLocalPathname(): string { const { siteConfig: {baseUrl}, diff --git a/packages/docusaurus-theme-common/src/utils/useLocationChange.ts b/packages/docusaurus-theme-common/src/utils/useLocationChange.ts index 1aeaf69f0bd7..8d947257c38f 100644 --- a/packages/docusaurus-theme-common/src/utils/useLocationChange.ts +++ b/packages/docusaurus-theme-common/src/utils/useLocationChange.ts @@ -8,8 +8,7 @@ import {useEffect} from 'react'; import {useLocation} from '@docusaurus/router'; import type {Location} from 'history'; -import {usePrevious} from './usePrevious'; -import {useDynamicCallback} from './reactUtils'; +import {useDynamicCallback, usePrevious} from './reactUtils'; type LocationChangeEvent = { location: Location; diff --git a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts index 029dd1bca899..349047d216d7 100644 --- a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts +++ b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts @@ -50,17 +50,17 @@ function createLocalePluralForms(locale: string): LocalePluralForms { } /** - * Poor man's PluralSelector implementation, using an english fallback. We want - * a lightweight, future-proof and good-enough solution. We don't want a perfect - * and heavy solution. + * Poor man's `PluralSelector` implementation, using an English fallback. We + * want a lightweight, future-proof and good-enough solution. We don't want a + * perfect and heavy solution. * * Docusaurus classic theme has only 2 deeply nested labels requiring complex - * plural rules. We don't want to use Intl + PluralRules polyfills + full ICU - * syntax (react-intl) just for that. + * plural rules. We don't want to use `Intl` + `PluralRules` polyfills + full + * ICU syntax (react-intl) just for that. * * Notes: - * - 2021: 92+% Browsers support Intl.PluralRules, and support will increase in - * the future + * - 2021: 92+% Browsers support `Intl.PluralRules`, and support will increase + * in the future * - NodeJS >= 13 has full ICU support by default * - In case of "mismatch" between SSR and Browser ICU support, React keeps * working! diff --git a/packages/docusaurus-theme-common/src/utils/usePrevious.ts b/packages/docusaurus-theme-common/src/utils/usePrevious.ts deleted file mode 100644 index 22cb744e05bd..000000000000 --- a/packages/docusaurus-theme-common/src/utils/usePrevious.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {useRef} from 'react'; -import {useIsomorphicLayoutEffect} from './reactUtils'; - -export function usePrevious(value: T): T | undefined { - const ref = useRef(); - - useIsomorphicLayoutEffect(() => { - ref.current = value; - }); - - return ref.current; -} diff --git a/packages/docusaurus/src/client/__tests__/routeContext.test.tsx b/packages/docusaurus/src/client/__tests__/routeContext.test.tsx new file mode 100644 index 000000000000..558cf157a66f --- /dev/null +++ b/packages/docusaurus/src/client/__tests__/routeContext.test.tsx @@ -0,0 +1,89 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks/server'; +import {RouteContextProvider} from '../routeContext'; +import useRouteContext from '../exports/useRouteContext'; + +describe('RouteContextProvider', () => { + it('creates root route context registered by plugin', () => { + expect( + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toEqual({plugin: {id: 'test', name: 'test'}}); + }); + it('throws if there is no route context at all', () => { + expect( + () => + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + {children} + ), + }).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Unexpected: no Docusaurus route context found"`, + ); + }); + it('throws if there is no parent context created by plugin', () => { + expect( + () => + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + + {children} + + ), + }).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Unexpected: Docusaurus topmost route context has no \`plugin\` attribute"`, + ); + }); + it('merges route context created by parent', () => { + expect( + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + + + {children} + + + ), + }).result.current, + ).toEqual({ + data: {some: 'data', someMore: 'data'}, + plugin: {id: 'test', name: 'test'}, + }); + }); + it('never overrides the plugin attribute', () => { + expect( + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + + + {children} + + + ), + }).result.current, + ).toEqual({ + data: {some: 'data', someMore: 'data'}, + plugin: {id: 'test', name: 'test'}, + }); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/Head.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Head.test.tsx new file mode 100644 index 000000000000..847fa52391f7 --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/Head.test.tsx @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Head from '../Head'; +import {type FilledContext, HelmetProvider} from 'react-helmet-async'; +import renderer from 'react-test-renderer'; + +describe('Head', () => { + it('does exactly what Helmet does', () => { + const context = {}; + expect( + renderer + .create( + + + + + + + + + + + + +

    + , + ) + .toJSON(), + ).toMatchSnapshot(); + expect((context as FilledContext).helmet).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Head.test.tsx.snap b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Head.test.tsx.snap new file mode 100644 index 000000000000..419daccd48d6 --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Head.test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Head does exactly what Helmet does 1`] = ` +
    + Content +
    +`; + +exports[`Head does exactly what Helmet does 2`] = ` + + + + + + + + + + + + +`; diff --git a/packages/docusaurus/src/client/exports/__tests__/useRouteContext.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useRouteContext.test.tsx new file mode 100644 index 000000000000..d1c469cdc0ed --- /dev/null +++ b/packages/docusaurus/src/client/exports/__tests__/useRouteContext.test.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks/server'; +import {RouteContextProvider} from '../../routeContext'; +import useRouteContext from '../useRouteContext'; + +describe('useRouteContext', () => { + it('throws when there is no route context at all', () => { + expect( + () => renderHook(() => useRouteContext()).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Unexpected: no Docusaurus route context found"`, + ); + }); + it('returns merged route contexts', () => { + expect( + renderHook(() => useRouteContext(), { + wrapper: ({children}) => ( + + + {children} + + + ), + }).result.current, + ).toEqual({ + data: {some: 'data', someMore: 'data'}, + plugin: {id: 'test', name: 'test'}, + }); + }); +}); diff --git a/packages/docusaurus/src/client/exports/useRouteContext.tsx b/packages/docusaurus/src/client/exports/useRouteContext.tsx index 79c57fa9ae2c..9ba1a1f57039 100644 --- a/packages/docusaurus/src/client/exports/useRouteContext.tsx +++ b/packages/docusaurus/src/client/exports/useRouteContext.tsx @@ -12,9 +12,7 @@ import {Context} from '../routeContext'; export default function useRouteContext(): PluginRouteContext { const context = React.useContext(Context); if (!context) { - throw new Error( - 'Unexpected: no Docusaurus parent/current route context found', - ); + throw new Error('Unexpected: no Docusaurus route context found'); } return context; } diff --git a/packages/docusaurus/src/client/routeContext.tsx b/packages/docusaurus/src/client/routeContext.tsx index 78e87a5a65a4..1b285859b841 100644 --- a/packages/docusaurus/src/client/routeContext.tsx +++ b/packages/docusaurus/src/client/routeContext.tsx @@ -19,12 +19,10 @@ function mergeContexts({ }): PluginRouteContext { if (!parent) { if (!value) { - throw new Error( - 'Unexpected: no Docusaurus parent/current route context found', - ); + throw new Error('Unexpected: no Docusaurus route context found'); } else if (!('plugin' in value)) { throw new Error( - 'Unexpected: Docusaurus parent route context has no plugin attribute', + 'Unexpected: Docusaurus topmost route context has no `plugin` attribute', ); } return value; @@ -45,7 +43,8 @@ export function RouteContextProvider({ value, }: { children: ReactNode; - value: PluginRouteContext | null; + // Only topmost route has the `plugin` attribute + value: PluginRouteContext | RouteContext | null; }): JSX.Element { const parent = React.useContext(Context); diff --git a/website/src/utils/__tests__/jsUtils.test.ts b/website/src/utils/__tests__/jsUtils.test.ts new file mode 100644 index 000000000000..70dee1e5bafb --- /dev/null +++ b/website/src/utils/__tests__/jsUtils.test.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {toggleListItem} from '../jsUtils'; + +describe('toggleListItem', () => { + it('removes item already in list', () => { + expect(toggleListItem([1, 2, 3], 2)).toEqual([1, 3]); + }); + it('appends item not in list', () => { + expect(toggleListItem([1, 2], 3)).toEqual([1, 2, 3]); + }); +}); diff --git a/yarn.lock b/yarn.lock index 71562635423e..6795d6385923 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11669,6 +11669,11 @@ jest-runtime@^27.5.1: slash "^3.0.0" strip-bom "^4.0.0" +jest-serializer-react-helmet-async@^1.0.21: + version "1.0.21" + resolved "https://registry.yarnpkg.com/jest-serializer-react-helmet-async/-/jest-serializer-react-helmet-async-1.0.21.tgz#bf2aee7522909bc4c933a0911db236b92db4685c" + integrity sha512-oJARA6ACc3QNR4s/EUjecLQclGf2+vMO0azoiEBwjJrsDHGHkMHcM935+r7aGkmteY1awdoyQ78ZGDiC7dwtsw== + jest-serializer@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" From 44107fb879a619ccea24f597fe0f5758eda99b63 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 22 Mar 2022 16:00:05 +0800 Subject: [PATCH 045/405] chore(types): remove querystring from dependencies (#6957) * chore(types): remove querystring from dependencies * fix lock --- packages/docusaurus-types/package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index b401067d23a7..59eec31416ef 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -18,7 +18,6 @@ "dependencies": { "commander": "^5.1.0", "joi": "^17.6.0", - "querystring": "0.2.1", "utility-types": "^3.10.0", "webpack": "^5.70.0", "webpack-merge": "^5.8.0" diff --git a/yarn.lock b/yarn.lock index 6795d6385923..675056fc673d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15660,11 +15660,6 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== -querystring@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" From 6e2eb44964951861a395682eaa1008b73d5cce43 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 22 Mar 2022 19:40:56 +0800 Subject: [PATCH 046/405] refactor: unify how validateOptions is handled (#6961) * refactor: unify how validateOptions is handled * fix types * fix again --- .../src/__tests__/options.test.ts | 7 +- .../src/index.ts | 4 +- .../src/options.ts | 8 +- .../__snapshots__/options.test.ts.snap | 5 + .../pluginOptionSchema.test.ts.snap | 5 - .../src/__tests__/feed.test.ts | 2 +- ...rontMatter.test.ts => frontMatter.test.ts} | 2 +- .../src/__tests__/index.test.ts | 29 +-- .../src/__tests__/options.test.ts | 160 ++++++++++++++++ .../src/__tests__/pluginOptionSchema.test.ts | 152 --------------- .../src/__tests__/translations.test.ts | 2 +- .../src/blogUtils.ts | 2 +- .../{blogFrontMatter.ts => frontMatter.ts} | 0 .../src/index.ts | 17 +- .../src/{pluginOptionSchema.ts => options.ts} | 18 +- ...rontMatter.test.ts => frontMatter.test.ts} | 2 +- .../src/__tests__/index.test.ts | 133 +++++++++----- .../src/__tests__/options.test.ts | 173 ++++++++---------- .../src/docs.ts | 2 +- .../src/{docFrontMatter.ts => frontMatter.ts} | 0 .../src/options.ts | 14 +- .../src/__tests__/index.test.ts | 21 ++- ...inOptionSchema.test.ts => options.test.ts} | 40 ++-- .../{pageFrontMatter.ts => frontMatter.ts} | 0 .../src/index.ts | 20 +- .../src/{pluginOptionSchema.ts => options.ts} | 13 +- .../src/index.ts | 7 +- .../src/index.ts | 7 +- .../src/index.ts | 3 +- packages/docusaurus-plugin-pwa/src/options.ts | 10 +- .../src/__tests__/options.test.ts | 52 ++++++ .../src/__tests__/pluginOptionSchema.test.ts | 55 ------ .../docusaurus-plugin-sitemap/src/index.ts | 19 +- .../src/{pluginOptionSchema.ts => options.ts} | 13 +- .../src/plugin-sitemap.d.ts | 1 + .../docusaurus-theme-classic/src/index.ts | 4 +- .../src/validateThemeConfig.ts | 10 +- .../src/validateThemeConfig.ts | 10 +- .../src/validateThemeConfig.ts | 10 +- packages/docusaurus-types/src/index.d.ts | 22 +-- .../src/__tests__/validationUtils.test.ts | 3 + .../src/validationUtils.ts | 3 +- .../docusaurus/src/server/plugins/init.ts | 2 +- 43 files changed, 532 insertions(+), 530 deletions(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap delete mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap rename packages/docusaurus-plugin-content-blog/src/__tests__/{blogFrontMatter.test.ts => frontMatter.test.ts} (99%) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts delete mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts rename packages/docusaurus-plugin-content-blog/src/{blogFrontMatter.ts => frontMatter.ts} (100%) rename packages/docusaurus-plugin-content-blog/src/{pluginOptionSchema.ts => options.ts} (91%) rename packages/docusaurus-plugin-content-docs/src/__tests__/{docFrontMatter.test.ts => frontMatter.test.ts} (99%) rename packages/docusaurus-plugin-content-docs/src/{docFrontMatter.ts => frontMatter.ts} (100%) rename packages/docusaurus-plugin-content-pages/src/__tests__/{pluginOptionSchema.test.ts => options.test.ts} (53%) rename packages/docusaurus-plugin-content-pages/src/{pageFrontMatter.ts => frontMatter.ts} (100%) rename packages/docusaurus-plugin-content-pages/src/{pluginOptionSchema.ts => options.ts} (79%) create mode 100644 packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts delete mode 100644 packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts rename packages/docusaurus-plugin-sitemap/src/{pluginOptionSchema.ts => options.ts} (71%) diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts index a8e57816a396..0354dcfe995a 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/options.test.ts @@ -15,11 +15,14 @@ function testValidate(options: Options) { describe('normalizePluginOptions', () => { it('returns default options for undefined user options', () => { - expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS); + expect(testValidate(undefined)).toEqual({ + ...DEFAULT_OPTIONS, + id: 'default', + }); }); it('returns default options for empty user options', () => { - expect(testValidate(undefined)).toEqual(DEFAULT_OPTIONS); + expect(testValidate({})).toEqual({...DEFAULT_OPTIONS, id: 'default'}); }); it('overrides one default options with valid user options', () => { diff --git a/packages/docusaurus-plugin-client-redirects/src/index.ts b/packages/docusaurus-plugin-client-redirects/src/index.ts index d5a20c405935..21ec1195f373 100644 --- a/packages/docusaurus-plugin-client-redirects/src/index.ts +++ b/packages/docusaurus-plugin-client-redirects/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {LoadContext, Plugin, Props} from '@docusaurus/types'; +import type {LoadContext, Plugin} from '@docusaurus/types'; import type {PluginContext, RedirectMetadata} from './types'; import type {PluginOptions} from '@docusaurus/plugin-client-redirects'; @@ -24,7 +24,7 @@ export default function pluginClientRedirectsPages( return { name: 'docusaurus-plugin-client-redirects', - async postBuild(props: Props) { + async postBuild(props) { const pluginContext: PluginContext = { relativeRoutesPaths: props.routesPaths.map( (path) => `${addLeadingSlash(removePrefix(path, props.baseUrl))}`, diff --git a/packages/docusaurus-plugin-client-redirects/src/options.ts b/packages/docusaurus-plugin-client-redirects/src/options.ts index 1e997227c9c7..d81b535482b8 100644 --- a/packages/docusaurus-plugin-client-redirects/src/options.ts +++ b/packages/docusaurus-plugin-client-redirects/src/options.ts @@ -7,12 +7,10 @@ import type { PluginOptions, + Options, RedirectOption, } from '@docusaurus/plugin-client-redirects'; -import type { - OptionValidationContext, - ValidationResult, -} from '@docusaurus/types'; +import type {OptionValidationContext} from '@docusaurus/types'; import {Joi, PathnameSchema} from '@docusaurus/utils-validation'; export const DEFAULT_OPTIONS: Partial = { @@ -47,6 +45,6 @@ const UserOptionsSchema = Joi.object({ export function validateOptions({ validate, options: userOptions, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { return validate(UserOptionsSchema, userOptions); } diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap new file mode 100644 index 000000000000..76f0a53c41b7 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`validateOptions throws Error in case of invalid feed type 1`] = `"\\"feedOptions.type\\" does not match any of the allowed types"`; + +exports[`validateOptions throws Error in case of invalid options 1`] = `"\\"postsPerPage\\" must be greater than or equal to 1"`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap deleted file mode 100644 index c598236fd0eb..000000000000 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`blog plugin options schema throws Error in case of invalid feed type 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`; - -exports[`blog plugin options schema throws Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be greater than or equal to 1]`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index 03b4abb14d78..facf967523db 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -11,7 +11,7 @@ import fs from 'fs-extra'; import {createBlogFeedFiles} from '../feed'; import type {LoadContext, I18n} from '@docusaurus/types'; import type {BlogContentPaths} from '../types'; -import {DEFAULT_OPTIONS} from '../pluginOptionSchema'; +import {DEFAULT_OPTIONS} from '../options'; import {generateBlogPosts} from '../blogUtils'; import type {PluginOptions} from '@docusaurus/plugin-content-blog'; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts similarity index 99% rename from packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts rename to packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts index b8d7d9047ff6..5a8dc0ebd8a0 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/blogFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {validateBlogPostFrontMatter} from '../blogFrontMatter'; +import {validateBlogPostFrontMatter} from '../frontMatter'; import escapeStringRegexp from 'escape-string-regexp'; import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog'; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 2a6d9d24f745..2a197366835e 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -9,9 +9,9 @@ import {jest} from '@jest/globals'; import path from 'path'; import pluginContentBlog from '../index'; import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types'; -import {PluginOptionSchema} from '../pluginOptionSchema'; +import {validateOptions} from '../options'; import type {BlogPost} from '../types'; -import type {Joi} from '@docusaurus/utils-validation'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; import {posixPath, getFileCommitDate} from '@docusaurus/utils'; import type { PluginOptions, @@ -47,18 +47,6 @@ function getI18n(locale: string): I18n { const DefaultI18N: I18n = getI18n('en'); -function validateAndNormalize( - schema: Joi.ObjectSchema, - options: Partial, -) { - const {value, error} = schema.validate(options); - if (error) { - throw error; - } else { - return value; - } -} - const PluginPath = 'blog'; const BaseEditUrl = 'https://baseEditUrl.com/edit'; @@ -81,11 +69,14 @@ const getPlugin = async ( generatedFilesDir, i18n, } as LoadContext, - validateAndNormalize(PluginOptionSchema, { - path: PluginPath, - editUrl: BaseEditUrl, - ...pluginOptions, - }), + validateOptions({ + validate: normalizePluginOptions, + options: { + path: PluginPath, + editUrl: BaseEditUrl, + ...pluginOptions, + }, + }) as PluginOptions, ); }; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts new file mode 100644 index 000000000000..738884dd0297 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts @@ -0,0 +1,160 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {validateOptions, DEFAULT_OPTIONS} from '../options'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; +import type {Options} from '@docusaurus/plugin-content-blog'; + +function testValidate(options: Options) { + return validateOptions({validate: normalizePluginOptions, options}); +} + +// the type of remark/rehype plugins can be either function, object or array +const markdownPluginsFunctionStub = () => {}; +const markdownPluginsObjectStub = {}; + +const defaultOptions = {...DEFAULT_OPTIONS, id: 'default'}; + +describe('validateOptions', () => { + it('returns default options for undefined user options', () => { + expect(testValidate(undefined)).toEqual(defaultOptions); + }); + + it('returns default options for empty user options', () => { + expect(testValidate({})).toEqual(defaultOptions); + }); + + it('accepts correctly defined user options', () => { + const userOptions = { + ...defaultOptions, + feedOptions: {type: 'rss' as const, title: 'myTitle'}, + path: 'not_blog', + routeBasePath: 'myBlog', + postsPerPage: 5, + include: ['api/*', 'docs/*'], + }; + expect(testValidate(userOptions)).toEqual({ + ...userOptions, + feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, + }); + }); + + it('accepts valid user options', () => { + const userOptions = { + ...defaultOptions, + routeBasePath: 'myBlog', + beforeDefaultRemarkPlugins: [], + beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], + remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], + rehypePlugins: [ + markdownPluginsObjectStub, + [markdownPluginsFunctionStub, {option1: '42'}], + ], + }; + expect(testValidate(userOptions)).toEqual(userOptions); + }); + + it('throws Error in case of invalid options', () => { + expect(() => + testValidate({ + path: 'not_blog', + postsPerPage: -1, + include: ['api/*', 'docs/*'], + routeBasePath: 'not_blog', + }), + ).toThrowErrorMatchingSnapshot(); + }); + + it('throws Error in case of invalid feed type', () => { + expect(() => + testValidate({ + feedOptions: { + type: 'none', + }, + }), + ).toThrowErrorMatchingSnapshot(); + }); + + it('converts all feed type to array with other feed type', () => { + expect( + testValidate({ + feedOptions: {type: 'all'}, + }), + ).toEqual({ + ...defaultOptions, + feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''}, + }); + }); + + it('accepts null type and return same', () => { + expect( + testValidate({ + feedOptions: {type: null}, + }), + ).toEqual({ + ...defaultOptions, + feedOptions: {type: null}, + }); + }); + + it('contains array with rss + atom for missing feed type', () => { + expect( + testValidate({ + feedOptions: {}, + }), + ).toEqual(defaultOptions); + }); + + it('has array with rss + atom, title for missing feed type', () => { + expect( + testValidate({ + feedOptions: {title: 'title'}, + }), + ).toEqual({ + ...defaultOptions, + feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''}, + }); + }); + + it('accepts 0 sidebar count', () => { + const userOptions = {blogSidebarCount: 0}; + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); + }); + + it('accepts "ALL" sidebar count', () => { + const userOptions = {blogSidebarCount: 'ALL' as const}; + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); + }); + + it('rejects "abcdef" sidebar count', () => { + const userOptions = {blogSidebarCount: 'abcdef'}; + expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot( + `"\\"blogSidebarCount\\" must be one of [ALL, number]"`, + ); + }); + + it('accepts "all posts" sidebar title', () => { + const userOptions = {blogSidebarTitle: 'all posts'}; + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); + }); + + it('rejects 42 sidebar title', () => { + const userOptions = {blogSidebarTitle: 42}; + expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot( + `"\\"blogSidebarTitle\\" must be a string"`, + ); + }); +}); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts deleted file mode 100644 index 5aa55c353510..000000000000 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; - -// the type of remark/rehype plugins can be either function, object or array -const markdownPluginsFunctionStub = () => {}; -const markdownPluginsObjectStub = {}; - -describe('blog plugin options schema', () => { - it('normalizes options', () => { - const {value, error} = PluginOptionSchema.validate({}); - expect(value).toEqual(DEFAULT_OPTIONS); - expect(error).toBeUndefined(); - }); - - it('accepts correctly defined user options', () => { - const userOptions = { - ...DEFAULT_OPTIONS, - feedOptions: {type: 'rss', title: 'myTitle'}, - path: 'not_blog', - routeBasePath: 'myBlog', - postsPerPage: 5, - include: ['api/*', 'docs/*'], - }; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual({ - ...userOptions, - feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, - }); - expect(error).toBeUndefined(); - }); - - it('accepts valid user options', async () => { - const userOptions = { - ...DEFAULT_OPTIONS, - routeBasePath: 'myBlog', - beforeDefaultRemarkPlugins: [], - beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], - remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], - rehypePlugins: [ - markdownPluginsObjectStub, - [markdownPluginsFunctionStub, {option1: '42'}], - ], - }; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual(userOptions); - expect(error).toBeUndefined(); - }); - - it('throws Error in case of invalid options', () => { - const {error} = PluginOptionSchema.validate({ - path: 'not_blog', - postsPerPage: -1, - include: ['api/*', 'docs/*'], - routeBasePath: 'not_blog', - }); - - expect(error).toMatchSnapshot(); - }); - - it('throws Error in case of invalid feed type', () => { - const {error} = PluginOptionSchema.validate({ - feedOptions: { - type: 'none', - }, - }); - - expect(error).toMatchSnapshot(); - }); - - it('converts all feed type to array with other feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {type: 'all'}, - }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''}, - }); - }); - - it('accepts null type and return same', () => { - const {value, error} = PluginOptionSchema.validate({ - feedOptions: {type: null}, - }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: null}, - }); - expect(error).toBeUndefined(); - }); - - it('contains array with rss + atom for missing feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {}, - }); - expect(value).toEqual(DEFAULT_OPTIONS); - }); - - it('has array with rss + atom, title for missing feed type', () => { - const {value} = PluginOptionSchema.validate({ - feedOptions: {title: 'title'}, - }); - expect(value).toEqual({ - ...DEFAULT_OPTIONS, - feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''}, - }); - }); -}); - -describe('blog sidebar', () => { - it('accepts 0 sidebar count', () => { - const userOptions = {blogSidebarCount: 0}; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBeUndefined(); - }); - - it('accepts "ALL" sidebar count', () => { - const userOptions = {blogSidebarCount: 'ALL'}; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBeUndefined(); - }); - - it('rejects "abcdef" sidebar count', () => { - const userOptions = {blogSidebarCount: 'abcdef'}; - const {error} = PluginOptionSchema.validate(userOptions); - expect(error).toMatchInlineSnapshot( - `[ValidationError: "blogSidebarCount" must be one of [ALL, number]]`, - ); - }); - - it('accepts "all posts" sidebar title', () => { - const userOptions = {blogSidebarTitle: 'all posts'}; - const {value, error} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); - expect(error).toBeUndefined(); - }); - - it('rejects 42 sidebar title', () => { - const userOptions = {blogSidebarTitle: 42}; - const {error} = PluginOptionSchema.validate(userOptions); - expect(error).toMatchInlineSnapshot( - `[ValidationError: "blogSidebarTitle" must be a string]`, - ); - }); -}); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts index b6f950a10e53..840a3af4d359 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/translations.test.ts @@ -7,7 +7,7 @@ import type {BlogPost, BlogContent} from '../types'; import {getTranslationFiles, translateContent} from '../translations'; -import {DEFAULT_OPTIONS} from '../pluginOptionSchema'; +import {DEFAULT_OPTIONS} from '../options'; import {updateTranslationFileMessages} from '@docusaurus/utils'; import type {PluginOptions} from '@docusaurus/plugin-content-blog'; diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index a19f55d641fd..59b38a5e5e87 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -31,7 +31,7 @@ import { getContentPathList, } from '@docusaurus/utils'; import type {LoadContext} from '@docusaurus/types'; -import {validateBlogPostFrontMatter} from './blogFrontMatter'; +import {validateBlogPostFrontMatter} from './frontMatter'; import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors'; import logger from '@docusaurus/logger'; import type { diff --git a/packages/docusaurus-plugin-content-blog/src/blogFrontMatter.ts b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts similarity index 100% rename from packages/docusaurus-plugin-content-blog/src/blogFrontMatter.ts rename to packages/docusaurus-plugin-content-blog/src/frontMatter.ts diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 754aee6b11d1..d8338c97ce73 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -30,14 +30,7 @@ import type { BlogContentPaths, BlogMarkdownLoaderOptions, } from './types'; -import {PluginOptionSchema} from './pluginOptionSchema'; -import type { - LoadContext, - Plugin, - HtmlTags, - OptionValidationContext, - ValidationResult, -} from '@docusaurus/types'; +import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; import { generateBlogPosts, getSourceToPermalink, @@ -572,10 +565,4 @@ export default async function pluginContentBlog( }; } -export function validateOptions({ - validate, - options, -}: OptionValidationContext): ValidationResult { - const validatedOptions = validate(PluginOptionSchema, options); - return validatedOptions; -} +export {validateOptions} from './options'; diff --git a/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-content-blog/src/options.ts similarity index 91% rename from packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts rename to packages/docusaurus-plugin-content-blog/src/options.ts index 666ec5f22d9b..c4c344116324 100644 --- a/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-content-blog/src/options.ts @@ -13,7 +13,8 @@ import { URISchema, } from '@docusaurus/utils-validation'; import {GlobExcludeDefault} from '@docusaurus/utils'; -import type {PluginOptions} from '@docusaurus/plugin-content-blog'; +import type {PluginOptions, Options} from '@docusaurus/plugin-content-blog'; +import type {OptionValidationContext} from '@docusaurus/types'; export const DEFAULT_OPTIONS: PluginOptions = { feedOptions: {type: ['rss', 'atom'], copyright: ''}, @@ -46,7 +47,7 @@ export const DEFAULT_OPTIONS: PluginOptions = { sortPosts: 'descending', }; -export const PluginOptionSchema = Joi.object({ +const PluginOptionSchema = Joi.object({ path: Joi.string().default(DEFAULT_OPTIONS.path), archiveBasePath: Joi.string() .default(DEFAULT_OPTIONS.archiveBasePath) @@ -125,4 +126,15 @@ export const PluginOptionSchema = Joi.object({ sortPosts: Joi.string() .valid('descending', 'ascending') .default(DEFAULT_OPTIONS.sortPosts), -}); +}).default(DEFAULT_OPTIONS); + +export function validateOptions({ + validate, + options, +}: OptionValidationContext): PluginOptions { + const validatedOptions = validate( + PluginOptionSchema, + options, + ) as PluginOptions; + return validatedOptions; +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts similarity index 99% rename from packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts rename to packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index 5f8aa9d787e7..1fa4809c48db 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docFrontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {validateDocFrontMatter} from '../docFrontMatter'; +import {validateDocFrontMatter} from '../frontMatter'; import type {DocFrontMatter} from '../types'; import escapeStringRegexp from 'escape-string-regexp'; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 22c46c63725e..0d6df18fe915 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -20,7 +20,7 @@ import {posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import {sortConfig} from '@docusaurus/core/src/server/plugins'; import * as cliDocs from '../cli'; -import {OptionsSchema} from '../options'; +import {validateOptions} from '../options'; import {normalizePluginOptions} from '@docusaurus/utils-validation'; import type {LoadedVersion} from '../types'; import type { @@ -119,8 +119,11 @@ describe('sidebar', () => { const sidebarPath = path.join(siteDir, 'wrong-sidebars.json'); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - sidebarPath, + validateOptions({ + validate: normalizePluginOptions, + options: { + sidebarPath, + }, }), ); await expect(plugin.loadContent!()).rejects.toThrowErrorMatchingSnapshot(); @@ -133,8 +136,11 @@ describe('sidebar', () => { await expect(async () => { const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - sidebarPath: 'wrong-path-sidebar.json', + validateOptions({ + validate: normalizePluginOptions, + options: { + sidebarPath: 'wrong-path-sidebar.json', + }, }), ); await plugin.loadContent!(); @@ -152,8 +158,11 @@ describe('sidebar', () => { const context = await loadContext(siteDir); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - sidebarPath: undefined, + validateOptions({ + validate: normalizePluginOptions, + options: { + sidebarPath: undefined, + }, }), ); const result = await plugin.loadContent!(); @@ -167,8 +176,11 @@ describe('sidebar', () => { const context = await loadContext(siteDir); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - sidebarPath: false, + validateOptions({ + validate: normalizePluginOptions, + options: { + sidebarPath: false, + }, }), ); const result = await plugin.loadContent!(); @@ -186,7 +198,7 @@ describe('empty/no docs website', () => { await fs.ensureDir(path.join(siteDir, 'docs')); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, {}), + validateOptions({validate: normalizePluginOptions, options: {}}), ); await expect( plugin.loadContent!(), @@ -200,8 +212,11 @@ describe('empty/no docs website', () => { await expect( pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: `path/does/not/exist`, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'path/does/not/exist', + }, }), ), ).rejects.toThrowErrorMatchingInlineSnapshot( @@ -217,9 +232,12 @@ describe('simple website', () => { const sidebarPath = path.join(siteDir, 'sidebars.json'); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', - sidebarPath, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarPath, + }, }), ); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); @@ -328,9 +346,12 @@ describe('versioned website', () => { const routeBasePath = 'docs'; const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - routeBasePath, - sidebarPath, + validateOptions({ + validate: normalizePluginOptions, + options: { + routeBasePath, + sidebarPath, + }, }), ); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); @@ -455,11 +476,14 @@ describe('versioned website (community)', () => { const pluginId = 'community'; const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - id: 'community', - path: 'community', - routeBasePath, - sidebarPath, + validateOptions({ + validate: normalizePluginOptions, + options: { + id: 'community', + path: 'community', + routeBasePath, + sidebarPath, + }, }), ); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); @@ -558,9 +582,12 @@ describe('site with doc label', () => { const sidebarPath = path.join(siteDir, 'sidebars.json'); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', - sidebarPath, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarPath, + }, }), ); @@ -596,8 +623,11 @@ describe('site with full autogenerated sidebar', () => { const context = await loadContext(siteDir); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + }, }), ); @@ -648,14 +678,17 @@ describe('site with partial autogenerated sidebars', () => { const context = await loadContext(siteDir, {}); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', - sidebarPath: path.join( - __dirname, - '__fixtures__', - 'site-with-autogenerated-sidebar', - 'partialAutogeneratedSidebars.js', - ), + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarPath: path.join( + __dirname, + '__fixtures__', + 'site-with-autogenerated-sidebar', + 'partialAutogeneratedSidebars.js', + ), + }, }), ); @@ -701,14 +734,17 @@ describe('site with partial autogenerated sidebars 2 (fix #4638)', () => { const context = await loadContext(siteDir, {}); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', - sidebarPath: path.join( - __dirname, - '__fixtures__', - 'site-with-autogenerated-sidebar', - 'partialAutogeneratedSidebars2.js', - ), + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarPath: path.join( + __dirname, + '__fixtures__', + 'site-with-autogenerated-sidebar', + 'partialAutogeneratedSidebars2.js', + ), + }, }), ); @@ -735,9 +771,12 @@ describe('site with custom sidebar items generator', () => { const context = await loadContext(siteDir); const plugin = await pluginContentDocs( context, - normalizePluginOptions(OptionsSchema, { - path: 'docs', - sidebarItemsGenerator, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarItemsGenerator, + }, }), ); const content = (await plugin.loadContent?.())!; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index a4833aa6d7b3..89bec2179df3 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {OptionsSchema, DEFAULT_OPTIONS, validateOptions} from '../options'; +import {validateOptions, DEFAULT_OPTIONS} from '../options'; import {normalizePluginOptions} from '@docusaurus/utils-validation'; import {DefaultSidebarItemsGenerator} from '../sidebars/generator'; import { @@ -13,27 +13,26 @@ import { DisabledNumberPrefixParser, } from '../numberPrefix'; import {GlobExcludeDefault} from '@docusaurus/utils'; -import type {PluginOptions} from '@docusaurus/plugin-content-docs'; +import type {Options} from '@docusaurus/plugin-content-docs'; // the type of remark/rehype plugins is function const markdownPluginsFunctionStub = () => {}; const markdownPluginsObjectStub = {}; -function testValidateOptions(options: Partial) { - return validateOptions({ - options: { - ...DEFAULT_OPTIONS, - ...options, - }, - validate: normalizePluginOptions, - }); +function testValidate(options: Options) { + return validateOptions({validate: normalizePluginOptions, options}); } +const defaultOptions = { + ...DEFAULT_OPTIONS, + id: 'default', + // The admonitions plugin is automatically added. Not really worth testing + remarkPlugins: expect.any(Array), +}; + describe('normalizeDocsPluginOptions', () => { it('returns default options for undefined user options', async () => { - const {value, error} = await OptionsSchema.validate({}); - expect(value).toEqual(DEFAULT_OPTIONS); - expect(error).toBeUndefined(); + expect(testValidate({})).toEqual(defaultOptions); }); it('accepts correctly defined user options', async () => { @@ -77,14 +76,15 @@ describe('normalizeDocsPluginOptions', () => { sidebarCollapsible: false, sidebarCollapsed: false, }; - const {value, error} = await OptionsSchema.validate(userOptions); - expect(value).toEqual(userOptions); - expect(error).toBeUndefined(); + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + remarkPlugins: [...userOptions.remarkPlugins, expect.any(Array)], + }); }); it('accepts correctly defined remark and rehype plugin options', async () => { const userOptions = { - ...DEFAULT_OPTIONS, beforeDefaultRemarkPlugins: [], beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], @@ -93,85 +93,71 @@ describe('normalizeDocsPluginOptions', () => { [markdownPluginsFunctionStub, {option1: '42'}], ], }; - const {value, error} = await OptionsSchema.validate(userOptions); - expect(value).toEqual(userOptions); - expect(error).toBeUndefined(); + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + remarkPlugins: [...userOptions.remarkPlugins, expect.any(Array)], + }); }); it('accepts admonitions false', async () => { const admonitionsFalse = { - ...DEFAULT_OPTIONS, admonitions: false, }; - const {value, error} = OptionsSchema.validate(admonitionsFalse); - expect(value).toEqual(admonitionsFalse); - expect(error).toBeUndefined(); + expect(testValidate(admonitionsFalse)).toEqual({ + ...defaultOptions, + ...admonitionsFalse, + }); + }); + + it('rejects admonitions true', async () => { + const admonitionsTrue = { + admonitions: true, + }; + expect(() => + testValidate(admonitionsTrue), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"admonitions\\" contains an invalid value"`, + ); }); it('accepts numberPrefixParser function', () => { function customNumberPrefixParser() {} expect( - normalizePluginOptions(OptionsSchema, { - ...DEFAULT_OPTIONS, - numberPrefixParser: customNumberPrefixParser, - }), + testValidate({numberPrefixParser: customNumberPrefixParser}), ).toEqual({ - ...DEFAULT_OPTIONS, - id: 'default', + ...defaultOptions, numberPrefixParser: customNumberPrefixParser, }); }); it('accepts numberPrefixParser false', () => { - expect( - normalizePluginOptions(OptionsSchema, { - ...DEFAULT_OPTIONS, - numberPrefixParser: false, - }), - ).toEqual({ - ...DEFAULT_OPTIONS, - id: 'default', + expect(testValidate({numberPrefixParser: false})).toEqual({ + ...defaultOptions, numberPrefixParser: DisabledNumberPrefixParser, }); }); it('accepts numberPrefixParser true', () => { - expect( - normalizePluginOptions(OptionsSchema, { - ...DEFAULT_OPTIONS, - numberPrefixParser: true, - }), - ).toEqual({ - ...DEFAULT_OPTIONS, - id: 'default', + expect(testValidate({numberPrefixParser: true})).toEqual({ + ...defaultOptions, numberPrefixParser: DefaultNumberPrefixParser, }); }); - it('rejects admonitions true', async () => { - const admonitionsTrue = { - ...DEFAULT_OPTIONS, - admonitions: true, - }; - const {error} = OptionsSchema.validate(admonitionsTrue); - expect(error).toMatchInlineSnapshot( - `[ValidationError: "admonitions" contains an invalid value]`, - ); - }); - it('rejects invalid remark plugin options', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { + expect(() => + testValidate({ remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]], - }); - }).toThrowErrorMatchingInlineSnapshot( + }), + ).toThrowErrorMatchingInlineSnapshot( `"\\"remarkPlugins[0]\\" does not match any of the allowed types"`, ); }); it('rejects invalid rehype plugin options', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { + expect(() => + testValidate({ rehypePlugins: [ [ markdownPluginsFunctionStub, @@ -179,61 +165,51 @@ describe('normalizeDocsPluginOptions', () => { markdownPluginsFunctionStub, ], ], - }); - }).toThrowErrorMatchingInlineSnapshot( + }), + ).toThrowErrorMatchingInlineSnapshot( `"\\"rehypePlugins[0]\\" does not match any of the allowed types"`, ); }); it('rejects bad path inputs', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { - path: 2, - }); - }).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`); + expect(() => testValidate({path: 2})).toThrowErrorMatchingInlineSnapshot( + `"\\"path\\" must be a string"`, + ); }); it('rejects bad include inputs', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { - include: '**/*.{md,mdx}', - }); - }).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`); + expect(() => + testValidate({include: '**/*.{md,mdx}'}), + ).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`); }); it('rejects bad showLastUpdateTime inputs', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { - showLastUpdateTime: 'true', - }); - }).toThrowErrorMatchingInlineSnapshot( + expect(() => + testValidate({showLastUpdateTime: 'true'}), + ).toThrowErrorMatchingInlineSnapshot( `"\\"showLastUpdateTime\\" must be a boolean"`, ); }); it('rejects bad remarkPlugins input', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { - remarkPlugins: 'remark-math', - }); - }).toThrowErrorMatchingInlineSnapshot( + expect(() => + testValidate({remarkPlugins: 'remark-math'}), + ).toThrowErrorMatchingInlineSnapshot( `"\\"remarkPlugins\\" must be an array"`, ); }); it('rejects bad lastVersion', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { - lastVersion: false, - }); - }).toThrowErrorMatchingInlineSnapshot( + expect(() => + testValidate({lastVersion: false}), + ).toThrowErrorMatchingInlineSnapshot( `"\\"lastVersion\\" must be a string"`, ); }); it('rejects bad versions', () => { - expect(() => { - normalizePluginOptions(OptionsSchema, { + expect(() => + testValidate({ versions: { current: { hey: 3, @@ -243,32 +219,29 @@ describe('normalizeDocsPluginOptions', () => { label: 'world', }, }, - }); - }).toThrowErrorMatchingInlineSnapshot( + }), + ).toThrowErrorMatchingInlineSnapshot( `"\\"versions.current.hey\\" is not allowed"`, ); }); it('handles sidebarCollapsed option inconsistencies', () => { expect( - testValidateOptions({ - ...DEFAULT_OPTIONS, + testValidate({ sidebarCollapsible: true, sidebarCollapsed: undefined, }).sidebarCollapsed, ).toBe(true); expect( - testValidateOptions({ - ...DEFAULT_OPTIONS, + testValidate({ sidebarCollapsible: false, sidebarCollapsed: undefined, }).sidebarCollapsed, ).toBe(false); expect( - testValidateOptions({ - ...DEFAULT_OPTIONS, + testValidate({ sidebarCollapsible: false, sidebarCollapsed: true, }).sidebarCollapsed, diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 9fcfa8ee324f..c94ff470b0f2 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -34,7 +34,7 @@ import getSlug from './slug'; import {CURRENT_VERSION_NAME} from './constants'; import {getDocsDirPaths} from './versions'; import {stripPathNumberPrefixes} from './numberPrefix'; -import {validateDocFrontMatter} from './docFrontMatter'; +import {validateDocFrontMatter} from './frontMatter'; import type {SidebarsUtils} from './sidebars/utils'; import {toDocNavigationLink, toNavigationLink} from './sidebars/utils'; import type { diff --git a/packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/docFrontMatter.ts rename to packages/docusaurus-plugin-content-docs/src/frontMatter.ts diff --git a/packages/docusaurus-plugin-content-docs/src/options.ts b/packages/docusaurus-plugin-content-docs/src/options.ts index 3e5e9f5a7a97..258236acaaea 100644 --- a/packages/docusaurus-plugin-content-docs/src/options.ts +++ b/packages/docusaurus-plugin-content-docs/src/options.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {PluginOptions} from '@docusaurus/plugin-content-docs'; +import type {PluginOptions, Options} from '@docusaurus/plugin-content-docs'; import { Joi, RemarkPluginsSchema, @@ -15,10 +15,7 @@ import { } from '@docusaurus/utils-validation'; import {GlobExcludeDefault} from '@docusaurus/utils'; -import type { - OptionValidationContext, - ValidationResult, -} from '@docusaurus/types'; +import type {OptionValidationContext} from '@docusaurus/types'; import logger from '@docusaurus/logger'; import admonitions from 'remark-admonitions'; import {DefaultSidebarItemsGenerator} from './sidebars/generator'; @@ -70,7 +67,7 @@ const VersionsOptionsSchema = Joi.object() .pattern(Joi.string().required(), VersionOptionsSchema) .default(DEFAULT_OPTIONS.versions); -export const OptionsSchema = Joi.object({ +const OptionsSchema = Joi.object({ path: Joi.string().default(DEFAULT_OPTIONS.path), editUrl: Joi.alternatives().try(URISchema, Joi.function()), editCurrentVersion: Joi.boolean().default(DEFAULT_OPTIONS.editCurrentVersion), @@ -80,6 +77,7 @@ export const OptionsSchema = Joi.object({ // .allow('') "" .default(DEFAULT_OPTIONS.routeBasePath), tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath), + // @ts-expect-error: deprecated homePageId: Joi.any().forbidden().messages({ 'any.unknown': 'The docs plugin option homePageId is not supported anymore. To make a doc the "home", please add "slug: /" in its front matter. See: https://docusaurus.io/docs/next/docs-introduction#home-page-docs', @@ -146,7 +144,7 @@ export const OptionsSchema = Joi.object({ export function validateOptions({ validate, options: userOptions, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { let options = userOptions; if (options.sidebarCollapsible === false) { @@ -168,7 +166,7 @@ export function validateOptions({ } } - const normalizedOptions = validate(OptionsSchema, options); + const normalizedOptions = validate(OptionsSchema, options) as PluginOptions; if (normalizedOptions.admonitions) { normalizedOptions.remarkPlugins = normalizedOptions.remarkPlugins.concat([ diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts index b71ffcdfad22..7e3df9c7d129 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts @@ -9,7 +9,8 @@ import path from 'path'; import {loadContext} from '@docusaurus/core/lib/server'; import pluginContentPages from '../index'; -import {PluginOptionSchema} from '../pluginOptionSchema'; +import {validateOptions} from '../options'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; describe('docusaurus-plugin-content-pages', () => { it('loads simple pages', async () => { @@ -17,9 +18,12 @@ describe('docusaurus-plugin-content-pages', () => { const context = await loadContext(siteDir); const plugin = await pluginContentPages( context, - PluginOptionSchema.validate({ - path: 'src/pages', - }).value, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'src/pages', + }, + }), ); const pagesMetadata = await plugin.loadContent!(); @@ -37,9 +41,12 @@ describe('docusaurus-plugin-content-pages', () => { currentLocale: 'fr', }, }, - PluginOptionSchema.validate({ - path: 'src/pages', - }).value, + validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'src/pages', + }, + }), ); const pagesMetadata = await plugin.loadContent!(); diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts similarity index 53% rename from packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts rename to packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts index 484ffac9159d..5038527034cb 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts @@ -5,31 +5,29 @@ * LICENSE file in the root directory of this source tree. */ -import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; -import type {PluginOptions} from '@docusaurus/plugin-content-pages'; +import {validateOptions, DEFAULT_OPTIONS} from '../options'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; +import type {Options} from '@docusaurus/plugin-content-pages'; -function normalizePluginOptions( - options: Partial, -): PluginOptions { - const {value, error} = PluginOptionSchema.validate(options, { - convert: false, - }); - if (error) { - throw error; - } else { - return value; - } +function testValidate(options: Options) { + return validateOptions({validate: normalizePluginOptions, options}); } +const defaultOptions = { + ...DEFAULT_OPTIONS, + id: 'default', +}; + describe('normalizePagesPluginOptions', () => { it('returns default options for undefined user options', () => { - const value = normalizePluginOptions({}); - expect(value).toEqual(DEFAULT_OPTIONS); + expect(testValidate({})).toEqual(defaultOptions); }); it('fills in default options for partially defined user options', () => { - const value = normalizePluginOptions({path: 'src/pages'}); - expect(value).toEqual(DEFAULT_OPTIONS); + expect(testValidate({path: 'src/foo'})).toEqual({ + ...defaultOptions, + path: 'src/foo', + }); }); it('accepts correctly defined user options', () => { @@ -39,13 +37,15 @@ describe('normalizePagesPluginOptions', () => { include: ['**/*.{js,jsx,ts,tsx}'], exclude: ['**/$*/'], }; - const value = normalizePluginOptions(userOptions); - expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions}); + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); }); it('rejects bad path inputs', () => { expect(() => { - normalizePluginOptions({ + testValidate({ // @ts-expect-error: bad attribute path: 42, }); diff --git a/packages/docusaurus-plugin-content-pages/src/pageFrontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts similarity index 100% rename from packages/docusaurus-plugin-content-pages/src/pageFrontMatter.ts rename to packages/docusaurus-plugin-content-pages/src/frontMatter.ts diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index d7f4c48f90f4..c205743e6a00 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -21,15 +21,9 @@ import { DEFAULT_PLUGIN_ID, parseMarkdownString, } from '@docusaurus/utils'; -import type { - LoadContext, - Plugin, - OptionValidationContext, - ValidationResult, -} from '@docusaurus/types'; +import type {LoadContext, Plugin} from '@docusaurus/types'; import admonitions from 'remark-admonitions'; -import {PluginOptionSchema} from './pluginOptionSchema'; -import {validatePageFrontMatter} from './pageFrontMatter'; +import {validatePageFrontMatter} from './frontMatter'; import type {LoadedContent, PagesContentPaths} from './types'; import type {PluginOptions, Metadata} from '@docusaurus/plugin-content-pages'; @@ -176,7 +170,7 @@ export default async function pluginContentPages( ); }, - configureWebpack(_config, isServer, {getJSLoader}) { + configureWebpack(config, isServer, {getJSLoader}) { const { rehypePlugins, remarkPlugins, @@ -241,10 +235,4 @@ export default async function pluginContentPages( }; } -export function validateOptions({ - validate, - options, -}: OptionValidationContext): ValidationResult { - const validatedOptions = validate(PluginOptionSchema, options); - return validatedOptions; -} +export {validateOptions} from './options'; diff --git a/packages/docusaurus-plugin-content-pages/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-content-pages/src/options.ts similarity index 79% rename from packages/docusaurus-plugin-content-pages/src/pluginOptionSchema.ts rename to packages/docusaurus-plugin-content-pages/src/options.ts index 662916af102c..9713fea810dd 100644 --- a/packages/docusaurus-plugin-content-pages/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-content-pages/src/options.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {PluginOptions} from '@docusaurus/plugin-content-pages'; +import type {PluginOptions, Options} from '@docusaurus/plugin-content-pages'; import { Joi, RemarkPluginsSchema, @@ -13,6 +13,7 @@ import { AdmonitionsSchema, } from '@docusaurus/utils-validation'; import {GlobExcludeDefault} from '@docusaurus/utils'; +import type {OptionValidationContext} from '@docusaurus/types'; export const DEFAULT_OPTIONS: PluginOptions = { path: 'src/pages', // Path to data on filesystem, relative to site dir. @@ -27,7 +28,7 @@ export const DEFAULT_OPTIONS: PluginOptions = { admonitions: {}, }; -export const PluginOptionSchema = Joi.object({ +const PluginOptionSchema = Joi.object({ path: Joi.string().default(DEFAULT_OPTIONS.path), routeBasePath: Joi.string().default(DEFAULT_OPTIONS.routeBasePath), include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include), @@ -43,3 +44,11 @@ export const PluginOptionSchema = Joi.object({ ), admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions), }); + +export function validateOptions({ + validate, + options, +}: OptionValidationContext): PluginOptions { + const validatedOptions = validate(PluginOptionSchema, options); + return validatedOptions; +} diff --git a/packages/docusaurus-plugin-google-analytics/src/index.ts b/packages/docusaurus-plugin-google-analytics/src/index.ts index 5e75e58b9929..0219c748f12c 100644 --- a/packages/docusaurus-plugin-google-analytics/src/index.ts +++ b/packages/docusaurus-plugin-google-analytics/src/index.ts @@ -10,11 +10,10 @@ import type { LoadContext, Plugin, OptionValidationContext, - ValidationResult, ThemeConfig, ThemeConfigValidationContext, } from '@docusaurus/types'; -import type {PluginOptions} from '@docusaurus/plugin-google-analytics'; +import type {PluginOptions, Options} from '@docusaurus/plugin-google-analytics'; export default function pluginGoogleAnalytics( context: LoadContext, @@ -74,13 +73,13 @@ const pluginOptionsSchema = Joi.object({ export function validateOptions({ validate, options, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { return validate(pluginOptionsSchema, options); } export function validateThemeConfig({ themeConfig, -}: ThemeConfigValidationContext): ValidationResult { +}: ThemeConfigValidationContext): ThemeConfig { if ('googleAnalytics' in themeConfig) { throw new Error( 'The "googleAnalytics" field in themeConfig should now be specified as option for plugin-google-analytics. More information at https://github.com/facebook/docusaurus/pull/5832.', diff --git a/packages/docusaurus-plugin-google-gtag/src/index.ts b/packages/docusaurus-plugin-google-gtag/src/index.ts index 238fe699a69a..66ed0365e0a9 100644 --- a/packages/docusaurus-plugin-google-gtag/src/index.ts +++ b/packages/docusaurus-plugin-google-gtag/src/index.ts @@ -10,11 +10,10 @@ import type { LoadContext, Plugin, OptionValidationContext, - ValidationResult, ThemeConfig, ThemeConfigValidationContext, } from '@docusaurus/types'; -import type {PluginOptions} from '@docusaurus/plugin-google-gtag'; +import type {PluginOptions, Options} from '@docusaurus/plugin-google-gtag'; export default function pluginGoogleGtag( context: LoadContext, @@ -88,13 +87,13 @@ const pluginOptionsSchema = Joi.object({ export function validateOptions({ validate, options, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { return validate(pluginOptionsSchema, options); } export function validateThemeConfig({ themeConfig, -}: ThemeConfigValidationContext): ValidationResult { +}: ThemeConfigValidationContext): ThemeConfig { if ('gtag' in themeConfig) { throw new Error( 'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.', diff --git a/packages/docusaurus-plugin-ideal-image/src/index.ts b/packages/docusaurus-plugin-ideal-image/src/index.ts index de28f087dfb3..4ea9fa4675c7 100644 --- a/packages/docusaurus-plugin-ideal-image/src/index.ts +++ b/packages/docusaurus-plugin-ideal-image/src/index.ts @@ -9,7 +9,6 @@ import type { LoadContext, Plugin, OptionValidationContext, - ValidationResult, } from '@docusaurus/types'; import type {PluginOptions} from '@docusaurus/plugin-ideal-image'; import {Joi} from '@docusaurus/utils-validation'; @@ -79,7 +78,7 @@ export default function pluginIdealImage( export function validateOptions({ validate, options, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { const pluginOptionsSchema = Joi.object({ disableInDev: Joi.boolean().default(true), }).unknown(); diff --git a/packages/docusaurus-plugin-pwa/src/options.ts b/packages/docusaurus-plugin-pwa/src/options.ts index 418313fafb4f..e96405756ad1 100644 --- a/packages/docusaurus-plugin-pwa/src/options.ts +++ b/packages/docusaurus-plugin-pwa/src/options.ts @@ -6,11 +6,7 @@ */ import {Joi} from '@docusaurus/utils-validation'; -import type { - ThemeConfig, - ValidationResult, - OptionValidationContext, -} from '@docusaurus/types'; +import type {OptionValidationContext} from '@docusaurus/types'; import type {PluginOptions} from '@docusaurus/plugin-pwa'; const DEFAULT_OPTIONS = { @@ -27,7 +23,7 @@ const DEFAULT_OPTIONS = { reloadPopup: '@theme/PwaReloadPopup', }; -export const Schema = Joi.object({ +const Schema = Joi.object({ debug: Joi.bool().default(DEFAULT_OPTIONS.debug), offlineModeActivationStrategies: Joi.array() .items( @@ -61,6 +57,6 @@ export const Schema = Joi.object({ export function validateOptions({ validate, options, -}: OptionValidationContext): ValidationResult { +}: OptionValidationContext): PluginOptions { return validate(Schema, options); } diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts new file mode 100644 index 000000000000..e53a2adc6ba9 --- /dev/null +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {validateOptions, DEFAULT_OPTIONS} from '../options'; +import {normalizePluginOptions} from '@docusaurus/utils-validation'; +import type {Options} from '@docusaurus/plugin-sitemap'; + +function testValidate(options: Options) { + return validateOptions({validate: normalizePluginOptions, options}); +} + +const defaultOptions = { + ...DEFAULT_OPTIONS, + id: 'default', +}; + +describe('validateOptions', () => { + it('returns default values for empty user options', () => { + expect(testValidate({})).toEqual(defaultOptions); + }); + + it('accepts correctly defined user options', () => { + const userOptions = { + changefreq: 'yearly', + priority: 0.9, + }; + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); + }); + + it('rejects out-of-range priority inputs', () => { + expect(() => + testValidate({priority: 2}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"priority\\" must be less than or equal to 1"`, + ); + }); + + it('rejects bad changefreq inputs', () => { + expect(() => + testValidate({changefreq: 'annually'}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"changefreq\\" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`, + ); + }); +}); diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts deleted file mode 100644 index b245be71375c..000000000000 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/pluginOptionSchema.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; - -function normalizePluginOptions(options) { - const {value, error} = PluginOptionSchema.validate(options, { - convert: false, - }); - if (error) { - throw error; - } else { - return value; - } -} - -describe('normalizeSitemapPluginOptions', () => { - it('returns default values for empty user options', () => { - const {value} = PluginOptionSchema.validate({}); - expect(value).toEqual(DEFAULT_OPTIONS); - }); - - it('accepts correctly defined user options', () => { - const userOptions = { - changefreq: 'yearly', - priority: 0.9, - }; - const {value} = PluginOptionSchema.validate(userOptions); - expect(value).toEqual(userOptions); - }); - - it('rejects out-of-range priority inputs', () => { - expect(() => { - normalizePluginOptions({ - priority: 2, - }); - }).toThrowErrorMatchingInlineSnapshot( - `"\\"priority\\" must be less than or equal to 1"`, - ); - }); - - it('rejects bad changefreq inputs', () => { - expect(() => { - normalizePluginOptions({ - changefreq: 'annually', - }); - }).toThrowErrorMatchingInlineSnapshot( - `"\\"changefreq\\" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`, - ); - }); -}); diff --git a/packages/docusaurus-plugin-sitemap/src/index.ts b/packages/docusaurus-plugin-sitemap/src/index.ts index e394a9a19291..0a6651029917 100644 --- a/packages/docusaurus-plugin-sitemap/src/index.ts +++ b/packages/docusaurus-plugin-sitemap/src/index.ts @@ -9,14 +9,7 @@ import fs from 'fs-extra'; import path from 'path'; import type {Options} from '@docusaurus/plugin-sitemap'; import createSitemap from './createSitemap'; -import type { - LoadContext, - Props, - OptionValidationContext, - ValidationResult, - Plugin, -} from '@docusaurus/types'; -import {PluginOptionSchema} from './pluginOptionSchema'; +import type {LoadContext, Plugin} from '@docusaurus/types'; export default function pluginSitemap( context: LoadContext, @@ -25,7 +18,7 @@ export default function pluginSitemap( return { name: 'docusaurus-plugin-sitemap', - async postBuild({siteConfig, routesPaths, outDir}: Props) { + async postBuild({siteConfig, routesPaths, outDir}) { if (siteConfig.noIndex) { return; } @@ -47,10 +40,4 @@ export default function pluginSitemap( }; } -export function validateOptions({ - validate, - options, -}: OptionValidationContext): ValidationResult { - const validatedOptions = validate(PluginOptionSchema, options); - return validatedOptions; -} +export {validateOptions} from './options'; diff --git a/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-sitemap/src/options.ts similarity index 71% rename from packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts rename to packages/docusaurus-plugin-sitemap/src/options.ts index 7ead9b2e8031..e7d7972153a5 100644 --- a/packages/docusaurus-plugin-sitemap/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-sitemap/src/options.ts @@ -8,13 +8,14 @@ import {Joi} from '@docusaurus/utils-validation'; import {EnumChangefreq} from 'sitemap'; import type {Options} from '@docusaurus/plugin-sitemap'; +import type {OptionValidationContext} from '@docusaurus/types'; -export const DEFAULT_OPTIONS: Required = { +export const DEFAULT_OPTIONS: Options = { changefreq: EnumChangefreq.WEEKLY, priority: 0.5, }; -export const PluginOptionSchema = Joi.object({ +const PluginOptionSchema = Joi.object({ cacheTime: Joi.forbidden().messages({ 'any.unknown': 'Option `cacheTime` in sitemap config is deprecated. Please remove it.', @@ -28,3 +29,11 @@ export const PluginOptionSchema = Joi.object({ 'Please use the new Docusaurus global trailingSlash config instead, and the sitemaps plugin will use it.', }), }); + +export function validateOptions({ + validate, + options, +}: OptionValidationContext): Options { + const validatedOptions = validate(PluginOptionSchema, options); + return validatedOptions; +} diff --git a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts index 7706a0cdd256..7f16b96a4c94 100644 --- a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts +++ b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts @@ -8,6 +8,7 @@ import type {EnumChangefreq} from 'sitemap'; export type Options = { + id?: string; /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ changefreq?: EnumChangefreq; /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index a3904f3582a5..64f56392a45e 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {LoadContext, Plugin, PostCssOptions} from '@docusaurus/types'; +import type {LoadContext, Plugin} from '@docusaurus/types'; import type {ThemeConfig} from '@docusaurus/theme-common'; import {getTranslationFiles, translateThemeConfig} from './translations'; import {createRequire} from 'module'; @@ -169,7 +169,7 @@ export default function docusaurusThemeClassic( }; }, - configurePostCss(postCssOptions: PostCssOptions) { + configurePostCss(postCssOptions) { if (direction === 'rtl') { const resolvedInfimaFile = require.resolve(getInfimaCSSFile(direction)); const plugin: PostCssPlugin = { diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts index cd068655bf0d..8de448ea652a 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts @@ -6,7 +6,10 @@ */ import {Joi, URISchema} from '@docusaurus/utils-validation'; -import type {ThemeConfig, Validate, ValidationResult} from '@docusaurus/types'; +import type { + ThemeConfig, + ThemeConfigValidationContext, +} from '@docusaurus/types'; const DEFAULT_DOCS_CONFIG = { versionPersistence: 'localStorage', @@ -373,9 +376,6 @@ export const ThemeConfigSchema = Joi.object({ export function validateThemeConfig({ validate, themeConfig, -}: { - validate: Validate; - themeConfig: ThemeConfig; -}): ValidationResult { +}: ThemeConfigValidationContext): ThemeConfig { return validate(ThemeConfigSchema, themeConfig); } diff --git a/packages/docusaurus-theme-live-codeblock/src/validateThemeConfig.ts b/packages/docusaurus-theme-live-codeblock/src/validateThemeConfig.ts index 5c3cd1dfde3d..4b9fb583be03 100644 --- a/packages/docusaurus-theme-live-codeblock/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-live-codeblock/src/validateThemeConfig.ts @@ -6,7 +6,10 @@ */ import {Joi} from '@docusaurus/utils-validation'; -import type {ThemeConfig, Validate, ValidationResult} from '@docusaurus/types'; +import type { + ThemeConfig, + ThemeConfigValidationContext, +} from '@docusaurus/types'; export const DEFAULT_CONFIG = { playgroundPosition: 'bottom', @@ -25,9 +28,6 @@ export const Schema = Joi.object({ export function validateThemeConfig({ validate, themeConfig, -}: { - validate: Validate; - themeConfig: ThemeConfig; -}): ValidationResult { +}: ThemeConfigValidationContext): ThemeConfig { return validate(Schema, themeConfig); } diff --git a/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts b/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts index 6ad9f3d6777f..95ff9e9f7cb4 100644 --- a/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-search-algolia/src/validateThemeConfig.ts @@ -6,7 +6,10 @@ */ import {Joi} from '@docusaurus/utils-validation'; -import type {ThemeConfig, Validate, ValidationResult} from '@docusaurus/types'; +import type { + ThemeConfig, + ThemeConfigValidationContext, +} from '@docusaurus/types'; export const DEFAULT_CONFIG = { // enabled by default, as it makes sense in most cases @@ -45,9 +48,6 @@ export const Schema = Joi.object({ export function validateThemeConfig({ validate, themeConfig, -}: { - validate: Validate; - themeConfig: ThemeConfig; -}): ValidationResult { +}: ThemeConfigValidationContext): ThemeConfig { return validate(Schema, themeConfig); } diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index e5ef1a919b25..21bcdf60c9b0 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -320,7 +320,7 @@ export type PluginModule = { (context: LoadContext, options: Options): | Plugin | Promise>; - validateOptions?: (data: OptionValidationContext) => T; + validateOptions?: (data: OptionValidationContext) => U; validateThemeConfig?: (data: ThemeConfigValidationContext) => T; getSwizzleComponentList?: () => string[] | undefined; // TODO deprecate this one later @@ -436,22 +436,20 @@ interface HtmlTagObject { innerHTML?: string; } -export type ValidationResult = T; - export type ValidationSchema = Joi.ObjectSchema; -export type Validate = ( - validationSchema: ValidationSchema, - options: Partial, -) => ValidationResult; +export type Validate = ( + validationSchema: ValidationSchema, + options: T, +) => U; -export interface OptionValidationContext { - validate: Validate; - options: Partial; -} +export type OptionValidationContext = { + validate: Validate; + options: T; +}; export interface ThemeConfigValidationContext { - validate: Validate; + validate: Validate; themeConfig: Partial; } diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts index d7f0742bfc0a..25ed7b2f2793 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts @@ -24,6 +24,9 @@ describe('normalizePluginOptions', () => { options, ), ).toEqual(options); + expect( + normalizePluginOptions(Joi.object({foo: Joi.string()}), undefined), + ).toEqual({id: 'default'}); }); it('normalizes plugin options', () => { diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index 4e88d495b3c1..aae84333b98b 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -20,7 +20,8 @@ export function printWarning(warning?: Joi.ValidationError): void { export function normalizePluginOptions( schema: Joi.ObjectSchema, - options: Partial, + // This allows us to automatically normalize undefined to {id: 'default'} + options: Partial = {}, ): T { // All plugins can be provided an "id" option (multi-instance support) // we add schema validation automatically diff --git a/packages/docusaurus/src/server/plugins/init.ts b/packages/docusaurus/src/server/plugins/init.ts index 504071617a07..918476e983f3 100644 --- a/packages/docusaurus/src/server/plugins/init.ts +++ b/packages/docusaurus/src/server/plugins/init.ts @@ -179,7 +179,7 @@ export default async function initPlugins({ function doValidatePluginOptions( normalizedPluginConfig: NormalizedPluginConfig, - ) { + ): Required { const validateOptions = getOptionValidationFunction(normalizedPluginConfig); if (validateOptions) { return validateOptions({ From 4103fef11e8b0e30f8baba003f4ff0dbd9040580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Wed, 23 Mar 2022 11:57:02 +0100 Subject: [PATCH 047/405] chore: publish stylelint-copyright again (#6967) --- packages/stylelint-copyright/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stylelint-copyright/package.json b/packages/stylelint-copyright/package.json index f3413ee227f8..be46ef9595d4 100644 --- a/packages/stylelint-copyright/package.json +++ b/packages/stylelint-copyright/package.json @@ -4,7 +4,6 @@ "description": "Stylelint plugin to check CSS files for a copyright header.", "main": "index.js", "license": "MIT", - "private": true, "repository": { "type": "git", "url": "https://github.com/facebook/docusaurus.git", From b456a64f61db9539ad97148a37b2307bdec8ffa8 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 23 Mar 2022 21:39:19 +0800 Subject: [PATCH 048/405] feat(theme-common): JSDoc for all APIs (#6974) * feat(theme-common): JSDoc for all APIs * fix tests --- .../src/components/Collapsible/index.tsx | 60 +++++--- .../src/components/Details/index.tsx | 9 +- .../contexts/__tests__/docsSidebar.test.tsx | 31 ++++ .../contexts/__tests__/docsVersion.test.tsx | 46 ++++++ .../src/contexts/announcementBar.tsx | 28 ++-- .../src/contexts/colorMode.tsx | 34 ++--- .../contexts/docSidebarItemsExpandedState.tsx | 33 +++-- .../src/contexts/docsPreferredVersion.tsx | 137 ++++++++--------- .../src/contexts/docsSidebar.tsx | 42 ++++++ .../src/contexts/docsVersion.tsx | 36 +++++ .../src/contexts/navbarMobileSidebar.tsx | 47 +++--- .../navbarSecondaryMenu.tsx | 71 ++++----- .../src/contexts/tabGroupChoice.tsx | 42 +++--- .../src/hooks/useHideableNavbar.ts | 14 +- .../src/hooks/useKeyboardNavigation.ts | 8 +- .../src/hooks/useLockBodyScroll.ts | 5 +- .../src/hooks/usePrismTheme.ts | 4 + .../src/hooks/useSearchPage.ts | 17 ++- .../src/hooks/useTOCHighlight.ts | 19 ++- .../src/hooks/useWindowSize.ts | 24 +-- packages/docusaurus-theme-common/src/index.ts | 29 ++-- .../src/utils/ThemeClassNames.ts | 16 +- .../src/utils/__tests__/docsUtils.test.tsx | 56 +------ .../src/utils/__tests__/pathUtils.test.ts | 40 ----- .../src/utils/__tests__/routesUtils.test.ts | 34 ++++- .../src/utils/codeBlockUtils.ts | 90 ++++++------ .../src/utils/docsUtils.tsx | 139 ++++++------------ .../src/utils/footerUtils.ts | 4 + .../src/utils/generalUtils.ts | 3 + .../src/utils/historyUtils.ts | 28 ++-- .../src/utils/jsUtils.ts | 2 +- .../src/utils/metadataUtils.tsx | 18 ++- .../src/utils/navbarUtils.tsx | 2 +- .../src/utils/pathUtils.ts | 21 --- .../src/utils/reactUtils.tsx | 18 ++- .../src/utils/regexpUtils.ts | 3 +- .../src/utils/routesUtils.ts | 27 +++- .../src/utils/scrollUtils.tsx | 84 +++++------ .../src/utils/searchUtils.ts | 49 ++++++ .../src/utils/storageUtils.ts | 34 +++-- .../src/utils/tagsUtils.ts | 5 +- .../src/utils/tocUtils.ts | 23 ++- .../src/utils/useAlternatePageUtils.ts | 22 ++- .../src/utils/useContextualSearchFilters.ts | 55 ------- .../src/utils/useLocalPathname.ts | 8 +- .../src/utils/useLocationChange.ts | 19 ++- .../src/utils/usePluralForm.ts | 11 ++ .../src/utils/useThemeConfig.ts | 3 + 48 files changed, 871 insertions(+), 679 deletions(-) create mode 100644 packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx create mode 100644 packages/docusaurus-theme-common/src/contexts/__tests__/docsVersion.test.tsx create mode 100644 packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx create mode 100644 packages/docusaurus-theme-common/src/contexts/docsVersion.tsx rename packages/docusaurus-theme-common/src/{utils => contexts}/navbarSecondaryMenu.tsx (68%) delete mode 100644 packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts delete mode 100644 packages/docusaurus-theme-common/src/utils/pathUtils.ts delete mode 100644 packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts diff --git a/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx b/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx index a608d03772fc..9185ac91c16f 100644 --- a/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Collapsible/index.tsx @@ -20,20 +20,19 @@ import React, { const DefaultAnimationEasing = 'ease-in-out'; -export type UseCollapsibleConfig = { +/** + * This hook is a very thin wrapper around a `useState`. + */ +export function useCollapsible({ + initialState, +}: { + /** The initial state. Will be non-collapsed by default. */ initialState: boolean | (() => boolean); -}; - -export type UseCollapsibleReturns = { +}): { collapsed: boolean; setCollapsed: Dispatch>; toggleCollapsed: () => void; -}; - -// This hook just define the state -export function useCollapsible({ - initialState, -}: UseCollapsibleConfig): UseCollapsibleReturns { +} { const [collapsed, setCollapsed] = useState(initialState ?? false); const toggleCollapsed = useCallback(() => { @@ -152,8 +151,10 @@ type CollapsibleElementType = React.ElementType< Pick, 'className' | 'onTransitionEnd' | 'style'> >; -// Prevent hydration layout shift before animations are handled imperatively -// with JS +/** + * Prevent hydration layout shift before animations are handled imperatively + * with JS + */ function getSSRStyle(collapsed: boolean) { if (ExecutionEnvironment.canUseDOM) { return undefined; @@ -162,16 +163,27 @@ function getSSRStyle(collapsed: boolean) { } type CollapsibleBaseProps = { + /** The actual DOM element to be used in the markup. */ as?: CollapsibleElementType; + /** Initial collapsed state. */ collapsed: boolean; children: ReactNode; + /** Configuration of animation, like `duration` and `easing` */ animation?: CollapsibleAnimationConfig; + /** + * A callback fired when the collapse transition animation ends. Receives + * the **new** collapsed state: e.g. when + * expanding, `collapsed` will be `false`. You can use this for some "cleanup" + * like applying new styles when the container is fully expanded. + */ onCollapseTransitionEnd?: (collapsed: boolean) => void; + /** Class name for the underlying DOM element. */ className?: string; - - // This is mostly useful for details/summary component where ssrStyle is not - // needed (as details are hidden natively) and can mess up with the default - // native behavior of the browser when JS fails to load or is disabled + /** + * This is mostly useful for details/summary component where ssrStyle is not + * needed (as details are hidden natively) and can mess up with the browser's + * native behavior when JS fails to load or is disabled + */ disableSSRStyle?: boolean; }; @@ -233,14 +245,20 @@ function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) { } type CollapsibleProps = CollapsibleBaseProps & { - // Lazy allows to delay the rendering when collapsed => it will render - // children only after hydration, on first expansion - // Required prop: it forces to think if content should be server-rendered - // or not! This has perf impact on the SSR output and html file sizes - // See https://github.com/facebook/docusaurus/issues/4753 + /** + * Delay rendering of the content till first expansion. Marked as required to + * force us to think if content should be server-rendered or not. This has + * perf impact since it reduces html file sizes, but could undermine SEO. + * @see https://github.com/facebook/docusaurus/issues/4753 + */ lazy: boolean; }; +/** + * A headless component providing smooth and uniform collapsing behavior. The + * component will be invisible (zero height) when collapsed. Doesn't provide + * interactivity by itself: collapse state is toggled through props. + */ export function Collapsible({lazy, ...props}: CollapsibleProps): JSX.Element { const Comp = lazy ? CollapsibleLazy : CollapsibleBase; return ; diff --git a/packages/docusaurus-theme-common/src/components/Details/index.tsx b/packages/docusaurus-theme-common/src/components/Details/index.tsx index b8e172d62a4b..ccf7e10b7fb4 100644 --- a/packages/docusaurus-theme-common/src/components/Details/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Details/index.tsx @@ -31,9 +31,14 @@ function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean { } export type DetailsProps = { + /** Summary is provided as props, including the wrapping `` tag */ summary?: ReactElement; } & ComponentProps<'details'>; +/** + * A mostly un-styled `
    ` element with smooth collapsing. Provides some + * very lightweight styles, but you should bring your UI. + */ export function Details({ summary, children, @@ -45,8 +50,8 @@ export function Details({ const {collapsed, setCollapsed} = useCollapsible({ initialState: !props.open, }); - // Use a separate prop because it must be set only after animation completes - // Otherwise close anim won't work + // Use a separate state for the actual details prop, because it must be set + // only after animation completes, otherwise close animations won't work const [open, setOpen] = useState(props.open); return ( diff --git a/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx b/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx new file mode 100644 index 000000000000..5d66881b7d16 --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks'; +import {useDocsSidebar, DocsSidebarProvider} from '../docsSidebar'; +import type {PropSidebar} from '@docusaurus/plugin-content-docs'; + +describe('useDocsSidebar', () => { + it('throws if context provider is missing', () => { + expect( + () => renderHook(() => useDocsSidebar()).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Hook useDocsSidebar is called outside the . "`, + ); + }); + + it('reads value from context provider', () => { + const sidebar: PropSidebar = []; + const {result} = renderHook(() => useDocsSidebar(), { + wrapper: ({children}) => ( + {children} + ), + }); + expect(result.current).toBe(sidebar); + }); +}); diff --git a/packages/docusaurus-theme-common/src/contexts/__tests__/docsVersion.test.tsx b/packages/docusaurus-theme-common/src/contexts/__tests__/docsVersion.test.tsx new file mode 100644 index 000000000000..972a824cd31f --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/__tests__/docsVersion.test.tsx @@ -0,0 +1,46 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import {renderHook} from '@testing-library/react-hooks'; +import {useDocsVersion, DocsVersionProvider} from '../docsVersion'; +import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs'; + +function testVersion(data?: Partial): PropVersionMetadata { + return { + version: 'versionName', + label: 'Version Label', + className: 'version className', + badge: true, + banner: 'unreleased', + docs: {}, + docsSidebars: {}, + isLast: false, + pluginId: 'default', + ...data, + }; +} + +describe('useDocsVersion', () => { + it('throws if context provider is missing', () => { + expect( + () => renderHook(() => useDocsVersion()).result.current, + ).toThrowErrorMatchingInlineSnapshot( + `"Hook useDocsVersion is called outside the . "`, + ); + }); + + it('reads value from context provider', () => { + const version = testVersion(); + const {result} = renderHook(() => useDocsVersion(), { + wrapper: ({children}) => ( + {children} + ), + }); + expect(result.current).toBe(version); + }); +}); diff --git a/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx index 01fe0ac84852..f244be2bee2e 100644 --- a/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/announcementBar.tsx @@ -32,12 +32,18 @@ const isDismissedInStorage = () => const setDismissedInStorage = (bool: boolean) => AnnouncementBarDismissStorage.set(String(bool)); -type AnnouncementBarAPI = { +type ContextValue = { + /** Whether the announcement bar should be displayed. */ readonly isActive: boolean; + /** + * Callback fired when the user closes the announcement. Will be saved. + */ readonly close: () => void; }; -const useAnnouncementBarContextValue = (): AnnouncementBarAPI => { +const Context = React.createContext(null); + +function useContextValue(): ContextValue { const {announcementBar} = useThemeConfig(); const isBrowser = useIsBrowser(); @@ -93,27 +99,19 @@ const useAnnouncementBarContextValue = (): AnnouncementBarAPI => { }), [announcementBar, isClosed, handleClose], ); -}; - -const AnnouncementBarContext = React.createContext( - null, -); +} export function AnnouncementBarProvider({ children, }: { children: ReactNode; }): JSX.Element { - const value = useAnnouncementBarContextValue(); - return ( - - {children} - - ); + const value = useContextValue(); + return {children}; } -export function useAnnouncementBar(): AnnouncementBarAPI { - const api = useContext(AnnouncementBarContext); +export function useAnnouncementBar(): ContextValue { + const api = useContext(Context); if (!api) { throw new ReactContextError('AnnouncementBarProvider'); } diff --git a/packages/docusaurus-theme-common/src/contexts/colorMode.tsx b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx index 7fe480d32b5b..ee7d4eb54f54 100644 --- a/packages/docusaurus-theme-common/src/contexts/colorMode.tsx +++ b/packages/docusaurus-theme-common/src/contexts/colorMode.tsx @@ -20,8 +20,10 @@ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import {createStorageSlot} from '../utils/storageUtils'; import {useThemeConfig} from '../utils/useThemeConfig'; -type ColorModeContextValue = { +type ContextValue = { + /** Current color mode. */ readonly colorMode: ColorMode; + /** Set new color mode. */ readonly setColorMode: (colorMode: ColorMode) => void; // TODO legacy APIs kept for retro-compatibility: deprecate them @@ -30,6 +32,8 @@ type ColorModeContextValue = { readonly setDarkTheme: () => void; }; +const Context = React.createContext(undefined); + const ColorModeStorageKey = 'theme'; const ColorModeStorage = createStorageSlot(ColorModeStorageKey); @@ -44,18 +48,16 @@ export type ColorMode = typeof ColorModes[keyof typeof ColorModes]; const coerceToColorMode = (colorMode?: string | null): ColorMode => colorMode === ColorModes.dark ? ColorModes.dark : ColorModes.light; -const getInitialColorMode = (defaultMode: ColorMode | undefined): ColorMode => { - if (!ExecutionEnvironment.canUseDOM) { - return coerceToColorMode(defaultMode); - } - return coerceToColorMode(document.documentElement.getAttribute('data-theme')); -}; +const getInitialColorMode = (defaultMode: ColorMode | undefined): ColorMode => + ExecutionEnvironment.canUseDOM + ? coerceToColorMode(document.documentElement.getAttribute('data-theme')) + : coerceToColorMode(defaultMode); const storeColorMode = (newColorMode: ColorMode) => { ColorModeStorage.set(coerceToColorMode(newColorMode)); }; -function useColorModeContextValue(): ColorModeContextValue { +function useContextValue(): ContextValue { const { colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme}, } = useThemeConfig(); @@ -153,25 +155,17 @@ function useColorModeContextValue(): ColorModeContextValue { ); } -const ColorModeContext = React.createContext( - undefined, -); - export function ColorModeProvider({ children, }: { children: ReactNode; }): JSX.Element { - const contextValue = useColorModeContextValue(); - return ( - - {children} - - ); + const value = useContextValue(); + return {children}; } -export function useColorMode(): ColorModeContextValue { - const context = useContext(ColorModeContext); +export function useColorMode(): ContextValue { + const context = useContext(Context); if (context == null) { throw new ReactContextError( 'ColorModeProvider', diff --git a/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx b/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx index 72687024808e..b3d84a78389d 100644 --- a/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docSidebarItemsExpandedState.tsx @@ -8,15 +8,30 @@ import React, {type ReactNode, useMemo, useState, useContext} from 'react'; import {ReactContextError} from '../utils/reactUtils'; -const EmptyContext: unique symbol = Symbol('EmptyContext'); -const Context = React.createContext< - DocSidebarItemsExpandedState | typeof EmptyContext ->(EmptyContext); -type DocSidebarItemsExpandedState = { +type ContextValue = { + /** + * The item that the user last opened, `null` when there's none open. On + * initial render, it will always be `null`, which doesn't necessarily mean + * there's no category open (can have 0, 1, or many being initially open). + */ expandedItem: number | null; + /** + * Set the currently expanded item, when the user opens one. Set the value to + * `null` when the user closes an open category. + */ setExpandedItem: (a: number | null) => void; }; +const EmptyContext: unique symbol = Symbol('EmptyContext'); +const Context = React.createContext( + EmptyContext, +); + +/** + * Should be used to wrap one sidebar category level. This provider syncs the + * expanded states of all sibling categories, and categories can choose to + * collapse itself if another one is expanded. + */ export function DocSidebarItemsExpandedStateProvider({ children, }: { @@ -31,10 +46,10 @@ export function DocSidebarItemsExpandedStateProvider({ return {children}; } -export function useDocSidebarItemsExpandedState(): DocSidebarItemsExpandedState { - const contextValue = useContext(Context); - if (contextValue === EmptyContext) { +export function useDocSidebarItemsExpandedState(): ContextValue { + const value = useContext(Context); + if (value === EmptyContext) { throw new ReactContextError('DocSidebarItemsExpandedStateProvider'); } - return contextValue; + return value; } diff --git a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx index a1c95d592190..cd4bb935b683 100644 --- a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx @@ -54,32 +54,29 @@ const DocsPreferredVersionStorage = { type DocsPreferredVersionName = string | null; -// State for a single docs plugin instance +/** State for a single docs plugin instance */ type DocsPreferredVersionPluginState = { preferredVersionName: DocsPreferredVersionName; }; -// We need to store in state/storage globally -// one preferred version per docs plugin instance -// pluginId => pluginState -type DocsPreferredVersionState = Record< - string, - DocsPreferredVersionPluginState ->; - -// Initial state is always null as we can't read local storage from node SSR -function getInitialState(pluginIds: string[]): DocsPreferredVersionState { - const initialState: DocsPreferredVersionState = {}; - pluginIds.forEach((pluginId) => { - initialState[pluginId] = { - preferredVersionName: null, - }; - }); - return initialState; -} +/** + * We need to store the state in storage globally, with one preferred version + * per docs plugin instance. + */ +type DocsPreferredVersionState = { + [pluginId: string]: DocsPreferredVersionPluginState; +}; -// Read storage for all docs plugins -// Assign to each doc plugin a preferred version (if found) +/** + * Initial state is always null as we can't read local storage from node SSR + */ +const getInitialState = (pluginIds: string[]): DocsPreferredVersionState => + Object.fromEntries(pluginIds.map((id) => [id, {preferredVersionName: null}])); + +/** + * Read storage for all docs plugins, assigning each doc plugin a preferred + * version (if found) + */ function readStorageState({ pluginIds, versionPersistence, @@ -89,9 +86,11 @@ function readStorageState({ versionPersistence: DocsVersionPersistence; allDocsData: Record; }): DocsPreferredVersionState { - // The storage value we read might be stale, - // and belong to a version that does not exist in the site anymore - // In such case, we remove the storage value to avoid downstream errors + /** + * The storage value we read might be stale, and belong to a version that does + * not exist in the site anymore. In such case, we remove the storage value to + * avoid downstream errors. + */ function restorePluginState( pluginId: string, ): DocsPreferredVersionPluginState { @@ -109,20 +108,25 @@ function readStorageState({ DocsPreferredVersionStorage.clear(pluginId, versionPersistence); return {preferredVersionName: null}; } - - const initialState: DocsPreferredVersionState = {}; - pluginIds.forEach((pluginId) => { - initialState[pluginId] = restorePluginState(pluginId); - }); - return initialState; + return Object.fromEntries( + pluginIds.map((id) => [id, restorePluginState(id)]), + ); } function useVersionPersistence(): DocsVersionPersistence { return useThemeConfig().docs.versionPersistence; } -// Value that will be accessible through context: [state,api] -function useContextValue() { +type ContextValue = [ + state: DocsPreferredVersionState, + api: { + savePreferredVersion: (pluginId: string, versionName: string) => void; + }, +]; + +const Context = React.createContext(null); + +function useContextValue(): ContextValue { const allDocsData = useAllDocsData(); const versionPersistence = useVersionPersistence(); const pluginIds = useMemo(() => Object.keys(allDocsData), [allDocsData]); @@ -154,15 +158,22 @@ function useContextValue() { }; }, [versionPersistence]); - return [state, api] as const; + return [state, api]; } -type DocsPreferredVersionContextValue = ReturnType; - -const Context = React.createContext( - null, -); +function DocsPreferredVersionContextProviderUnsafe({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const value = useContextValue(); + return {children}; +} +/** + * This is a maybe-layer. If the docs plugin is not enabled, this provider is a + * simple pass-through. + */ export function DocsPreferredVersionContextProvider({ children, }: { @@ -178,16 +189,7 @@ export function DocsPreferredVersionContextProvider({ return children; } -function DocsPreferredVersionContextProviderUnsafe({ - children, -}: { - children: ReactNode; -}): JSX.Element { - const contextValue = useContextValue(); - return {children}; -} - -function useDocsPreferredVersionContext(): DocsPreferredVersionContextValue { +function useDocsPreferredVersionContext(): ContextValue { const value = useContext(Context); if (!value) { throw new ReactContextError('DocsPreferredVersionContextProvider'); @@ -195,11 +197,14 @@ function useDocsPreferredVersionContext(): DocsPreferredVersionContextValue { return value; } -// Note, the preferredVersion attribute will always be null before mount +/** + * Returns a read-write interface to a plugin's preferred version. + * Note, the `preferredVersion` attribute will always be `null` before mount. + */ export function useDocsPreferredVersion( pluginId: string | undefined = DEFAULT_PLUGIN_ID, ): { - preferredVersion: GlobalVersion | null | undefined; + preferredVersion: GlobalVersion | null; savePreferredVersionName: (versionName: string) => void; } { const docsData = useDocsData(pluginId); @@ -207,9 +212,10 @@ export function useDocsPreferredVersion( const {preferredVersionName} = state[pluginId]!; - const preferredVersion = preferredVersionName - ? docsData.versions.find((version) => version.name === preferredVersionName) - : null; + const preferredVersion = + docsData.versions.find( + (version) => version.name === preferredVersionName, + ) ?? null; const savePreferredVersionName = useCallback( (versionName: string) => { @@ -218,12 +224,12 @@ export function useDocsPreferredVersion( [api, pluginId], ); - return {preferredVersion, savePreferredVersionName} as const; + return {preferredVersion, savePreferredVersionName}; } export function useDocsPreferredVersionByPluginId(): Record< string, - GlobalVersion | null | undefined + GlobalVersion | null > { const allDocsData = useAllDocsData(); const [state] = useDocsPreferredVersionContext(); @@ -232,19 +238,14 @@ export function useDocsPreferredVersionByPluginId(): Record< const docsData = allDocsData[pluginId]!; const {preferredVersionName} = state[pluginId]!; - return preferredVersionName - ? docsData.versions.find( - (version) => version.name === preferredVersionName, - ) - : null; + return ( + docsData.versions.find( + (version) => version.name === preferredVersionName, + ) ?? null + ); } - const pluginIds = Object.keys(allDocsData); - - const result: Record = {}; - pluginIds.forEach((pluginId) => { - result[pluginId] = getPluginIdPreferredVersion(pluginId); - }); - - return result; + return Object.fromEntries( + pluginIds.map((id) => [id, getPluginIdPreferredVersion(id)]), + ); } diff --git a/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx new file mode 100644 index 000000000000..4d2f7caa61d7 --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx @@ -0,0 +1,42 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ReactNode, useContext} from 'react'; +import type {PropSidebar} from '@docusaurus/plugin-content-docs'; +import {ReactContextError} from '../utils/reactUtils'; + +// Using a Symbol because null is a valid context value (a doc with no sidebar) +// Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx +const EmptyContext: unique symbol = Symbol('EmptyContext'); + +const Context = React.createContext( + EmptyContext, +); + +/** + * Provide the current sidebar to your children. + */ +export function DocsSidebarProvider({ + children, + sidebar, +}: { + children: ReactNode; + sidebar: PropSidebar | null; +}): JSX.Element { + return {children}; +} + +/** + * Gets the sidebar that's currently displayed, or `null` if there isn't one + */ +export function useDocsSidebar(): PropSidebar | null { + const sidebar = useContext(Context); + if (sidebar === EmptyContext) { + throw new ReactContextError('DocsSidebarProvider'); + } + return sidebar; +} diff --git a/packages/docusaurus-theme-common/src/contexts/docsVersion.tsx b/packages/docusaurus-theme-common/src/contexts/docsVersion.tsx new file mode 100644 index 000000000000..efa8ffc147d6 --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/docsVersion.tsx @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ReactNode, useContext} from 'react'; +import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs'; +import {ReactContextError} from '../utils/reactUtils'; + +const Context = React.createContext(null); + +/** + * Provide the current version's metadata to your children. + */ +export function DocsVersionProvider({ + children, + version, +}: { + children: ReactNode; + version: PropVersionMetadata | null; +}): JSX.Element { + return {children}; +} + +/** + * Gets the version metadata of the current doc page. + */ +export function useDocsVersion(): PropVersionMetadata { + const version = useContext(Context); + if (version === null) { + throw new ReactContextError('DocsVersionProvider'); + } + return version; +} diff --git a/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx index 76f77974e6d6..81e04fc391b5 100644 --- a/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx @@ -6,11 +6,11 @@ */ import React, { - type ReactNode, useCallback, useEffect, useState, useMemo, + type ReactNode, } from 'react'; import {useWindowSize} from '../hooks/useWindowSize'; import {useHistoryPopHandler} from '../utils/historyUtils'; @@ -18,31 +18,38 @@ import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; import {useThemeConfig} from '../utils/useThemeConfig'; import {ReactContextError} from '../utils/reactUtils'; -type NavbarMobileSidebarContextValue = { +type ContextValue = { + /** + * Mobile sidebar should be disabled in case it's empty, i.e. no secondary + * menu + no navbar items). If disabled, the toggle button should not be + * displayed at all. + */ disabled: boolean; + /** + * Signals whether the actual sidebar should be displayed (contrary to + * `disabled` which is about the toggle button). Sidebar should not visible + * until user interaction to avoid SSR rendering. + */ shouldRender: boolean; - toggle: () => void; + /** The displayed state. Can be toggled with the `toggle` callback. */ shown: boolean; + /** Toggle the `shown` attribute. */ + toggle: () => void; }; -const Context = React.createContext< - NavbarMobileSidebarContextValue | undefined ->(undefined); +const Context = React.createContext(undefined); -// Mobile sidebar can be disabled in case it would lead to an empty sidebar -// In this case it's not useful to display a navbar sidebar toggle button -function useNavbarMobileSidebarDisabled() { +function useIsNavbarMobileSidebarDisabled() { const activeDocPlugin = useActivePlugin(); const {items} = useThemeConfig().navbar; return items.length === 0 && !activeDocPlugin; } -function useNavbarMobileSidebarContextValue(): NavbarMobileSidebarContextValue { - const disabled = useNavbarMobileSidebarDisabled(); +function useContextValue(): ContextValue { + const disabled = useIsNavbarMobileSidebarDisabled(); const windowSize = useWindowSize(); - // Mobile sidebar not visible until user interaction: can avoid SSR rendering - const shouldRender = !disabled && windowSize === 'mobile'; // || windowSize === 'ssr'; + const shouldRender = !disabled && windowSize === 'mobile'; const [shown, setShown] = useState(false); @@ -68,14 +75,8 @@ function useNavbarMobileSidebarContextValue(): NavbarMobileSidebarContextValue { } }, [windowSize]); - // Return stable context value return useMemo( - () => ({ - disabled, - shouldRender, - toggle, - shown, - }), + () => ({disabled, shouldRender, toggle, shown}), [disabled, shouldRender, toggle, shown], ); } @@ -85,13 +86,13 @@ export function NavbarMobileSidebarProvider({ }: { children: ReactNode; }): JSX.Element { - const value = useNavbarMobileSidebarContextValue(); + const value = useContextValue(); return {children}; } -export function useNavbarMobileSidebar(): NavbarMobileSidebarContextValue { +export function useNavbarMobileSidebar(): ContextValue { const context = React.useContext(Context); - if (context == null) { + if (context === undefined) { throw new ReactContextError('NavbarMobileSidebarProvider'); } return context; diff --git a/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx similarity index 68% rename from packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx rename to packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx index 3e983234f961..1b6f188915f1 100644 --- a/packages/docusaurus-theme-common/src/utils/navbarSecondaryMenu.tsx +++ b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx @@ -14,19 +14,8 @@ import React, { type ReactNode, type ComponentType, } from 'react'; -import {ReactContextError, usePrevious} from './reactUtils'; -import {useNavbarMobileSidebar} from '../contexts/navbarMobileSidebar'; - -/* -The idea behind all this is that a specific component must be able to fill a -placeholder in the generic layout. The doc page should be able to fill the -secondary menu of the main mobile navbar. This permits to reduce coupling -between the main layout and the specific page. - -This kind of feature is often called portal/teleport/gateway... various -unmaintained React libs exist. Most up-to-date one: https://github.com/gregberge/react-teleporter -Not sure any of those is safe regarding concurrent mode. - */ +import {ReactContextError, usePrevious} from '../utils/reactUtils'; +import {useNavbarMobileSidebar} from './navbarMobileSidebar'; export type NavbarSecondaryMenuComponent = ComponentType; @@ -34,7 +23,7 @@ type State = { shown: boolean; content: | { - component: ComponentType; + component: NavbarSecondaryMenuComponent; props: object; } | {component: null; props: null}; @@ -45,7 +34,14 @@ const InitialState: State = { content: {component: null, props: null}, }; -function useContextValue() { +type ContextValue = [ + state: State, + setState: React.Dispatch>, +]; + +const Context = React.createContext(null); + +function useContextValue(): ContextValue { const mobileSidebar = useNavbarMobileSidebar(); const [state, setState] = useState(InitialState); @@ -76,21 +72,16 @@ function useContextValue() { } }, [mobileSidebar.shown, hasContent]); - return [state, setState] as const; + return [state, setState]; } -type ContextValue = ReturnType; - -const Context = React.createContext(null); - export function NavbarSecondaryMenuProvider({ children, }: { children: ReactNode; }): JSX.Element { - return ( - {children} - ); + const value = useContextValue(); + return {children}; } function useNavbarSecondaryMenuContext(): ContextValue { @@ -101,7 +92,7 @@ function useNavbarSecondaryMenuContext(): ContextValue { return value; } -function useShallowMemoizedObject>(obj: O) { +function useShallowMemoizedObject(obj: O) { return useMemo( () => obj, // Is this safe? @@ -110,15 +101,22 @@ function useShallowMemoizedObject>(obj: O) { ); } -// Fill the secondary menu placeholder with some real content -export function NavbarSecondaryMenuFiller< - Props extends Record, ->({ +/** + * This component renders nothing by itself, but it fills the placeholder in the + * generic secondary menu layout. This reduces coupling between the main layout + * and the specific page. + * + * This kind of feature is often called portal/teleport/gateway/outlet... + * Various unmaintained React libs exist. Most up-to-date one: + * https://github.com/gregberge/react-teleporter + * Not sure any of those is safe regarding concurrent mode. + */ +export function NavbarSecondaryMenuFiller

    ({ component, props, }: { - component: NavbarSecondaryMenuComponent; - props: Props; + component: NavbarSecondaryMenuComponent

    ; + props: P; }): JSX.Element | null { const [, setState] = useNavbarSecondaryMenuContext(); @@ -146,9 +144,16 @@ function renderElement(state: State): JSX.Element | undefined { return undefined; } +/** Wires the logic for rendering the mobile navbar secondary menu. */ export function useNavbarSecondaryMenu(): { + /** Whether secondary menu is displayed. */ shown: boolean; + /** + * Hide the secondary menu; fired either when hiding the entire sidebar, or + * when going back to the primary menu. + */ hide: () => void; + /** The content returned from the current secondary menu filler. */ content: JSX.Element | undefined; } { const [state, setState] = useNavbarSecondaryMenuContext(); @@ -159,11 +164,7 @@ export function useNavbarSecondaryMenu(): { ); return useMemo( - () => ({ - shown: state.shown, - hide, - content: renderElement(state), - }), + () => ({shown: state.shown, hide, content: renderElement(state)}), [hide, state], ); } diff --git a/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx index 3b0f14d90cf9..72b561d053b3 100644 --- a/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx +++ b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx @@ -18,16 +18,16 @@ import {ReactContextError} from '../utils/reactUtils'; const TAB_CHOICE_PREFIX = 'docusaurus.tab.'; -type TabGroupChoiceContextValue = { +type ContextValue = { + /** A map from `groupId` to the `value` of the saved choice. */ readonly tabGroupChoices: {readonly [groupId: string]: string}; + /** Set the new choice value of a group. */ readonly setTabGroupChoices: (groupId: string, newChoice: string) => void; }; -const TabGroupChoiceContext = React.createContext< - TabGroupChoiceContextValue | undefined ->(undefined); +const Context = React.createContext(undefined); -function useTabGroupChoiceContextValue(): TabGroupChoiceContextValue { +function useContextValue(): ContextValue { const [tabGroupChoices, setChoices] = useState<{ readonly [groupId: string]: string; }>({}); @@ -50,13 +50,18 @@ function useTabGroupChoiceContextValue(): TabGroupChoiceContextValue { } }, []); - return { - tabGroupChoices, - setTabGroupChoices: (groupId: string, newChoice: string) => { + const setTabGroupChoices = useCallback( + (groupId: string, newChoice: string) => { setChoices((oldChoices) => ({...oldChoices, [groupId]: newChoice})); setChoiceSyncWithLocalStorage(groupId, newChoice); }, - }; + [setChoiceSyncWithLocalStorage], + ); + + return useMemo( + () => ({tabGroupChoices, setTabGroupChoices}), + [tabGroupChoices, setTabGroupChoices], + ); } export function TabGroupChoiceProvider({ @@ -64,23 +69,12 @@ export function TabGroupChoiceProvider({ }: { children: ReactNode; }): JSX.Element { - const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoiceContextValue(); - const contextValue = useMemo( - () => ({ - tabGroupChoices, - setTabGroupChoices, - }), - [tabGroupChoices, setTabGroupChoices], - ); - return ( - - {children} - - ); + const value = useContextValue(); + return {children}; } -export function useTabGroupChoice(): TabGroupChoiceContextValue { - const context = useContext(TabGroupChoiceContext); +export function useTabGroupChoice(): ContextValue { + const context = useContext(Context); if (context == null) { throw new ReactContextError('TabGroupChoiceProvider'); } diff --git a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts index 62e9b3740585..2eb85744e8de 100644 --- a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts +++ b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts @@ -9,8 +9,14 @@ import {useState, useCallback, useRef} from 'react'; import {useLocationChange} from '../utils/useLocationChange'; import {useScrollPosition} from '../utils/scrollUtils'; +/** + * Wires the imperative logic of a hideable navbar. + * @param hideOnScroll If `false`, this hook is basically a no-op. + */ export function useHideableNavbar(hideOnScroll: boolean): { + /** A ref to the navbar component. Plug this into the actual element. */ readonly navbarRef: (node: HTMLElement | null) => void; + /** If `false`, the navbar component should not be rendered. */ readonly isNavbarVisible: boolean; } { const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll); @@ -29,7 +35,8 @@ export function useHideableNavbar(hideOnScroll: boolean): { const scrollTop = currentPosition.scrollY; - // It needed for mostly to handle rubber band scrolling + // Needed mostly for handling rubber band scrolling. + // See https://github.com/facebook/docusaurus/pull/5721 if (scrollTop < navbarHeight.current) { setIsNavbarVisible(true); return; @@ -66,8 +73,5 @@ export function useHideableNavbar(hideOnScroll: boolean): { setIsNavbarVisible(true); }); - return { - navbarRef, - isNavbarVisible, - }; + return {navbarRef, isNavbarVisible}; } diff --git a/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts b/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts index be6bfe8ecbf6..7a2ebfcc7a3f 100644 --- a/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts +++ b/packages/docusaurus-theme-common/src/hooks/useKeyboardNavigation.ts @@ -12,7 +12,13 @@ import './styles.css'; export const keyboardFocusedClassName = 'navigation-with-keyboard'; /** - * Detect keyboard focus indicator to not show outline for mouse users + * Side-effect that adds the `keyboardFocusedClassName` to the body element when + * the keyboard has been pressed, or removes it when the mouse is clicked. + * + * The presence of this class name signals that the user may be using keyboard + * for navigation, and the theme **must** add focus outline when this class name + * is present. (And optionally not if it's absent, for design purposes) + * * Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 */ export function useKeyboardNavigation(): void { diff --git a/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts b/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts index c35e127fcf67..649eddff447f 100644 --- a/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts +++ b/packages/docusaurus-theme-common/src/hooks/useLockBodyScroll.ts @@ -7,10 +7,13 @@ import {useEffect} from 'react'; +/** + * Side-effect that locks the document body's scroll throughout the lifetime of + * the containing component. e.g. when the mobile sidebar is expanded. + */ export function useLockBodyScroll(lock: boolean = true): void { useEffect(() => { document.body.style.overflow = lock ? 'hidden' : 'visible'; - return () => { document.body.style.overflow = 'visible'; }; diff --git a/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts b/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts index 3c8f84760172..bb8034657baa 100644 --- a/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts +++ b/packages/docusaurus-theme-common/src/hooks/usePrismTheme.ts @@ -9,6 +9,10 @@ import defaultTheme from 'prism-react-renderer/themes/palenight'; import {useColorMode} from '../contexts/colorMode'; import {useThemeConfig} from '../utils/useThemeConfig'; +/** + * Returns a color-mode-dependent Prism theme: whatever the user specified in + * the config. Falls back to `palenight`. + */ export function usePrismTheme(): typeof defaultTheme { const {prism} = useThemeConfig(); const {colorMode} = useColorMode(); diff --git a/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts b/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts index f97c43c97cdb..36c1cdaacf0b 100644 --- a/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts +++ b/packages/docusaurus-theme-common/src/hooks/useSearchPage.ts @@ -11,9 +11,22 @@ import {useCallback, useEffect, useState} from 'react'; const SEARCH_PARAM_QUERY = 'q'; +/** Some utility functions around search queries. */ export function useSearchPage(): { + /** + * Works hand-in-hand with `setSearchQuery`; whatever the user has inputted + * into the search box. + */ searchQuery: string; + /** + * Set a new search query. In addition to updating `searchQuery`, this handle + * also mutates the location and appends the query. + */ setSearchQuery: (newSearchQuery: string) => void; + /** + * Given a query, this handle generates the corresponding search page link, + * with base URL prepended. + */ generateSearchPageLink: (targetSearchQuery: string) => string; } { const history = useHistory(); @@ -52,7 +65,9 @@ export function useSearchPage(): { const generateSearchPageLink = useCallback( (targetSearchQuery: string) => // Refer to https://github.com/facebook/docusaurus/pull/2838 - `${baseUrl}search?q=${encodeURIComponent(targetSearchQuery)}`, + `${baseUrl}search?${SEARCH_PARAM_QUERY}=${encodeURIComponent( + targetSearchQuery, + )}`, [baseUrl], ); diff --git a/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts b/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts index aca25bf8311e..afd6a12b173f 100644 --- a/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts +++ b/packages/docusaurus-theme-common/src/hooks/useTOCHighlight.ts @@ -11,8 +11,10 @@ import {useThemeConfig} from '../utils/useThemeConfig'; // TODO make the hardcoded theme-classic classnames configurable (or add them // to ThemeClassNames?) -// If the anchor has no height and is just a "marker" in the dom; we'll use the -// parent (normally the link text) rect boundaries instead +/** + * If the anchor has no height and is just a "marker" in the DOM; we'll use the + * parent (normally the link text) rect boundaries instead + */ function getVisibleBoundingClientRect(element: HTMLElement): DOMRect { const rect = element.getBoundingClientRect(); const hasNoHeight = rect.top === rect.bottom; @@ -24,7 +26,7 @@ function getVisibleBoundingClientRect(element: HTMLElement): DOMRect { /** * Considering we divide viewport into 2 zones of each 50vh, this returns true - * if an element is in the first zone (ie, appear in viewport, near the top) + * if an element is in the first zone (i.e., appear in viewport, near the top) */ function isInViewportTopHalf(boundingRect: DOMRect) { return boundingRect.top > 0 && boundingRect.bottom < window.innerHeight / 2; @@ -114,12 +116,23 @@ function useAnchorTopOffsetRef() { } export type TOCHighlightConfig = { + /** A class name that all TOC links share. */ linkClassName: string; + /** The class name applied to the active (highlighted) link. */ linkActiveClassName: string; + /** + * The minimum heading level that the TOC includes. Only headings that are in + * this range will be eligible as "active heading". + */ minHeadingLevel: number; + /** @see {@link TOCHighlightConfig.minHeadingLevel} */ maxHeadingLevel: number; }; +/** + * Side-effect that applies the active class name to the TOC heading that the + * user is currently viewing. Disabled when `config` is undefined. + */ export function useTOCHighlight(config: TOCHighlightConfig | undefined): void { const lastActiveLinkRef = useRef(undefined); diff --git a/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts b/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts index b867cf4fd95a..a9583b199eb0 100644 --- a/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts +++ b/packages/docusaurus-theme-common/src/hooks/useWindowSize.ts @@ -12,12 +12,6 @@ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; const windowSizes = { desktop: 'desktop', mobile: 'mobile', - - // This "ssr" value is very important to handle hydration FOUC / layout shifts - // You have to handle server-rendering explicitly on the call-site - // On the server, you may need to render BOTH the mobile/desktop elements (and - // hide one of them with mediaquery) - // We don't return "undefined" on purpose, to make it more explicit ssr: 'ssr', } as const; @@ -34,13 +28,21 @@ function getWindowSize() { : windowSizes.mobile; } -// Simulate the SSR window size in dev, so that potential hydration FOUC/layout -// shift problems can be seen in dev too! const DevSimulateSSR = process.env.NODE_ENV === 'development' && true; -// This hook returns an enum value on purpose! -// We don't want it to return the actual width value, for resize perf reasons -// We only want to re-render once a breakpoint is crossed +/** + * Gets the current window size as an enum value. We don't want it to return the + * actual width value, so that it only re-renders once a breakpoint is crossed. + * + * It may return `"ssr"`, which is very important to handle hydration FOUC or + * layout shifts. You have to handle it explicitly upfront. On the server, you + * may need to render BOTH the mobile/desktop elements (and hide one of them + * with mediaquery). We don't return `undefined` on purpose, to make it more + * explicit. + * + * In development mode, this hook will still return `"ssr"` for one second, to + * catch potential layout shifts, similar to strict mode calling effects twice. + */ export function useWindowSize(): WindowSize { const [windowSize, setWindowSize] = useState(() => { if (DevSimulateSSR) { diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 4d0a02ef1058..a823af8d4220 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -23,28 +23,28 @@ export { DocSidebarItemsExpandedStateProvider, useDocSidebarItemsExpandedState, } from './contexts/docSidebarItemsExpandedState'; +export {DocsVersionProvider, useDocsVersion} from './contexts/docsVersion'; +export {DocsSidebarProvider, useDocsSidebar} from './contexts/docsSidebar'; export {createStorageSlot, listStorageKeys} from './utils/storageUtils'; export {useAlternatePageUtils} from './utils/useAlternatePageUtils'; -export {useContextualSearchFilters} from './utils/useContextualSearchFilters'; - export { parseCodeBlockTitle, parseLanguage, parseLines, } from './utils/codeBlockUtils'; -export {docVersionSearchTag, DEFAULT_SEARCH_TAG} from './utils/searchUtils'; +export { + docVersionSearchTag, + DEFAULT_SEARCH_TAG, + useContextualSearchFilters, +} from './utils/searchUtils'; export { isDocsPluginEnabled, - DocsVersionProvider, - useDocsVersion, useDocById, - DocsSidebarProvider, - useDocsSidebar, findSidebarCategory, findFirstCategoryLink, useCurrentSidebarCategory, @@ -52,20 +52,13 @@ export { useSidebarBreadcrumbs, } from './utils/docsUtils'; -export {isSamePath} from './utils/pathUtils'; - export {useTitleFormatter} from './utils/generalUtils'; export {usePluralForm} from './utils/usePluralForm'; export {useLocationChange} from './utils/useLocationChange'; -export { - useCollapsible, - Collapsible, - type UseCollapsibleConfig, - type UseCollapsibleReturns, -} from './components/Collapsible'; +export {useCollapsible, Collapsible} from './components/Collapsible'; export {Details, type DetailsProps} from './components/Details'; @@ -124,7 +117,7 @@ export { export {isRegexpStringMatch} from './utils/regexpUtils'; -export {useHomePageRoute} from './utils/routesUtils'; +export {useHomePageRoute, isSamePath} from './utils/routesUtils'; export { PageMetadata, @@ -149,8 +142,8 @@ export {useNavbarMobileSidebar} from './contexts/navbarMobileSidebar'; export { useNavbarSecondaryMenu, NavbarSecondaryMenuFiller, -} from './utils/navbarSecondaryMenu'; -export type {NavbarSecondaryMenuComponent} from './utils/navbarSecondaryMenu'; + type NavbarSecondaryMenuComponent, +} from './contexts/navbarSecondaryMenu'; export {useHideableNavbar} from './hooks/useHideableNavbar'; export { diff --git a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts index e5b49926357f..ec3ffc11a969 100644 --- a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts +++ b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts @@ -5,10 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -// These class names are used to style page layouts in Docusaurus -// Those are meant to be targeted by user-provided custom CSS selectors // Please do not modify the classnames! This is a breaking change, and annoying // for users! + +/** + * These class names are used to style page layouts in Docusaurus, meant to be + * targeted by user-provided custom CSS selectors. + */ export const ThemeClassNames = { page: { blogListPage: 'blog-list-page', @@ -17,8 +20,8 @@ export const ThemeClassNames = { blogTagPostListPage: 'blog-tags-post-list-page', docsDocPage: 'docs-doc-page', - docsTagsListPage: 'docs-tags-list-page', // List of tags - docsTagDocListPage: 'docs-tags-doc-list-page', // Docs for a tag + docsTagsListPage: 'docs-tags-list-page', + docsTagDocListPage: 'docs-tags-doc-list-page', mdxPage: 'mdx-page', }, @@ -29,8 +32,9 @@ export const ThemeClassNames = { mdxPages: 'mdx-wrapper', }, - // /!\ Please keep the naming convention consistent! - // Something like: "theme-{blog,doc,version,page}?-" + /** + * Follows the naming convention "theme-{blog,doc,version,page}?-" + */ common: { editThisPage: 'theme-edit-this-page', lastUpdated: 'theme-last-updated', diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index f0cc92830c1e..4fd8df849b2a 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -10,15 +10,13 @@ import {renderHook} from '@testing-library/react-hooks'; import { findFirstCategoryLink, isActiveSidebarItem, - DocsVersionProvider, - useDocsVersion, useDocById, - useDocsSidebar, - DocsSidebarProvider, findSidebarCategory, useCurrentSidebarCategory, useSidebarBreadcrumbs, } from '../docsUtils'; +import {DocsSidebarProvider} from '../../contexts/docsSidebar'; +import {DocsVersionProvider} from '../../contexts/docsVersion'; import {StaticRouter} from 'react-router-dom'; import {Context} from '@docusaurus/core/src/client/docusaurusContext'; import type { @@ -68,46 +66,6 @@ function testVersion(data?: Partial): PropVersionMetadata { }; } -describe('useDocsVersion', () => { - it('throws if context provider is missing', () => { - expect( - () => renderHook(() => useDocsVersion()).result.current, - ).toThrowErrorMatchingInlineSnapshot( - `"Hook useDocsVersion is called outside the . "`, - ); - }); - - it('reads value from context provider', () => { - const version = testVersion(); - const {result} = renderHook(() => useDocsVersion(), { - wrapper: ({children}) => ( - {children} - ), - }); - expect(result.current).toBe(version); - }); -}); - -describe('useDocsSidebar', () => { - it('throws if context provider is missing', () => { - expect( - () => renderHook(() => useDocsSidebar()).result.current, - ).toThrowErrorMatchingInlineSnapshot( - `"Hook useDocsSidebar is called outside the . "`, - ); - }); - - it('reads value from context provider', () => { - const sidebar: PropSidebar = []; - const {result} = renderHook(() => useDocsSidebar(), { - wrapper: ({children}) => ( - {children} - ), - }); - expect(result.current).toBe(sidebar); - }); -}); - describe('useDocById', () => { const version = testVersion({ docs: { @@ -506,11 +464,11 @@ describe('useCurrentSidebarCategory', () => { const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock([ category, ]); - expect(() => mockUseCurrentSidebarCategory('/cat')) - .toThrowErrorMatchingInlineSnapshot(` - "Unexpected: sidebar category could not be found for pathname='/cat'. - Hook useCurrentSidebarCategory() should only be used on Category pages" - `); + expect(() => + mockUseCurrentSidebarCategory('/cat'), + ).toThrowErrorMatchingInlineSnapshot( + `"/cat is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages."`, + ); }); it('throws when sidebar is missing', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts deleted file mode 100644 index a35cd30199b9..000000000000 --- a/packages/docusaurus-theme-common/src/utils/__tests__/pathUtils.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {isSamePath} from '../pathUtils'; - -describe('isSamePath', () => { - it('returns true for compared path without trailing slash', () => { - expect(isSamePath('/docs', '/docs')).toBeTruthy(); - }); - - it('returns true for compared path with trailing slash', () => { - expect(isSamePath('/docs', '/docs/')).toBeTruthy(); - }); - - it('returns true for compared path with different case', () => { - expect(isSamePath('/doCS', '/DOcs')).toBeTruthy(); - }); - - it('returns true for compared path with different case + trailing slash', () => { - expect(isSamePath('/doCS', '/DOcs/')).toBeTruthy(); - }); - - it('returns false for compared path with double trailing slash', () => { - expect(isSamePath('/docs', '/docs//')).toBeFalsy(); - }); - - it('returns true for twice undefined/null', () => { - expect(isSamePath(undefined, undefined)).toBeTruthy(); - expect(isSamePath(undefined, undefined)).toBeTruthy(); - }); - - it('returns false when one undefined', () => { - expect(isSamePath('/docs', undefined)).toBeFalsy(); - expect(isSamePath(undefined, '/docs')).toBeFalsy(); - }); -}); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts index 305164f36e64..a36e447d72a5 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts @@ -6,7 +6,39 @@ */ import type {Route} from '@docusaurus/types'; -import {findHomePageRoute} from '../routesUtils'; +import {findHomePageRoute, isSamePath} from '../routesUtils'; + +describe('isSamePath', () => { + it('returns true for compared path without trailing slash', () => { + expect(isSamePath('/docs', '/docs')).toBeTruthy(); + }); + + it('returns true for compared path with trailing slash', () => { + expect(isSamePath('/docs', '/docs/')).toBeTruthy(); + }); + + it('returns true for compared path with different case', () => { + expect(isSamePath('/doCS', '/DOcs')).toBeTruthy(); + }); + + it('returns true for compared path with different case + trailing slash', () => { + expect(isSamePath('/doCS', '/DOcs/')).toBeTruthy(); + }); + + it('returns false for compared path with double trailing slash', () => { + expect(isSamePath('/docs', '/docs//')).toBeFalsy(); + }); + + it('returns true for twice undefined/null', () => { + expect(isSamePath(undefined, undefined)).toBeTruthy(); + expect(isSamePath(undefined, undefined)).toBeTruthy(); + }); + + it('returns false when one undefined', () => { + expect(isSamePath('/docs', undefined)).toBeFalsy(); + expect(isSamePath(undefined, '/docs')).toBeFalsy(); + }); +}); describe('findHomePageRoute', () => { const homePage: Route = { diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index 3f4b2d7a2e93..8b89983bcbac 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -10,47 +10,24 @@ import rangeParser from 'parse-numeric-range'; const codeBlockTitleRegex = /title=(?["'])(?.*?)\1/; const highlightLinesRangeRegex = /\{(?<range>[\d,-]+)\}/; -const commentTypes = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const; -type CommentType = typeof commentTypes[number]; - -type CommentPattern = { - start: string; - end: string; -}; - // Supported types of highlight comments -const commentPatterns: Record<CommentType, CommentPattern> = { - js: { - start: '\\/\\/', - end: '', - }, - jsBlock: { - start: '\\/\\*', - end: '\\*\\/', - }, - jsx: { - start: '\\{\\s*\\/\\*', - end: '\\*\\/\\s*\\}', - }, - python: { - start: '#', - end: '', - }, - html: { - start: '<!--', - end: '-->', - }, +const commentPatterns = { + js: {start: '\\/\\/', end: ''}, + jsBlock: {start: '\\/\\*', end: '\\*\\/'}, + jsx: {start: '\\{\\s*\\/\\*', end: '\\*\\/\\s*\\}'}, + python: {start: '#', end: ''}, + html: {start: '<!--', end: '-->'}, }; +type CommentType = keyof typeof commentPatterns; + const magicCommentDirectives = [ 'highlight-next-line', 'highlight-start', 'highlight-end', ]; -const getMagicCommentDirectiveRegex = ( - languages: readonly CommentType[] = commentTypes, -) => { +function getCommentPattern(languages: CommentType[]) { // to be more reliable, the opening and closing comment must match const commentPattern = languages .map((lang) => { @@ -60,38 +37,45 @@ const getMagicCommentDirectiveRegex = ( .join('|'); // white space is allowed, but otherwise it should be on it's own line return new RegExp(`^\\s*(?:${commentPattern})\\s*$`); -}; +} -// select comment styles based on language -const magicCommentDirectiveRegex = (lang: string) => { +/** + * Select comment styles based on language + */ +function getAllMagicCommentDirectiveStyles(lang: string) { switch (lang) { case 'js': case 'javascript': case 'ts': case 'typescript': - return getMagicCommentDirectiveRegex(['js', 'jsBlock']); + return getCommentPattern(['js', 'jsBlock']); case 'jsx': case 'tsx': - return getMagicCommentDirectiveRegex(['js', 'jsBlock', 'jsx']); + return getCommentPattern(['js', 'jsBlock', 'jsx']); case 'html': - return getMagicCommentDirectiveRegex(['js', 'jsBlock', 'html']); + return getCommentPattern(['js', 'jsBlock', 'html']); case 'python': case 'py': - return getMagicCommentDirectiveRegex(['python']); + return getCommentPattern(['python']); default: // all comment types - return getMagicCommentDirectiveRegex(); + return getCommentPattern(Object.keys(commentPatterns) as CommentType[]); } -}; +} export function parseCodeBlockTitle(metastring?: string): string { return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? ''; } +/** + * Gets the language name from the class name (set by MDX). + * e.g. `"language-javascript"` => `"javascript"`. + * Returns undefined if there is no language class name. + */ export function parseLanguage(className: string): string | undefined { const languageClassName = className .split(' ') @@ -100,15 +84,33 @@ export function parseLanguage(className: string): string | undefined { } /** - * @param metastring The highlight range declared here starts at 1 - * @returns Note: all line numbers start at 0, not 1 + * Parses the code content, strips away any magic comments, and returns the + * clean content and the highlighted lines marked by the comments or metastring. + * + * If the metastring contains highlight range, the `content` will be returned + * as-is without any parsing. + * + * @param content The raw code with magic comments. Trailing newline will be + * trimmed upfront. + * @param metastring The full metastring, as received from MDX. Highlight range + * declared here starts at 1. + * @param language Language of the code block, used to determine which kinds of + * magic comment styles to enable. */ export function parseLines( content: string, metastring?: string, language?: string, ): { + /** + * The highlighted lines, 0-indexed. e.g. `[0, 1, 4]` means the 1st, 2nd, and + * 5th lines are highlighted. + */ highlightLines: number[]; + /** + * The clean code without any magic comments (only if highlight range isn't + * present in the metastring). + */ code: string; } { let code = content.replace(/\n$/, ''); @@ -124,7 +126,7 @@ export function parseLines( if (language === undefined) { return {highlightLines: [], code}; } - const directiveRegex = magicCommentDirectiveRegex(language); + const directiveRegex = getAllMagicCommentDirectiveStyles(language); // go through line by line const lines = code.split('\n'); let highlightBlockStart: number; diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 7d51244caab3..2a16dc6f8eb0 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -5,57 +5,32 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode, useContext} from 'react'; import { - useActivePlugin, useAllDocsData, + useActivePlugin, } from '@docusaurus/plugin-content-docs/client'; import type { PropSidebar, PropSidebarItem, PropSidebarItemCategory, PropVersionDoc, - PropVersionMetadata, PropSidebarBreadcrumbsItem, } from '@docusaurus/plugin-content-docs'; -import {isSamePath} from './pathUtils'; -import {ReactContextError} from './reactUtils'; +import {useDocsVersion} from '../contexts/docsVersion'; +import {useDocsSidebar} from '../contexts/docsSidebar'; +import {isSamePath} from './routesUtils'; import {useLocation} from '@docusaurus/router'; // TODO not ideal, see also "useDocs" export const isDocsPluginEnabled: boolean = !!useAllDocsData; -// Using a Symbol because null is a valid context value (a doc with no sidebar) -// Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx -const EmptyContextValue: unique symbol = Symbol('EmptyContext'); - -const DocsVersionContext = React.createContext< - PropVersionMetadata | typeof EmptyContextValue ->(EmptyContextValue); - -export function DocsVersionProvider({ - children, - version, -}: { - children: ReactNode; - version: PropVersionMetadata | typeof EmptyContextValue; -}): JSX.Element { - return ( - <DocsVersionContext.Provider value={version}> - {children} - </DocsVersionContext.Provider> - ); -} - -export function useDocsVersion(): PropVersionMetadata { - const version = useContext(DocsVersionContext); - if (version === EmptyContextValue) { - throw new ReactContextError('DocsVersionProvider'); - } - return version; -} - +/** + * A null-safe way to access a doc's data by ID in the active version. + */ export function useDocById(id: string): PropVersionDoc; +/** + * A null-safe way to access a doc's data by ID in the active version. + */ export function useDocById(id: string | undefined): PropVersionDoc | undefined; export function useDocById(id: string | undefined): PropVersionDoc | undefined { const version = useDocsVersion(); @@ -69,34 +44,9 @@ export function useDocById(id: string | undefined): PropVersionDoc | undefined { return doc; } -const DocsSidebarContext = React.createContext< - PropSidebar | null | typeof EmptyContextValue ->(EmptyContextValue); - -export function DocsSidebarProvider({ - children, - sidebar, -}: { - children: ReactNode; - sidebar: PropSidebar | null; -}): JSX.Element { - return ( - <DocsSidebarContext.Provider value={sidebar}> - {children} - </DocsSidebarContext.Provider> - ); -} - -export function useDocsSidebar(): PropSidebar | null { - const sidebar = useContext(DocsSidebarContext); - if (sidebar === EmptyContextValue) { - throw new ReactContextError('DocsSidebarProvider'); - } - return sidebar; -} - -// Use the components props and the sidebar in context -// to get back the related sidebar category that we want to render +/** + * Pure function, similar to `Array#find`, but works on the sidebar tree. + */ export function findSidebarCategory( sidebar: PropSidebar, predicate: (category: PropSidebarItemCategory) => boolean, @@ -115,7 +65,10 @@ export function findSidebarCategory( return undefined; } -// If a category card has no link => link to the first subItem having a link +/** + * Best effort to assign a link to a sidebar category. If the category doesn't + * have a link itself, we link to the first sub item with a link. + */ export function findFirstCategoryLink( item: PropSidebarItemCategory, ): string | undefined { @@ -142,6 +95,10 @@ export function findFirstCategoryLink( return undefined; } +/** + * Gets the category associated with the current location. Should only be used + * on category index pages. + */ export function useCurrentSidebarCategory(): PropSidebarItemCategory { const {pathname} = useLocation(); const sidebar = useDocsSidebar(); @@ -153,47 +110,53 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory { ); if (!category) { throw new Error( - `Unexpected: sidebar category could not be found for pathname='${pathname}'. -Hook useCurrentSidebarCategory() should only be used on Category pages`, + `${pathname} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`, ); } return category; } -function containsActiveSidebarItem( +const isActive = (testedPath: string | undefined, activePath: string) => + typeof testedPath !== 'undefined' && isSamePath(testedPath, activePath); +const containsActiveSidebarItem = ( items: PropSidebarItem[], activePath: string, -): boolean { - return items.some((subItem) => isActiveSidebarItem(subItem, activePath)); -} +) => items.some((subItem) => isActiveSidebarItem(subItem, activePath)); +/** + * Checks if a sidebar item should be active, based on the active path. + */ export function isActiveSidebarItem( item: PropSidebarItem, activePath: string, ): boolean { - const isActive = (testedPath: string | undefined) => - typeof testedPath !== 'undefined' && isSamePath(testedPath, activePath); - if (item.type === 'link') { - return isActive(item.href); + return isActive(item.href, activePath); } if (item.type === 'category') { return ( - isActive(item.href) || containsActiveSidebarItem(item.items, activePath) + isActive(item.href, activePath) || + containsActiveSidebarItem(item.items, activePath) ); } return false; } -function getBreadcrumbs({ - sidebar, - pathname, -}: { - sidebar: PropSidebar; - pathname: string; -}): PropSidebarBreadcrumbsItem[] { +/** + * Gets the breadcrumbs of the current doc page, based on its sidebar location. + * Returns `null` if there's no sidebar or breadcrumbs are disabled. + */ +export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null { + const sidebar = useDocsSidebar(); + const {pathname} = useLocation(); + const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs; + + if (breadcrumbsOption === false || !sidebar) { + return null; + } + const breadcrumbs: PropSidebarBreadcrumbsItem[] = []; function extract(items: PropSidebar) { @@ -215,15 +178,3 @@ function getBreadcrumbs({ return breadcrumbs.reverse(); } - -export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null { - const sidebar = useDocsSidebar(); - const {pathname} = useLocation(); - const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs; - - if (breadcrumbsOption === false || !sidebar) { - return null; - } - - return getBreadcrumbs({sidebar, pathname}); -} diff --git a/packages/docusaurus-theme-common/src/utils/footerUtils.ts b/packages/docusaurus-theme-common/src/utils/footerUtils.ts index 2ced0cd6df17..28add85dceee 100644 --- a/packages/docusaurus-theme-common/src/utils/footerUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/footerUtils.ts @@ -7,6 +7,10 @@ import type {MultiColumnFooter, SimpleFooter} from './useThemeConfig'; +/** + * A rough duck-typing about whether the `footer.links` is intended to be multi- + * column. + */ export function isMultiColumnFooterLinks( links: MultiColumnFooter['links'] | SimpleFooter['links'], ): links is MultiColumnFooter['links'] { diff --git a/packages/docusaurus-theme-common/src/utils/generalUtils.ts b/packages/docusaurus-theme-common/src/utils/generalUtils.ts index ba98a144bfa4..c6732b82ccf6 100644 --- a/packages/docusaurus-theme-common/src/utils/generalUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/generalUtils.ts @@ -7,6 +7,9 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +/** + * Formats the page's title based on relevant site config and other contexts. + */ export function useTitleFormatter(title?: string | undefined): string { const {siteConfig} = useDocusaurusContext(); const {title: siteTitle, titleDelimiter} = siteConfig; diff --git a/packages/docusaurus-theme-common/src/utils/historyUtils.ts b/packages/docusaurus-theme-common/src/utils/historyUtils.ts index c0a289dcc1f4..129396b44e7d 100644 --- a/packages/docusaurus-theme-common/src/utils/historyUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/historyUtils.ts @@ -5,44 +5,38 @@ * LICENSE file in the root directory of this source tree. */ -import {useEffect, useRef} from 'react'; +import {useEffect} from 'react'; import {useHistory} from '@docusaurus/router'; +import {useDynamicCallback} from './reactUtils'; import type {Location, Action} from 'history'; type HistoryBlockHandler = (location: Location, action: Action) => void | false; /** * Permits to register a handler that will be called on history actions (pop, - * push, replace) If the handler returns false, the navigation transition will - * be blocked/cancelled + * push, replace). If the handler returns `false`, the navigation transition + * will be blocked/cancelled. */ -export function useHistoryActionHandler(handler: HistoryBlockHandler): void { +function useHistoryActionHandler(handler: HistoryBlockHandler): void { const {block} = useHistory(); - - // Avoid stale closure issues without triggering useless re-renders - const lastHandlerRef = useRef(handler); - useEffect(() => { - lastHandlerRef.current = handler; - }, [handler]); - + const stableHandler = useDynamicCallback(handler); useEffect( - () => - // See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md - block((location, action) => lastHandlerRef.current(location, action)), - [block, lastHandlerRef], + // See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md + () => block((location, action) => stableHandler(location, action)), + [block, stableHandler], ); } /** * Permits to register a handler that will be called on history pop navigation - * (backward/forward) If the handler returns false, the backward/forward + * (backward/forward). If the handler returns `false`, the backward/forward * transition will be blocked. Unfortunately there's no good way to detect the * "direction" (backward/forward) of the POP event. */ export function useHistoryPopHandler(handler: HistoryBlockHandler): void { useHistoryActionHandler((location, action) => { if (action === 'POP') { - // Eventually block navigation if handler returns false + // Maybe block navigation if handler returns false return handler(location, action); } // Don't block other navigation actions diff --git a/packages/docusaurus-theme-common/src/utils/jsUtils.ts b/packages/docusaurus-theme-common/src/utils/jsUtils.ts index 5a4c43aca9d3..740a5a8b61df 100644 --- a/packages/docusaurus-theme-common/src/utils/jsUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/jsUtils.ts @@ -26,7 +26,7 @@ export function duplicates<T>( } /** - * Remove duplicate array items (similar to _.uniq) + * Remove duplicate array items (similar to `_.uniq`) * @param arr The array. * @returns An array with duplicate elements removed by reference comparison. */ diff --git a/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx index 9de31637150e..d7b85f0d04b3 100644 --- a/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx @@ -20,7 +20,10 @@ interface PageMetadataProps { readonly children?: ReactNode; } -// Helper component to manipulate page metadata and override site defaults +/** + * Helper component to manipulate page metadata and override site defaults. + * Works in the same way as Helmet. + */ export function PageMetadata({ title, description, @@ -44,6 +47,7 @@ export function PageMetadata({ <meta name="keywords" content={ + // https://github.com/microsoft/TypeScript/issues/17002 (Array.isArray(keywords) ? keywords.join(',') : keywords) as string } /> @@ -59,8 +63,12 @@ export function PageMetadata({ const HtmlClassNameContext = React.createContext<string | undefined>(undefined); -// This wrapper is necessary because Helmet does not "merge" classes -// See https://github.com/staylor/react-helmet-async/issues/161 +/** + * Every layer of this provider will append a class name to the HTML element. + * There's no consumer for this hook: it's side-effect-only. This wrapper is + * necessary because Helmet does not "merge" classes. + * @see https://github.com/staylor/react-helmet-async/issues/161 + */ export function HtmlClassNameProvider({ className: classNameProp, children, @@ -87,6 +95,10 @@ function pluginNameToClassName(pluginName: string) { )}`; } +/** + * A very thin wrapper around `HtmlClassNameProvider` that adds the plugin ID + + * name to the HTML class name. + */ export function PluginHtmlClassNameProvider({ children, }: { diff --git a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx index b9433574caae..cb93708d3fb5 100644 --- a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx @@ -7,7 +7,7 @@ import React, {type ReactNode} from 'react'; import {NavbarMobileSidebarProvider} from '../contexts/navbarMobileSidebar'; -import {NavbarSecondaryMenuProvider} from './navbarSecondaryMenu'; +import {NavbarSecondaryMenuProvider} from '../contexts/navbarSecondaryMenu'; const DefaultNavItemPosition = 'right'; diff --git a/packages/docusaurus-theme-common/src/utils/pathUtils.ts b/packages/docusaurus-theme-common/src/utils/pathUtils.ts deleted file mode 100644 index a3eacf47238b..000000000000 --- a/packages/docusaurus-theme-common/src/utils/pathUtils.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * Compare the 2 paths, case insensitive and ignoring trailing slash - */ -export const isSamePath = ( - path1: string | undefined, - path2: string | undefined, -): boolean => { - const normalize = (pathname: string | undefined) => - (!pathname || pathname?.endsWith('/') - ? pathname - : `${pathname}/` - )?.toLowerCase(); - return normalize(path1) === normalize(path2); -}; diff --git a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx index b2e5d5c0436b..09cb1b7b52e7 100644 --- a/packages/docusaurus-theme-common/src/utils/reactUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/reactUtils.tsx @@ -9,11 +9,12 @@ import {useCallback, useEffect, useLayoutEffect, useRef} from 'react'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; /** - * This hook is like useLayoutEffect, but without the SSR warning - * It seems hacky but it's used in many React libs (Redux, Formik...) + * This hook is like `useLayoutEffect`, but without the SSR warning. + * It seems hacky but it's used in many React libs (Redux, Formik...). * Also mentioned here: https://github.com/facebook/react/issues/16956 + * * It is useful when you need to update a ref as soon as possible after a React - * render (before `useEffect`) + * render (before `useEffect`). */ export const useIsomorphicLayoutEffect = ExecutionEnvironment.canUseDOM ? useLayoutEffect @@ -23,10 +24,11 @@ export const useIsomorphicLayoutEffect = ExecutionEnvironment.canUseDOM * Permits to transform an unstable callback (like an arrow function provided as * props) to a "stable" callback that is safe to use in a `useEffect` dependency * array. Useful to avoid React stale closure problems + avoid useless effect - * re-executions + * re-executions. * * Workaround until the React team recommends a good solution, see * https://github.com/facebook/react/issues/16956 + * * This generally works but has some potential drawbacks, such as * https://github.com/facebook/react/issues/16956#issuecomment-536636418 */ @@ -44,6 +46,9 @@ export function useDynamicCallback<T extends (...args: never[]) => unknown>( return useCallback<T>((...args) => ref.current(...args), []); } +/** + * Gets `value` from the last render. + */ export function usePrevious<T>(value: T): T | undefined { const ref = useRef<T>(); @@ -54,6 +59,11 @@ export function usePrevious<T>(value: T): T | undefined { return ref.current; } +/** + * This error is thrown when a context is consumed outside its provider. Allows + * reusing a generic error message format and reduces bundle size. The hook's + * name will be extracted from its stack, so only the provider's name is needed. + */ export class ReactContextError extends Error { constructor(providerName: string, additionalInfo?: string) { super(); diff --git a/packages/docusaurus-theme-common/src/utils/regexpUtils.ts b/packages/docusaurus-theme-common/src/utils/regexpUtils.ts index 36d8b8e8de97..4e87fe68c2ef 100644 --- a/packages/docusaurus-theme-common/src/utils/regexpUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/regexpUtils.ts @@ -6,7 +6,8 @@ */ /** - * Converts an optional string into a Regex case insensitive and global + * Matches a string regex (as provided from the config) against a target in a + * null-safe fashion, case insensitive and global. */ export function isRegexpStringMatch( regexAsString?: string, diff --git a/packages/docusaurus-theme-common/src/utils/routesUtils.ts b/packages/docusaurus-theme-common/src/utils/routesUtils.ts index e826771119c6..2b48b8bccde2 100644 --- a/packages/docusaurus-theme-common/src/utils/routesUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/routesUtils.ts @@ -5,11 +5,26 @@ * LICENSE file in the root directory of this source tree. */ -import generatedRoutes from '@generated/routes'; import {useMemo} from 'react'; +import generatedRoutes from '@generated/routes'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import type {Route} from '@docusaurus/types'; +/** + * Compare the 2 paths, case insensitive and ignoring trailing slash + */ +export function isSamePath( + path1: string | undefined, + path2: string | undefined, +): boolean { + const normalize = (pathname: string | undefined) => + (!pathname || pathname?.endsWith('/') + ? pathname + : `${pathname}/` + )?.toLowerCase(); + return normalize(path1) === normalize(path2); +} + /** * Note that sites don't always have a homepage in practice, so we can't assume * that linking to '/' is always safe. @@ -47,14 +62,14 @@ export function findHomePageRoute({ return doFindHomePageRoute(initialRoutes); } +/** + * Fetches the route that points to "/". Use this instead of the naive "/", + * because the homepage may not exist. + */ export function useHomePageRoute(): Route | undefined { const {baseUrl} = useDocusaurusContext().siteConfig; return useMemo( - () => - findHomePageRoute({ - routes: generatedRoutes, - baseUrl, - }), + () => findHomePageRoute({routes: generatedRoutes, baseUrl}), [baseUrl], ); } diff --git a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx index 74e372a1d999..9c49e0c146bb 100644 --- a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx @@ -17,25 +17,12 @@ import React, { import {useDynamicCallback, ReactContextError} from './reactUtils'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; -/** - * We need a way to update the scroll position while ignoring scroll events - * without affecting Navbar/BackToTop visibility - * - * This API permits to temporarily disable/ignore scroll events - * Motivated by https://github.com/facebook/docusaurus/pull/5618 - */ type ScrollController = { - /** - * A boolean ref tracking whether scroll events are enabled - */ + /** A boolean ref tracking whether scroll events are enabled. */ scrollEventsEnabledRef: React.MutableRefObject<boolean>; - /** - * Enables scroll events in `useScrollPosition` - */ + /** Enable scroll events in `useScrollPosition`. */ enableScrollEvents: () => void; - /** - * Disables scroll events in `useScrollPosition` - */ + /** Disable scroll events in `useScrollPosition`. */ disableScrollEvents: () => void; }; @@ -65,13 +52,21 @@ export function ScrollControllerProvider({ }: { children: ReactNode; }): JSX.Element { + const value = useScrollControllerContextValue(); return ( - <ScrollMonitorContext.Provider value={useScrollControllerContextValue()}> + <ScrollMonitorContext.Provider value={value}> {children} </ScrollMonitorContext.Provider> ); } +/** + * We need a way to update the scroll position while ignoring scroll events + * so as not to toggle Navbar/BackToTop visibility. + * + * This API permits to temporarily disable/ignore scroll events. Motivated by + * https://github.com/facebook/docusaurus/pull/5618 + */ export function useScrollController(): ScrollController { const context = useContext(ScrollMonitorContext); if (context == null) { @@ -80,6 +75,8 @@ export function useScrollController(): ScrollController { return context; } +type ScrollPosition = {scrollX: number; scrollY: number}; + const getScrollPosition = (): ScrollPosition | null => ExecutionEnvironment.canUseDOM ? { @@ -88,8 +85,14 @@ const getScrollPosition = (): ScrollPosition | null => } : null; -type ScrollPosition = {scrollX: number; scrollY: number}; - +/** + * This hook fires an effect when the scroll position changes. The effect will + * be provided with the before/after scroll positions. Note that the effect may + * not be always run: if scrolling is disabled through `useScrollController`, it + * will be a no-op. + * + * @see {@link useScrollController} + */ export function useScrollPosition( effect: ( position: ScrollPosition, @@ -124,22 +127,16 @@ export function useScrollPosition( window.addEventListener('scroll', handleScroll, opts); return () => window.removeEventListener('scroll', handleScroll, opts); - }, [ - dynamicEffect, - scrollEventsEnabledRef, // eslint-disable-next-line react-hooks/exhaustive-deps - ...deps, - ]); + }, [dynamicEffect, scrollEventsEnabledRef, ...deps]); } type UseScrollPositionSaver = { - /** - * Measure the top of an element, and store the details - */ + /** Measure the top of an element, and store the details. */ save: (elem: HTMLElement) => void; /** * Restore the page position to keep the stored element's position from - * the top of the viewport, and remove the stored details + * the top of the viewport, and remove the stored details. */ restore: () => {restored: boolean}; }; @@ -177,21 +174,24 @@ function useScrollPositionSaver(): UseScrollPositionSaver { return useMemo(() => ({save, restore}), [restore, save]); } -type UseScrollPositionBlockerReturn = { - blockElementScrollPositionUntilNextRender: (el: HTMLElement) => void; -}; - /** - * This hook permits to "block" the scroll position of a dom element + * This hook permits to "block" the scroll position of a DOM element. * The idea is that we should be able to update DOM content above this element - * but the screen position of this element should not change + * but the screen position of this element should not change. + * + * Feature motivated by the Tabs groups: clicking on a tab may affect tabs of + * the same group upper in the tree, yet to avoid a bad UX, the clicked tab must + * remain under the user mouse. * - * Feature motivated by the Tabs groups: - * clicking on a tab may affect tabs of the same group upper in the tree - * Yet to avoid a bad UX, the clicked tab must remain under the user mouse! - * See GIF here: https://github.com/facebook/docusaurus/pull/5618 + * @see https://github.com/facebook/docusaurus/pull/5618 */ -export function useScrollPositionBlocker(): UseScrollPositionBlockerReturn { +export function useScrollPositionBlocker(): { + /** + * Takes an element, and keeps its screen position no matter what's getting + * rendered above it, until the next render. + */ + blockElementScrollPositionUntilNextRender: (el: HTMLElement) => void; +} { const scrollController = useScrollController(); const scrollPositionSaver = useScrollPositionSaver(); @@ -207,9 +207,9 @@ export function useScrollPositionBlocker(): UseScrollPositionBlockerReturn { const {restored} = scrollPositionSaver.restore(); nextLayoutEffectCallbackRef.current = undefined; - // Restoring the former scroll position will trigger a scroll event - // We need to wait for next scroll event to happen - // before enabling again the scrollController events + // Restoring the former scroll position will trigger a scroll event. We + // need to wait for next scroll event to happen before enabling the + // scrollController events again. if (restored) { const handleScrollRestoreEvent = () => { scrollController.enableScrollEvents(); diff --git a/packages/docusaurus-theme-common/src/utils/searchUtils.ts b/packages/docusaurus-theme-common/src/utils/searchUtils.ts index daa93c9c4db1..57fdb3635f9b 100644 --- a/packages/docusaurus-theme-common/src/utils/searchUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/searchUtils.ts @@ -5,11 +5,60 @@ * LICENSE file in the root directory of this source tree. */ +import { + useAllDocsData, + useActivePluginAndVersion, +} from '@docusaurus/plugin-content-docs/client'; +import {useDocsPreferredVersionByPluginId} from '../contexts/docsPreferredVersion'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; + export const DEFAULT_SEARCH_TAG = 'default'; +/** The search tag to append as each doc's metadata. */ export function docVersionSearchTag( pluginId: string, versionName: string, ): string { return `docs-${pluginId}-${versionName}`; } + +/** + * Gets the relevant context information for contextual search. + * + * The value is generic and not coupled to Algolia/DocSearch, since we may want + * to support multiple search engines, or allowing users to use their own search + * engine solution. + */ +export function useContextualSearchFilters(): {locale: string; tags: string[]} { + const {i18n} = useDocusaurusContext(); + const allDocsData = useAllDocsData(); + const activePluginAndVersion = useActivePluginAndVersion(); + const docsPreferredVersionByPluginId = useDocsPreferredVersionByPluginId(); + + function getDocPluginTags(pluginId: string) { + const activeVersion = + activePluginAndVersion?.activePlugin?.pluginId === pluginId + ? activePluginAndVersion.activeVersion + : undefined; + + const preferredVersion = docsPreferredVersionByPluginId[pluginId]; + + const latestVersion = allDocsData[pluginId]!.versions.find( + (v) => v.isLast, + )!; + + const version = activeVersion ?? preferredVersion ?? latestVersion; + + return docVersionSearchTag(pluginId, version.name); + } + + const tags = [ + DEFAULT_SEARCH_TAG, + ...Object.keys(allDocsData).map(getDocPluginTags), + ]; + + return { + locale: i18n.currentLocale, + tags, + }; +} diff --git a/packages/docusaurus-theme-common/src/utils/storageUtils.ts b/packages/docusaurus-theme-common/src/utils/storageUtils.ts index cd03b6417087..d5dcbdc8c3f5 100644 --- a/packages/docusaurus-theme-common/src/utils/storageUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/storageUtils.ts @@ -11,8 +11,12 @@ export type StorageType = typeof StorageTypes[number]; const DefaultStorageType: StorageType = 'localStorage'; -// Will return null browser storage is unavailable (like running Docusaurus in -// iframe) See https://github.com/facebook/docusaurus/pull/4501 +/** + * Will return `null` if browser storage is unavailable (like running Docusaurus + * in an iframe). This should NOT be called in SSR. + * + * @see https://github.com/facebook/docusaurus/pull/4501 + */ function getBrowserStorage( storageType: StorageType = DefaultStorageType, ): Storage | null { @@ -32,11 +36,12 @@ function getBrowserStorage( } } +let hasLoggedBrowserStorageNotAvailableWarning = false; /** - * Poor man's memoization to avoid logging multiple times the same warning - * Sometimes, localStorage/sessionStorage is unavailable due to browser policies + * Poor man's memoization to avoid logging multiple times the same warning. + * Sometimes, `localStorage`/`sessionStorage` is unavailable due to browser + * policies. */ -let hasLoggedBrowserStorageNotAvailableWarning = false; function logOnceBrowserStorageNotAvailableWarning(error: Error) { if (!hasLoggedBrowserStorageNotAvailableWarning) { console.warn( @@ -61,7 +66,7 @@ const NoopStorageSlot: StorageSlot = { del: () => {}, }; -// Fail-fast, as storage APIs should not be used during the SSR process +// Fail-fast, as storage APIs should not be used during the SSR process function createServerStorageSlot(key: string): StorageSlot { function throwError(): never { throw new Error(`Illegal storage API usage for storage key "${key}". @@ -77,16 +82,19 @@ Please only call storage APIs in effects and event handlers.`); } /** - * Creates an object for accessing a particular key in localStorage. - * The API is fail-safe, and usage of browser storage should be considered + * Creates an interface to work on a particular key in the storage model. + * Note that this function only initializes the interface, but doesn't allocate + * anything by itself (i.e. no side-effects). + * + * The API is fail-safe, since usage of browser storage should be considered * unreliable. Local storage might simply be unavailable (iframe + browser * security) or operations might fail individually. Please assume that using - * this API can be a NO-OP. See also https://github.com/facebook/docusaurus/issues/6036 + * this API can be a no-op. See also https://github.com/facebook/docusaurus/issues/6036 */ -export const createStorageSlot = ( +export function createStorageSlot( key: string, options?: {persistence?: StorageType}, -): StorageSlot => { +): StorageSlot { if (typeof window === 'undefined') { return createServerStorageSlot(key); } @@ -121,10 +129,10 @@ export const createStorageSlot = ( } }, }; -}; +} /** - * Returns a list of all the keys currently stored in browser storage + * Returns a list of all the keys currently stored in browser storage, * or an empty list if browser storage can't be accessed. */ export function listStorageKeys( diff --git a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts index 3c1aee95c015..4405a8631d27 100644 --- a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts @@ -26,10 +26,13 @@ function getTagLetter(tag: string): string { return tag[0]!.toUpperCase(); } +/** + * Takes a list of tags (as provided by the content plugins), and groups them by + * their initials. + */ export function listTagsByLetters( tags: readonly TagsListItem[], ): TagLetterEntry[] { - // Group by letters const groups: Record<string, TagsListItem[]> = {}; Object.values(tags).forEach((tag) => { const letter = getTagLetter(tag.name); diff --git a/packages/docusaurus-theme-common/src/utils/tocUtils.ts b/packages/docusaurus-theme-common/src/utils/tocUtils.ts index d02ed1b472ca..c5a7fc9c6659 100644 --- a/packages/docusaurus-theme-common/src/utils/tocUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tocUtils.ts @@ -52,6 +52,10 @@ function treeifyTOC(flatTOC: readonly TOCItem[]): TOCTreeNode[] { return rootNodes; } +/** + * Takes a flat TOC list (from the MDX loader) and treeifies it into what the + * TOC components expect. Memoized for performance. + */ export function useTreeifiedTOC(toc: TOCItem[]): readonly TOCTreeNode[] { return useMemo(() => treeifyTOC(toc), [toc]); } @@ -87,6 +91,18 @@ function filterTOC({ }); } +/** + * Takes a flat TOC list (from the MDX loader) and treeifies it into what the + * TOC components expect, applying the `minHeadingLevel` and `maxHeadingLevel`. + * Memoized for performance. + * + * **Important**: this is not the same as `useTreeifiedTOC(toc.filter(...))`, + * because we have to filter the TOC after it has been treeified. This is mostly + * to ensure that weird TOC structures preserve their semantics. For example, an + * h3-h2-h4 sequence should not be treeified as an "h3 > h4" hierarchy with + * min=3, max=4, but should rather be "[h3, h4]" (since the h2 heading has split + * the two headings and they are not parents) + */ export function useFilteredAndTreeifiedTOC({ toc, minHeadingLevel, @@ -97,12 +113,7 @@ export function useFilteredAndTreeifiedTOC({ maxHeadingLevel: number; }): readonly TOCTreeNode[] { return useMemo( - () => - // Note: we have to filter the TOC after it has been treeified. This is - // mostly to ensure that weird TOC structures preserve their semantics. - // For example, an h3-h2-h4 sequence should not be treeified as an h3 > h4 - // hierarchy with min=3, max=4, but should rather be [h3, h4] - filterTOC({toc: treeifyTOC(toc), minHeadingLevel, maxHeadingLevel}), + () => filterTOC({toc: treeifyTOC(toc), minHeadingLevel, maxHeadingLevel}), [toc, minHeadingLevel, maxHeadingLevel], ); } diff --git a/packages/docusaurus-theme-common/src/utils/useAlternatePageUtils.ts b/packages/docusaurus-theme-common/src/utils/useAlternatePageUtils.ts index 29ce6f14fecf..ae0e55dcddff 100644 --- a/packages/docusaurus-theme-common/src/utils/useAlternatePageUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/useAlternatePageUtils.ts @@ -8,12 +8,26 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import {useLocation} from '@docusaurus/router'; -// Permits to obtain the url of the current page in another locale -// Useful to generate hreflang meta headers etc... -// See https://developers.google.com/search/docs/advanced/crawling/localized-versions +/** + * Permits to obtain the url of the current page in another locale, useful to + * generate hreflang meta headers etc... + * + * @see https://developers.google.com/search/docs/advanced/crawling/localized-versions + */ export function useAlternatePageUtils(): { + /** + * Everything (pathname, base URL, etc.) is read from the context. Just tell + * it which locale to link to and it will give you the alternate link for the + * current page. + */ createUrl: ({ + /** The locale name to link to. */ locale, + /** + * For hreflang SEO headers, we need it to be fully qualified (full + * protocol/domain/path...); but for locale dropdowns, using a pathname is + * good enough. + */ fullyQualified, }: { locale: string; @@ -46,8 +60,6 @@ export function useAlternatePageUtils(): { fullyQualified, }: { locale: string; - // For hreflang SEO headers, we need it to be fully qualified (full - // protocol/domain/path...) or locale dropdown, using a path is good enough fullyQualified: boolean; }) { return `${fullyQualified ? url : ''}${getLocalizedBaseUrl( diff --git a/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts b/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts deleted file mode 100644 index 28f9231a371a..000000000000 --- a/packages/docusaurus-theme-common/src/utils/useContextualSearchFilters.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { - useAllDocsData, - useActivePluginAndVersion, -} from '@docusaurus/plugin-content-docs/client'; -import {useDocsPreferredVersionByPluginId} from '../contexts/docsPreferredVersion'; -import {docVersionSearchTag, DEFAULT_SEARCH_TAG} from './searchUtils'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; - -export type useContextualSearchFiltersReturns = { - locale: string; - tags: string[]; -}; - -// We may want to support multiple search engines, don't couple that to -// Algolia/DocSearch. Maybe users want to use their own search engine solution -export function useContextualSearchFilters(): useContextualSearchFiltersReturns { - const {i18n} = useDocusaurusContext(); - const allDocsData = useAllDocsData(); - const activePluginAndVersion = useActivePluginAndVersion(); - const docsPreferredVersionByPluginId = useDocsPreferredVersionByPluginId(); - - function getDocPluginTags(pluginId: string) { - const activeVersion = - activePluginAndVersion?.activePlugin?.pluginId === pluginId - ? activePluginAndVersion.activeVersion - : undefined; - - const preferredVersion = docsPreferredVersionByPluginId[pluginId]; - - const latestVersion = allDocsData[pluginId]!.versions.find( - (v) => v.isLast, - )!; - - const version = activeVersion ?? preferredVersion ?? latestVersion; - - return docVersionSearchTag(pluginId, version.name); - } - - const tags = [ - DEFAULT_SEARCH_TAG, - ...Object.keys(allDocsData).map(getDocPluginTags), - ]; - - return { - locale: i18n.currentLocale, - tags, - }; -} diff --git a/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts b/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts index a7097b13b56f..07a1e987136b 100644 --- a/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts +++ b/packages/docusaurus-theme-common/src/utils/useLocalPathname.ts @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import {useLocation} from '@docusaurus/router'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; /** - * Get the pathname of current route, without the optional site baseUrl - * - /docs/myDoc => /docs/myDoc - * - /baseUrl/docs/myDoc => /docs/myDoc + * Get the pathname of current route, without the optional site baseUrl. + * - `/docs/myDoc` => `/docs/myDoc` + * - `/baseUrl/docs/myDoc` => `/docs/myDoc` */ export function useLocalPathname(): string { const { diff --git a/packages/docusaurus-theme-common/src/utils/useLocationChange.ts b/packages/docusaurus-theme-common/src/utils/useLocationChange.ts index 8d947257c38f..dd8ec1d0249c 100644 --- a/packages/docusaurus-theme-common/src/utils/useLocationChange.ts +++ b/packages/docusaurus-theme-common/src/utils/useLocationChange.ts @@ -10,14 +10,17 @@ import {useLocation} from '@docusaurus/router'; import type {Location} from 'history'; import {useDynamicCallback, usePrevious} from './reactUtils'; -type LocationChangeEvent = { - location: Location; - previousLocation: Location | undefined; -}; - -type OnLocationChange = (locationChangeEvent: LocationChangeEvent) => void; - -export function useLocationChange(onLocationChange: OnLocationChange): void { +/** + * Fires an effect when the location changes (which includes hash, query, etc.). + * Importantly, doesn't fire when there's no previous location: see + * https://github.com/facebook/docusaurus/pull/6696 + */ +export function useLocationChange( + onLocationChange: (locationChangeEvent: { + location: Location; + previousLocation: Location | undefined; + }) => void, +): void { const location = useLocation(); const previousLocation = usePrevious(location); diff --git a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts index 349047d216d7..cc5ce45317bf 100644 --- a/packages/docusaurus-theme-common/src/utils/usePluralForm.ts +++ b/packages/docusaurus-theme-common/src/utils/usePluralForm.ts @@ -105,7 +105,18 @@ function selectPluralMessage( return parts[Math.min(pluralFormIndex, parts.length - 1)]!; } +/** + * Reads the current locale and returns an interface very similar to + * `Intl.PluralRules`. + */ export function usePluralForm(): { + /** + * Give it a `count` and it will select the relevant message from + * `pluralMessages`. `pluralMessages` should be separated by `|`, and in the + * order of "zero", "one", "two", "few", "many", "other". The actual selection + * is done by `Intl.PluralRules`, which tells us all plurals the locale has + * and which plural we should use for `count`. + */ selectMessage: (count: number, pluralMessages: string) => string; } { const localePluralForm = useLocalePluralForms(); diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index a27451eacce7..8d301370883f 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -127,6 +127,9 @@ export type ThemeConfig = { // User-provided theme config, unnormalized export type UserThemeConfig = DeepPartial<ThemeConfig>; +/** + * A convenient/more semantic way to get theme config from context. + */ export function useThemeConfig(): ThemeConfig { return useDocusaurusContext().siteConfig.themeConfig as ThemeConfig; } From 4b3f568b7865bf6c80e3ee96a021d072b27f6e60 Mon Sep 17 00:00:00 2001 From: Felipe Santos <felipecassiors@gmail.com> Date: Wed, 23 Mar 2022 12:35:26 -0300 Subject: [PATCH 049/405] fix(content-docs): suppress git error on multiple occurrences (#6973) --- .eslintrc.js | 8 ++- jest.config.mjs | 2 + jest/utils/git.ts | 63 +++++++++++++++++++ .../src/__tests__/lastUpdate.test.ts | 23 ++++++- .../src/lastUpdate.ts | 23 +++---- .../src/__tests__/gitUtils.test.ts | 50 ++------------- 6 files changed, 112 insertions(+), 57 deletions(-) create mode 100644 jest/utils/git.ts diff --git a/.eslintrc.js b/.eslintrc.js index d31aec2e0a19..04e9657ae9fb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -202,7 +202,13 @@ module.exports = { 'import/no-unresolved': [ ERROR, { - ignore: ['^@theme', '^@docusaurus', '^@generated', '^@site'], + ignore: [ + '^@theme', + '^@docusaurus', + '^@generated', + '^@site', + '^@testing-utils', + ], }, ], 'import/order': OFF, diff --git a/jest.config.mjs b/jest.config.mjs index 6a012fdadb5c..7163875c4149 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -60,6 +60,8 @@ export default { // Using src instead of lib, so we always get fresh source '@docusaurus/plugin-content-docs/client': '@docusaurus/plugin-content-docs/src/client/index.ts', + + '@testing-utils/(.*)': '<rootDir>/jest/utils/$1.ts', }, snapshotSerializers: [ '<rootDir>/jest/snapshotPathNormalizer.ts', diff --git a/jest/utils/git.ts b/jest/utils/git.ts new file mode 100644 index 000000000000..38db021dccc9 --- /dev/null +++ b/jest/utils/git.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs-extra'; +import os from 'os'; +import path from 'path'; +import shell from 'shelljs'; + +class Git { + constructor(private dir: string) { + const res = shell.exec('git init', {cwd: dir, silent: true}); + if (res.code !== 0) { + throw new Error(`git init exited with code ${res.code}. +stderr: ${res.stderr} +stdout: ${res.stdout}`); + } + // Doesn't matter currently + shell.exec('git config user.email "test@jc-verse.com"', { + cwd: dir, + silent: true, + }); + shell.exec('git config user.name "Test"', {cwd: dir, silent: true}); + + shell.exec('git commit --allow-empty -m "First commit"', { + cwd: dir, + silent: true, + }); + } + commit(msg: string, date: string, author: string): void { + const addRes = shell.exec('git add .', {cwd: this.dir, silent: true}); + const commitRes = shell.exec( + `git commit -m "${msg}" --date "${date}T00:00:00Z" --author "${author}"`, + { + cwd: this.dir, + env: {GIT_COMMITTER_DATE: `${date}T00:00:00Z`}, + silent: true, + }, + ); + if (addRes.code !== 0) { + throw new Error(`git add exited with code ${addRes.code}. +stderr: ${addRes.stderr} +stdout: ${addRes.stdout}`); + } + if (commitRes.code !== 0) { + throw new Error(`git commit exited with code ${commitRes.code}. +stderr: ${commitRes.stderr} +stdout: ${commitRes.stdout}`); + } + } +} + +// This function is sync so the same mock repo can be shared across tests +export function createTempRepo(): {repoDir: string; git: Git} { + const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-test-repo')); + + const git = new Git(repoDir); + + return {repoDir, git}; +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts index 17cfaba48e9f..7f3e41bd195c 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {createTempRepo} from '@testing-utils/git'; import {jest} from '@jest/globals'; import fs from 'fs-extra'; import path from 'path'; @@ -69,7 +70,8 @@ describe('getFileLastUpdate', () => { const consoleMock = jest .spyOn(console, 'warn') .mockImplementation(() => {}); - const tempFilePath = path.join(__dirname, '__fixtures__', '.temp'); + const {repoDir} = createTempRepo(); + const tempFilePath = path.join(repoDir, 'file.md'); await fs.writeFile(tempFilePath, 'Lorem ipsum :)'); await expect(getFileLastUpdate(tempFilePath)).resolves.toBeNull(); expect(consoleMock).toHaveBeenCalledTimes(1); @@ -79,6 +81,25 @@ describe('getFileLastUpdate', () => { await fs.unlink(tempFilePath); }); + it('multiple files not tracked by git', async () => { + const consoleMock = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}); + const {repoDir} = createTempRepo(); + const tempFilePath1 = path.join(repoDir, 'file1.md'); + const tempFilePath2 = path.join(repoDir, 'file2.md'); + await fs.writeFile(tempFilePath1, 'Lorem ipsum :)'); + await fs.writeFile(tempFilePath2, 'Lorem ipsum :)'); + await expect(getFileLastUpdate(tempFilePath1)).resolves.toBeNull(); + await expect(getFileLastUpdate(tempFilePath2)).resolves.toBeNull(); + expect(consoleMock).toHaveBeenCalledTimes(1); + expect(consoleMock).toHaveBeenLastCalledWith( + expect.stringMatching(/not tracked by git./), + ); + await fs.unlink(tempFilePath1); + await fs.unlink(tempFilePath2); + }); + it('git does not exist', async () => { const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null); const consoleMock = jest diff --git a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts index c77ccae4efed..a0eb4d775997 100644 --- a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts +++ b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts @@ -31,17 +31,18 @@ export async function getFileLastUpdate( }); return {timestamp: result.timestamp, author: result.author}; } catch (err) { - if (err instanceof GitNotFoundError && !showedGitRequirementError) { - logger.warn('Sorry, the docs plugin last update options require Git.'); - showedGitRequirementError = true; - } else if ( - err instanceof FileNotTrackedError && - !showedFileNotTrackedError - ) { - logger.warn( - 'Cannot infer the update date for some files, as they are not tracked by git.', - ); - showedFileNotTrackedError = true; + if (err instanceof GitNotFoundError) { + if (!showedGitRequirementError) { + logger.warn('Sorry, the docs plugin last update options require Git.'); + showedGitRequirementError = true; + } + } else if (err instanceof FileNotTrackedError) { + if (!showedFileNotTrackedError) { + logger.warn( + 'Cannot infer the update date for some files, as they are not tracked by git.', + ); + showedFileNotTrackedError = true; + } } else { logger.warn(err); } diff --git a/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts index 64bbf62a4824..1d4519536cc4 100644 --- a/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/gitUtils.test.ts @@ -8,51 +8,12 @@ import {FileNotTrackedError, getFileCommitDate} from '../gitUtils'; import fs from 'fs-extra'; import path from 'path'; -import os from 'os'; -import shell from 'shelljs'; +import {createTempRepo} from '@testing-utils/git'; -// This function is sync so the same mock repo can be shared across tests /* eslint-disable no-restricted-properties */ -function createTempRepo() { - const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'git-test-repo')); - class Git { - constructor(private dir: string) { - const res = shell.exec('git init', {cwd: dir, silent: true}); - if (res.code !== 0) { - throw new Error(`git init exited with code ${res.code}. -stderr: ${res.stderr} -stdout: ${res.stdout}`); - } - // Doesn't matter currently - shell.exec('git config user.email "test@jc-verse.com"', { - cwd: dir, - silent: true, - }); - shell.exec('git config user.name "Test"', {cwd: dir, silent: true}); - } - commit(msg: string, date: string, author: string) { - const addRes = shell.exec('git add .', {cwd: this.dir, silent: true}); - const commitRes = shell.exec( - `git commit -m "${msg}" --date "${date}T00:00:00Z" --author "${author}"`, - { - cwd: this.dir, - env: {GIT_COMMITTER_DATE: `${date}T00:00:00Z`}, - silent: true, - }, - ); - if (addRes.code !== 0) { - throw new Error(`git add exited with code ${addRes.code}. -stderr: ${addRes.stderr} -stdout: ${addRes.stdout}`); - } - if (commitRes.code !== 0) { - throw new Error(`git commit exited with code ${commitRes.code}. -stderr: ${commitRes.stderr} -stdout: ${commitRes.stdout}`); - } - } - } - const git = new Git(repoDir); +function initializeTempRepo() { + const {repoDir, git} = createTempRepo(); + fs.writeFileSync(path.join(repoDir, 'test.txt'), 'Some content'); git.commit( 'Create test.txt', @@ -79,11 +40,12 @@ stdout: ${commitRes.stdout}`); 'Josh-Cena <josh-cena@jc-verse.com>', ); fs.writeFileSync(path.join(repoDir, 'untracked.txt'), "I'm untracked"); + return repoDir; } describe('getFileCommitDate', () => { - const repoDir = createTempRepo(); + const repoDir = initializeTempRepo(); it('returns earliest commit date', async () => { expect(getFileCommitDate(path.join(repoDir, 'test.txt'), {})).toEqual({ date: new Date('2020-06-19'), From 4d2ab826b8f5ebfc4f52c6bda86d0483facaefec Mon Sep 17 00:00:00 2001 From: Alois Klink <alois@aloisklink.com> Date: Thu, 24 Mar 2022 01:19:06 +0000 Subject: [PATCH 050/405] fix(validation): allow non-object params to remark/rehype plugins (#6977) Remark and Rehype plugins allow having options as a non-object type, such as a string. For instance, the official MDX docs even have an example of this: See https://mdxjs.com/docs/extending-mdx/#using-plugins The official plugin `remarkjs/remark-frontmatter` allows passing a string, e.g. `"toml"` as the options arg, instead of an object. --- .../__tests__/__snapshots__/validationSchemas.test.ts.snap | 4 ---- .../src/__tests__/validationSchemas.test.ts | 5 ++++- .../docusaurus-utils-validation/src/validationSchemas.ts | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index e4882b22b35c..56a45cbbc2aa 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -32,8 +32,6 @@ exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\ exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas rehypePluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; @@ -50,8 +48,6 @@ exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\ exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; -exports[`validation schemas remarkPluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts index 6f6f28f31536..534ac218fd94 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts @@ -46,6 +46,10 @@ function testMarkdownPluginSchemas(schema: Joi.Schema) { testOK([() => {}]); testOK([[() => {}, {attr: 'val'}]]); testOK([[() => {}, {attr: 'val'}], () => {}, [() => {}, {attr: 'val'}]]); + // cSpell:ignore remarkjs + // official `remarkjs/remark-frontmatter` plugin accepts string options + testOK([[() => {}, 'string-option']]); + testOK([[() => {}, true]]); testFail(null); testFail(false); @@ -55,7 +59,6 @@ function testMarkdownPluginSchemas(schema: Joi.Schema) { testFail([3]); testFail([[]]); testFail([[() => {}, undefined]]); - testFail([[() => {}, true]]); } describe('validation schemas', () => { diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index d7b23b7cc895..bf2bf6826fa1 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -19,7 +19,7 @@ export const PluginIdSchema = Joi.string() const MarkdownPluginsSchema = Joi.array() .items( - Joi.array().ordered(Joi.function().required(), Joi.object().required()), + Joi.array().ordered(Joi.function().required(), Joi.any().required()), Joi.function(), Joi.object(), ) From 19d2a18817b4906d02ff6ce862f7ec0c97638691 Mon Sep 17 00:00:00 2001 From: Jadon N <30273534+jadonn@users.noreply.github.com> Date: Wed, 23 Mar 2022 23:14:09 -0400 Subject: [PATCH 051/405] docs: npm run tsc -> npx tsc (#6978) * Correct npm run tsc to npm run typecheck According to this page, you should run `npm run tsc` to run `tsc` and do a type check. However, in the package.json file for Docusaurus version 2.0.0-beta.17 the command is actually `npm run typecheck`, which runs `tsc`. This update only replaces `tsc` with `typecheck` so the npm script will run correctly. * Recommend npx tsc for type-checking Based on feedback for the original change to replace `npm run tsc` with `npm run typecheck`, a better solution that was suggested was to use npx to run tsc instead of an npm script. `npx tsc` should work regardless of the template/presets you installed when you installed Docusaurus. --- website/docs/typescript-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/typescript-support.md b/website/docs/typescript-support.md index 3f9e09716855..13f6ad57158e 100644 --- a/website/docs/typescript-support.md +++ b/website/docs/typescript-support.md @@ -115,7 +115,7 @@ By default, the Docusaurus TypeScript config does not type-check JavaScript file The `// @ts-check` comment ensures the config file is properly type-checked when running: ```bash npm2yarn -npm run tsc +npx tsc ``` ::: From b8d2a4e84dc9a01395885dcd12f5837317081e5c Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Thu, 24 Mar 2022 12:47:56 +0300 Subject: [PATCH 052/405] refactor: replace text-based copy code button with icons (#6964) --- .../src/theme-classic.d.ts | 8 +++ .../src/theme/CodeBlock/CopyButton/index.tsx | 65 ++++++++++++++++++ .../CodeBlock/CopyButton/styles.module.css | 66 +++++++++++++++++++ .../src/theme/CodeBlock/index.tsx | 42 ++---------- .../src/theme/CodeBlock/styles.module.css | 20 +----- 5 files changed, 146 insertions(+), 55 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index dffa79e8d3e8..9dfa6b17f68e 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -126,6 +126,14 @@ declare module '@theme/CodeBlock' { export default function CodeBlock(props: Props): JSX.Element; } +declare module '@theme/CodeBlock/CopyButton' { + export interface Props { + readonly code: string; + } + + export default function CopyButton(props: Props): JSX.Element; +} + declare module '@theme/DocCard' { import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx new file mode 100644 index 000000000000..4a02ec1306a8 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx @@ -0,0 +1,65 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {useState} from 'react'; +import clsx from 'clsx'; +import copy from 'copy-text-to-clipboard'; +import {translate} from '@docusaurus/Translate'; +import type {Props} from '@theme/CodeBlock/CopyButton'; + +import styles from './styles.module.css'; + +export default function CopyButton({code}: Props): JSX.Element { + const [isCopied, setIsCopied] = useState(false); + const handleCopyCode = () => { + copy(code); + setIsCopied(true); + + setTimeout(() => { + setIsCopied(false); + }, 2000); + }; + + return ( + <button + type="button" + aria-label={ + isCopied + ? translate({ + id: 'theme.CodeBlock.copied', + message: 'Copied', + description: 'The copied button label on code blocks', + }) + : translate({ + id: 'theme.CodeBlock.copyButtonAriaLabel', + message: 'Copy code to clipboard', + description: 'The ARIA label for copy code blocks button', + }) + } + // @todo: check it again later + title={translate({ + id: 'theme.CodeBlock.copy', + message: 'Copy', + description: 'The copy button label on code blocks', + })} + className={clsx( + styles.copyButton, + 'clean-btn', + isCopied && styles.copyButtonCopied, + )} + onClick={handleCopyCode}> + <span className={styles.copyButtonIcons} aria-hidden="true"> + <svg className={styles.copyButtonIcon} viewBox="0 0 24 24"> + <path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" /> + </svg> + <svg className={styles.copyButtonSuccessIcon} viewBox="0 0 24 24"> + <path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" /> + </svg> + </span> + </button> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css new file mode 100644 index 000000000000..f91a3d6aacfd --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css @@ -0,0 +1,66 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.copyButton { + display: flex; + background: inherit; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + padding: 0.4rem; + position: absolute; + right: calc(var(--ifm-pre-padding) / 2); + top: calc(var(--ifm-pre-padding) / 2); + transition: opacity 200ms ease-in-out; + opacity: 0; +} + +.copyButton:focus-visible, +.copyButton:hover, +:global(.theme-code-block:hover) .copyButtonCopied { + opacity: 1 !important; +} + +:global(.theme-code-block:hover) .copyButton:not(.copyButtonCopied) { + opacity: 0.4; +} + +.copyButtonIcons { + position: relative; + width: 1.125rem; + height: 1.125rem; +} + +.copyButtonIcon, +.copyButtonSuccessIcon { + position: absolute; + top: 0; + left: 0; + fill: currentColor; + opacity: inherit; + width: inherit; + height: inherit; + transition: all 0.15s ease; +} + +.copyButtonSuccessIcon { + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.33); + opacity: 0; + color: #00d600; +} + +.copyButtonCopied .copyButtonIcon { + transform: scale(0.33); + opacity: 0; +} + +.copyButtonCopied .copyButtonSuccessIcon { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + transition-delay: 0.075s; +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index 994f325f4c93..943d3f84676e 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -8,8 +8,6 @@ import React, {isValidElement, useEffect, useState} from 'react'; import clsx from 'clsx'; import Highlight, {defaultProps, type Language} from 'prism-react-renderer'; -import copy from 'copy-text-to-clipboard'; -import Translate, {translate} from '@docusaurus/Translate'; import { useThemeConfig, parseCodeBlockTitle, @@ -18,6 +16,7 @@ import { ThemeClassNames, usePrismTheme, } from '@docusaurus/theme-common'; +import CopyButton from '@theme/CodeBlock/CopyButton'; import type {Props} from '@theme/CodeBlock'; import styles from './styles.module.css'; @@ -31,7 +30,6 @@ export default function CodeBlock({ }: Props): JSX.Element { const {prism} = useThemeConfig(); - const [showCopied, setShowCopied] = useState(false); const [mounted, setMounted] = useState(false); // The Prism theme on SSR is always the default theme but the site theme // can be in a different mode. React hydration doesn't update DOM styles @@ -90,13 +88,6 @@ export default function CodeBlock({ languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage; const {highlightLines, code} = parseLines(content, metastring, language); - const handleCopyCode = () => { - copy(code); - setShowCopied(true); - - setTimeout(() => setShowCopied(false), 2000); - }; - return ( <Highlight {...defaultProps} @@ -120,12 +111,13 @@ export default function CodeBlock({ {codeBlockTitle} </div> )} - <div className={clsx(styles.codeBlockContent, language)}> + <div + className={clsx(styles.codeBlockContent, language)} + style={style}> <pre /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */ tabIndex={0} - className={clsx(className, styles.codeBlock, 'thin-scrollbar')} - style={style}> + className={clsx(className, styles.codeBlock, 'thin-scrollbar')}> <code className={styles.codeBlockLines}> {tokens.map((line, i) => { if (line.length === 1 && line[0]!.content === '\n') { @@ -150,29 +142,7 @@ export default function CodeBlock({ </code> </pre> - <button - type="button" - aria-label={translate({ - id: 'theme.CodeBlock.copyButtonAriaLabel', - message: 'Copy code to clipboard', - description: 'The ARIA label for copy code blocks button', - })} - className={clsx(styles.copyButton, 'clean-btn')} - onClick={handleCopyCode}> - {showCopied ? ( - <Translate - id="theme.CodeBlock.copied" - description="The copied button label on code blocks"> - Copied - </Translate> - ) : ( - <Translate - id="theme.CodeBlock.copy" - description="The copy button label on code blocks"> - Copy - </Translate> - )} - </button> + <CopyButton code={code} /> </div> </div> )} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index a1bd413658d8..fcdcca6b1c09 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -30,6 +30,7 @@ margin: 0; padding: 0; border-radius: var(--ifm-global-radius); + background-color: inherit; } .codeBlockTitle + .codeBlockContent .codeBlock { @@ -42,25 +43,6 @@ border-radius: var(--ifm-global-radius); } -.copyButton { - background: rgb(0 0 0 / 30%); - border-radius: var(--ifm-global-radius); - color: var(--ifm-color-white); - opacity: 0; - user-select: none; - padding: 0.4rem 0.5rem; - position: absolute; - right: calc(var(--ifm-pre-padding) / 2); - top: calc(var(--ifm-pre-padding) / 2); - transition: opacity 200ms ease-in-out; -} - -.copyButton:focus, -.codeBlockContent:hover > .copyButton, -.codeBlockTitle:hover + .codeBlockContent .copyButton { - opacity: 1; -} - .codeBlockLines { font: inherit; /* rtl:ignore */ From 2eeb0e46a2e037a885a30c653d73dd1a3e921c94 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 24 Mar 2022 21:34:31 +0800 Subject: [PATCH 053/405] feat(utils): JSDoc for all APIs (#6980) * feat(utils): JSDoc for all APIs * fix tests --- .../src/types.ts | 5 +- .../src/markdown/__tests__/linkify.test.ts | 10 +- .../src/sidebars/utils.ts | 22 ++-- .../src/types.ts | 11 +- .../src/theme-classic.d.ts | 3 +- .../docusaurus-utils-validation/package.json | 1 + .../src/JoiFrontMatter.ts | 4 +- .../src/validationUtils.ts | 22 +++- .../src/__tests__/globUtils.test.ts | 2 +- .../src/__tests__/jsUtils.test.ts | 35 ----- .../src/__tests__/markdownUtils.test.ts | 20 ++- .../src/__tests__/tags.test.ts | 46 ++++--- packages/docusaurus-utils/src/constants.ts | 66 +++++++++- .../docusaurus-utils/src/dataFileUtils.ts | 53 ++++++-- packages/docusaurus-utils/src/emitUtils.ts | 29 +++- packages/docusaurus-utils/src/gitUtils.ts | 50 ++++++- packages/docusaurus-utils/src/globUtils.ts | 42 ++++-- packages/docusaurus-utils/src/hashUtils.ts | 11 +- packages/docusaurus-utils/src/i18nUtils.ts | 17 ++- packages/docusaurus-utils/src/index.ts | 9 +- packages/docusaurus-utils/src/jsUtils.ts | 54 +++++--- .../docusaurus-utils/src/markdownLinks.ts | 80 +++++++---- .../docusaurus-utils/src/markdownUtils.ts | 124 ++++++++++++++---- packages/docusaurus-utils/src/pathUtils.ts | 4 +- packages/docusaurus-utils/src/slugger.ts | 14 +- packages/docusaurus-utils/src/tags.ts | 62 +++++---- packages/docusaurus-utils/src/urlUtils.ts | 55 +++++++- packages/docusaurus-utils/src/webpackUtils.ts | 12 +- .../docusaurus/src/server/configValidation.ts | 7 +- .../src/server/translations/translations.ts | 14 +- project-words.txt | 4 + 31 files changed, 635 insertions(+), 253 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index 451f571d9342..a83cc76abfab 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -5,10 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type { - BrokenMarkdownLink, - ContentPaths, -} from '@docusaurus/utils/lib/markdownLinks'; +import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils'; import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog'; import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage'; diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index 2cf56ba9dcc7..c6e5bb9ac52b 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -13,7 +13,7 @@ import type { DocsMarkdownOption, SourceToPermalink, VersionMetadata, - BrokenMarkdownLink, + DocBrokenMarkdownLink, } from '../../types'; import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants'; @@ -156,22 +156,22 @@ describe('linkify', () => { filePath: doc5, link: 'docNotExist1.md', contentPaths: versionCurrent, - } as BrokenMarkdownLink); + } as DocBrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(2, { filePath: doc5, link: './docNotExist2.mdx', contentPaths: versionCurrent, - } as BrokenMarkdownLink); + } as DocBrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(3, { filePath: doc5, link: '../docNotExist3.mdx', contentPaths: versionCurrent, - } as BrokenMarkdownLink); + } as DocBrokenMarkdownLink); expect(onBrokenMarkdownLink).toHaveBeenNthCalledWith(4, { filePath: doc5, link: './subdir/docNotExist4.md', contentPaths: versionCurrent, - } as BrokenMarkdownLink); + } as DocBrokenMarkdownLink); }); it('transforms absolute links in versioned docs', async () => { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index ee5de8bb582e..6f8875f985e0 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -20,7 +20,7 @@ import type { } from './types'; import _ from 'lodash'; -import {getElementsAround, toMessageRelativeFilePath} from '@docusaurus/utils'; +import {toMessageRelativeFilePath} from '@docusaurus/utils'; import type {DocMetadataBase, DocNavLink} from '../types'; export function isCategoriesShorthand( @@ -225,11 +225,11 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { return {sidebarName, next: undefined, previous: undefined}; } - const {previous, next} = getElementsAround( - navigationItems, - currentItemIndex, - ); - return {sidebarName, previous, next}; + return { + sidebarName, + previous: navigationItems[currentItemIndex - 1], + next: navigationItems[currentItemIndex + 1], + }; } function getCategoryGeneratedIndexList(): SidebarItemCategoryWithGeneratedIndex[] { @@ -268,11 +268,11 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { const currentItemIndex = navigationItems.findIndex( isCurrentCategoryGeneratedIndexItem, ); - const {previous, next} = getElementsAround( - navigationItems, - currentItemIndex, - ); - return {sidebarName, previous, next}; + return { + sidebarName, + previous: navigationItems[currentItemIndex - 1], + next: navigationItems[currentItemIndex + 1], + }; } function checkSidebarsDocIds(validDocIds: string[], sidebarFilePath: string) { diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index f48ccb505854..67ba6366b5dd 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -8,11 +8,12 @@ /// <reference types="@docusaurus/module-type-aliases" /> import type {Sidebars} from './sidebars/types'; -import type {Tag, FrontMatterTag} from '@docusaurus/utils'; import type { - BrokenMarkdownLink as IBrokenMarkdownLink, + Tag, + FrontMatterTag, + BrokenMarkdownLink, ContentPaths, -} from '@docusaurus/utils/lib/markdownLinks'; +} from '@docusaurus/utils'; import type {VersionBanner} from '@docusaurus/plugin-content-docs'; export type DocFile = { @@ -133,11 +134,11 @@ export type LoadedContent = { loadedVersions: LoadedVersion[]; }; -export type BrokenMarkdownLink = IBrokenMarkdownLink<VersionMetadata>; +export type DocBrokenMarkdownLink = BrokenMarkdownLink<VersionMetadata>; export type DocsMarkdownOption = { versionsMetadata: VersionMetadata[]; siteDir: string; sourceToPermalink: SourceToPermalink; - onBrokenMarkdownLink: (brokenMarkdownLink: BrokenMarkdownLink) => void; + onBrokenMarkdownLink: (brokenMarkdownLink: DocBrokenMarkdownLink) => void; }; diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 9dfa6b17f68e..a508a0c4d03d 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -898,7 +898,8 @@ declare module '@theme/TagsListByLetter' { } declare module '@theme/TagsListInline' { - export type Tag = Readonly<{label: string; permalink: string}>; + import type {Tag} from '@docusaurus/utils'; + export interface Props { readonly tags: readonly Tag[]; } diff --git a/packages/docusaurus-utils-validation/package.json b/packages/docusaurus-utils-validation/package.json index a5b187ed83cf..1cd8f64b0561 100644 --- a/packages/docusaurus-utils-validation/package.json +++ b/packages/docusaurus-utils-validation/package.json @@ -20,6 +20,7 @@ "dependencies": { "@docusaurus/logger": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", + "js-yaml": "^4.1.0", "joi": "^17.6.0", "tslib": "^2.3.1" }, diff --git a/packages/docusaurus-utils-validation/src/JoiFrontMatter.ts b/packages/docusaurus-utils-validation/src/JoiFrontMatter.ts index 0205e9fdbe5a..011bccd8796c 100644 --- a/packages/docusaurus-utils-validation/src/JoiFrontMatter.ts +++ b/packages/docusaurus-utils-validation/src/JoiFrontMatter.ts @@ -18,11 +18,13 @@ const JoiFrontMatterString: Joi.Extension = { return {value}; }, }; + /** - * Enhance the default Joi.string() type so that it can convert number to + * Enhance the default `Joi.string()` type so that it can convert number to * strings. If user use front matter "tag: 2021", we shouldn't need to ask her * to write "tag: '2021'". Also yaml tries to convert patterns like "2019-01-01" * to dates automatically. + * * @see https://github.com/facebook/docusaurus/issues/4642 * @see https://github.com/sideway/joi/issues/1442#issuecomment-823997884 */ diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index aae84333b98b..fed60afc8e22 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -7,8 +7,10 @@ import type Joi from './Joi'; import logger from '@docusaurus/logger'; +import Yaml from 'js-yaml'; import {PluginIdSchema} from './validationSchemas'; +/** Print warnings returned from Joi validation. */ export function printWarning(warning?: Joi.ValidationError): void { if (warning) { const warningMessages = warning.details @@ -18,9 +20,14 @@ export function printWarning(warning?: Joi.ValidationError): void { } } +/** + * The callback that should be used to validate plugin options. Handles plugin + * IDs on a generic level: no matter what the schema declares, this callback + * would require a string ID or default to "default". + */ export function normalizePluginOptions<T extends {id?: string}>( schema: Joi.ObjectSchema<T>, - // This allows us to automatically normalize undefined to {id: 'default'} + // This allows us to automatically normalize undefined to { id: "default" } options: Partial<T> = {}, ): T { // All plugins can be provided an "id" option (multi-instance support) @@ -41,6 +48,10 @@ export function normalizePluginOptions<T extends {id?: string}>( return value; } +/** + * The callback that should be used to validate theme config. No matter what the + * schema declares, this callback would allow unknown attributes. + */ export function normalizeThemeConfig<T>( schema: Joi.ObjectSchema<T>, themeConfig: Partial<T>, @@ -62,6 +73,9 @@ export function normalizeThemeConfig<T>( return value; } +/** + * Validate front matter with better error message + */ export function validateFrontMatter<T>( frontMatter: Record<string, unknown>, schema: Joi.ObjectSchema<T>, @@ -75,13 +89,13 @@ export function validateFrontMatter<T>( printWarning(warning); if (error) { - const frontMatterString = JSON.stringify(frontMatter, null, 2); const errorDetails = error.details; const invalidFields = errorDetails.map(({path}) => path).join(', '); logger.error`The following front matter: -${logger.yellow(frontMatterString)} -contains invalid values for field(s): ${logger.yellow(invalidFields)}. +--- +${Yaml.dump(frontMatter)}--- +contains invalid values for field(s): code=${invalidFields}. ${errorDetails.map(({message}) => message)} `; throw error; diff --git a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts index e1794e972913..e2f3d52f2c1f 100644 --- a/packages/docusaurus-utils/src/__tests__/globUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/globUtils.test.ts @@ -103,7 +103,7 @@ describe('createAbsoluteFilePathMatcher', () => { expect(() => matcher('/bad/path/myDoc.md'), ).toThrowErrorMatchingInlineSnapshot( - `"createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=/bad/path/myDoc.md was not contained in any of the root folders [\\"/_root/docs\\",\\"/root/_docs/\\",\\"/__test__/website/src\\"]"`, + `"createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=/bad/path/myDoc.md was not contained in any of the root folders: /_root/docs, /root/_docs/, /__test__/website/src"`, ); }); }); diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index 6e7e4c99e349..b196e2a45b10 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -9,7 +9,6 @@ import {jest} from '@jest/globals'; import { removeSuffix, removePrefix, - getElementsAround, mapAsyncSequential, findAsyncSequential, reportMessage, @@ -38,40 +37,6 @@ describe('removePrefix', () => { }); }); -describe('getElementsAround', () => { - it('returns elements around', () => { - expect(getElementsAround(['a', 'b', 'c', 'd'], 0)).toEqual({ - previous: undefined, - next: 'b', - }); - expect(getElementsAround(['a', 'b', 'c', 'd'], 1)).toEqual({ - previous: 'a', - next: 'c', - }); - expect(getElementsAround(['a', 'b', 'c', 'd'], 2)).toEqual({ - previous: 'b', - next: 'd', - }); - expect(getElementsAround(['a', 'b', 'c', 'd'], 3)).toEqual({ - previous: 'c', - next: undefined, - }); - }); - - it('throws if bad index is provided', () => { - expect(() => - getElementsAround(['a', 'b', 'c', 'd'], -1), - ).toThrowErrorMatchingInlineSnapshot( - `"Valid \\"aroundIndex\\" for array (of size 4) are between 0 and 3, but you provided -1."`, - ); - expect(() => - getElementsAround(['a', 'b', 'c', 'd'], 4), - ).toThrowErrorMatchingInlineSnapshot( - `"Valid \\"aroundIndex\\" for array (of size 4) are between 0 and 3, but you provided 4."`, - ); - }); -}); - describe('mapAsyncSequential', () => { function sleep(timeout: number): Promise<void> { return new Promise((resolve) => { diff --git a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts index ae1edf89be08..f0a7ca3201c0 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts @@ -113,9 +113,13 @@ describe('createExcerpt', () => { import Component from '@site/src/components/Component' import './styles.css'; - export function ItemCol(props) { return <Item {...props} className={'col col--6 margin-bottom--lg'}/> } + export function ItemCol(props) { + return <Item {...props} className={'col col--6 margin-bottom--lg'}/> + } - export function ItemCol(props) { return <Item {...props} className={'col col--6 margin-bottom--lg'}/> }; + export function ItemCol(props) { + return <Item {...props} className={'col col--6 margin-bottom--lg'}/> + }; Lorem **ipsum** dolor sit \`amet\`[^1], consectetur _adipiscing_ elit. [**Vestibulum**](https://wiktionary.org/wiki/vestibulum) ex urna[^note], ~~molestie~~ et sagittis ut, varius ac justo :wink:. @@ -146,6 +150,18 @@ describe('createExcerpt', () => { `), ).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); }); + + it('creates excerpt after multi-line imports', () => { + expect( + createExcerpt(dedent` + import React, { + type ReactNode, + } from 'react'; + + Lorem \`ipsum\` dolor sit amet, consectetur \`adipiscing elit\`. + `), + ).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'); + }); }); describe('parseMarkdownContentTitle', () => { diff --git a/packages/docusaurus-utils/src/__tests__/tags.test.ts b/packages/docusaurus-utils/src/__tests__/tags.test.ts index 743b75068225..a78053b5d76b 100644 --- a/packages/docusaurus-utils/src/__tests__/tags.test.ts +++ b/packages/docusaurus-utils/src/__tests__/tags.test.ts @@ -5,62 +5,60 @@ * LICENSE file in the root directory of this source tree. */ -import { - normalizeFrontMatterTag, - normalizeFrontMatterTags, - groupTaggedItems, - type Tag, -} from '../tags'; - -describe('normalizeFrontMatterTag', () => { - type Input = Parameters<typeof normalizeFrontMatterTag>[1]; - type Output = ReturnType<typeof normalizeFrontMatterTag>; +import {normalizeFrontMatterTags, groupTaggedItems, type Tag} from '../tags'; +describe('normalizeFrontMatterTags', () => { it('normalizes simple string tag', () => { const tagsPath = '/all/tags'; - const input: Input = 'tag'; - const expectedOutput: Output = { + const input = 'tag'; + const expectedOutput = { label: 'tag', permalink: `${tagsPath}/tag`, }; - expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); + expect(normalizeFrontMatterTags(tagsPath, [input])).toEqual([ + expectedOutput, + ]); }); it('normalizes complex string tag', () => { const tagsPath = '/all/tags'; - const input: Input = 'some more Complex_tag'; - const expectedOutput: Output = { + const input = 'some more Complex_tag'; + const expectedOutput = { label: 'some more Complex_tag', permalink: `${tagsPath}/some-more-complex-tag`, }; - expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); + expect(normalizeFrontMatterTags(tagsPath, [input])).toEqual([ + expectedOutput, + ]); }); it('normalizes simple object tag', () => { const tagsPath = '/all/tags'; - const input: Input = {label: 'tag', permalink: 'tagPermalink'}; - const expectedOutput: Output = { + const input = {label: 'tag', permalink: 'tagPermalink'}; + const expectedOutput = { label: 'tag', permalink: `${tagsPath}/tagPermalink`, }; - expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); + expect(normalizeFrontMatterTags(tagsPath, [input])).toEqual([ + expectedOutput, + ]); }); it('normalizes complex string tag with object tag', () => { const tagsPath = '/all/tags'; - const input: Input = { + const input = { label: 'tag complex Label', permalink: '/MoreComplex/Permalink', }; - const expectedOutput: Output = { + const expectedOutput = { label: 'tag complex Label', permalink: `${tagsPath}/MoreComplex/Permalink`, }; - expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput); + expect(normalizeFrontMatterTags(tagsPath, [input])).toEqual([ + expectedOutput, + ]); }); -}); -describe('normalizeFrontMatterTags', () => { type Input = Parameters<typeof normalizeFrontMatterTags>[1]; type Output = ReturnType<typeof normalizeFrontMatterTags>; diff --git a/packages/docusaurus-utils/src/constants.ts b/packages/docusaurus-utils/src/constants.ts index 156038ffe0c0..0b413e6f4182 100644 --- a/packages/docusaurus-utils/src/constants.ts +++ b/packages/docusaurus-utils/src/constants.ts @@ -5,34 +5,86 @@ * LICENSE file in the root directory of this source tree. */ +/** Node major version, directly read from env. */ export const NODE_MAJOR_VERSION = parseInt( process.versions.node.split('.')[0]!, 10, ); +/** Node minor version, directly read from env. */ export const NODE_MINOR_VERSION = parseInt( process.versions.node.split('.')[1]!, 10, ); -// Can be overridden with cli option --out-dir +/** + * Can be overridden with cli option `--out-dir`. Code should generally use + * `context.outDir` instead (which is always absolute and localized). + */ export const DEFAULT_BUILD_DIR_NAME = 'build'; -// Can be overridden with cli option --config +/** + * Can be overridden with cli option `--config`. Code should generally use + * `context.siteConfigPath` instead (which is always absolute). + */ export const DEFAULT_CONFIG_FILE_NAME = 'docusaurus.config.js'; +/** Can be absolute or relative to site directory. */ export const BABEL_CONFIG_FILE_NAME = - process.env.DOCUSAURUS_BABEL_CONFIG_FILE_NAME || 'babel.config.js'; + process.env.DOCUSAURUS_BABEL_CONFIG_FILE_NAME ?? 'babel.config.js'; +/** + * Can be absolute or relative to site directory. Code should generally use + * `context.generatedFilesDir` instead (which is always absolute). + */ export const GENERATED_FILES_DIR_NAME = - process.env.DOCUSAURUS_GENERATED_FILES_DIR_NAME || '.docusaurus'; + process.env.DOCUSAURUS_GENERATED_FILES_DIR_NAME ?? '.docusaurus'; +/** + * We would assume all of the site's JS code lives in here and not outside. + * Relative to the site directory. + */ export const SRC_DIR_NAME = 'src'; -export const STATIC_DIR_NAME = 'static'; -export const OUTPUT_STATIC_ASSETS_DIR_NAME = 'assets'; // files handled by webpack, hashed (can be cached aggressively) + +/** + * Can be overridden with `config.staticDirectories`. Code should use + * `context.siteConfig.staticDirectories` instead (which is always absolute). + */ +export const DEFAULT_STATIC_DIR_NAME = 'static'; + +/** + * Files here are handled by webpack, hashed (can be cached aggressively). + * Relative to the build output folder. + */ +export const OUTPUT_STATIC_ASSETS_DIR_NAME = 'assets'; + +/** + * Components in this directory will receive the `@theme` alias and be able to + * shadow default theme components. + */ export const THEME_PATH = `${SRC_DIR_NAME}/theme`; + +/** + * All translation-related data live here, relative to site directory. Content + * will be namespaced by locale. + */ +export const I18N_DIR_NAME = 'i18n'; + +/** + * Translations for React code. + */ +export const CODE_TRANSLATIONS_FILE_NAME = 'code.json'; + +/** Dev server opens on this port by default. */ export const DEFAULT_PORT = 3000; + +/** Default plugin ID. */ export const DEFAULT_PLUGIN_ID = 'default'; -// Temporary fix for https://github.com/facebook/docusaurus/issues/5493 +/** + * Allow overriding the limit after which the url loader will no longer inline + * assets. + * + * @see https://github.com/facebook/docusaurus/issues/5493 + */ export const WEBPACK_URL_LOADER_LIMIT = process.env.WEBPACK_URL_LOADER_LIMIT ?? 10000; diff --git a/packages/docusaurus-utils/src/dataFileUtils.ts b/packages/docusaurus-utils/src/dataFileUtils.ts index b71693d06eca..58fc8151165e 100644 --- a/packages/docusaurus-utils/src/dataFileUtils.ts +++ b/packages/docusaurus-utils/src/dataFileUtils.ts @@ -13,15 +13,25 @@ import type {ContentPaths} from './markdownLinks'; import logger from '@docusaurus/logger'; type DataFileParams = { + /** Path to the potential data file, relative to `contentPaths` */ filePath: string; + /** + * Includes the base path and localized path, both of which are eligible for + * sourcing data files. Both paths should be absolute. + */ contentPaths: ContentPaths; }; +/** + * Looks for a data file in the potential content paths; loads a localized data + * file in priority. + * + * @returns An absolute path to the data file, or `undefined` if there isn't one. + */ export async function getDataFilePath({ filePath, contentPaths, }: DataFileParams): Promise<string | undefined> { - // Loads a localized data file in priority const contentPath = await findFolderContainingFile( getContentPathList(contentPaths), filePath, @@ -33,11 +43,17 @@ export async function getDataFilePath({ } /** - * Looks up for a data file in the content paths, returns the normalized object. - * Throws when validation fails; returns undefined when file not found + * Looks up for a data file in the content paths, returns the object validated + * and normalized according to the `validate` callback. + * + * @returns `undefined` when file not found + * @throws Throws when validation fails, displaying a helpful context message. */ export async function getDataFileData<T>( - params: DataFileParams & {fileType: string}, + params: DataFileParams & { + /** Used for the "The X file looks invalid" message. */ + fileType: string; + }, validate: (content: unknown) => T, ): Promise<T | undefined> { const filePath = await getDataFilePath(params); @@ -54,12 +70,21 @@ export async function getDataFileData<T>( } } -// Order matters: we look in priority in localized folder +/** + * Takes the `contentPaths` data structure and returns an ordered path list + * indicating their priorities. For all data, we look in the localized folder + * in priority. + */ export function getContentPathList(contentPaths: ContentPaths): string[] { return [contentPaths.contentPathLocalized, contentPaths.contentPath]; } -// return the first folder path in which the file exists in +/** + * @param folderPaths a list of absolute paths. + * @param relativeFilePath file path relative to each `folderPaths`. + * @returns the first folder path in which the file exists, or `undefined` if + * none is found. + */ export async function findFolderContainingFile( folderPaths: string[], relativeFilePath: string, @@ -69,6 +94,16 @@ export async function findFolderContainingFile( ); } +/** + * Fail-fast alternative to `findFolderContainingFile`. + * + * @param folderPaths a list of absolute paths. + * @param relativeFilePath file path relative to each `folderPaths`. + * @returns the first folder path in which the file exists. + * @throws Throws if no file can be found. You should use this method only when + * you actually know the file exists (e.g. when the `relativeFilePath` is read + * with a glob and you are just trying to localize it) + */ export async function getFolderContainingFile( folderPaths: string[], relativeFilePath: string, @@ -77,12 +112,10 @@ export async function getFolderContainingFile( folderPaths, relativeFilePath, ); - // should never happen, as the source was read from the FS anyway... if (!maybeFolderPath) { throw new Error( - `File "${relativeFilePath}" does not exist in any of these folders:\n- ${folderPaths.join( - '\n- ', - )}`, + `File "${relativeFilePath}" does not exist in any of these folders: +- ${folderPaths.join('\n- ')}`, ); } return maybeFolderPath; diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index d532985d6c65..ba4e29de0832 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -13,6 +13,16 @@ import {findAsyncSequential} from './jsUtils'; const fileHash = new Map<string, string>(); +/** + * Outputs a file to the generated files directory. Only writes files if content + * differs from cache (for hot reload performance). + * + * @param generatedFilesDir Absolute path. + * @param file Path relative to `generatedFilesDir`. + * @param content String content to write. + * @param skipCache If `true` (defaults as `true` for production), file is + * force-rewritten, skipping cache. + */ export async function generate( generatedFilesDir: string, file: string, @@ -23,14 +33,21 @@ export async function generate( if (skipCache) { await fs.outputFile(filepath, content); + // Cache still needs to be reset, otherwise, writing "A", "B", and "A" where + // "B" skips cache will cause the last "A" not be able to overwrite as the + // first "A" remains in cache. But if the file never existed in cache, no + // need to register it. + if (fileHash.get(filepath)) { + fileHash.set(filepath, createHash('md5').update(content).digest('hex')); + } return; } let lastHash = fileHash.get(filepath); - // If file already exists but its not in runtime cache yet, - // we try to calculate the content hash and then compare - // This is to avoid unnecessary overwriting and we can reuse old file. + // If file already exists but it's not in runtime cache yet, we try to + // calculate the content hash and then compare. This is to avoid unnecessary + // overwriting and we can reuse old file. if (!lastHash && (await fs.pathExists(filepath))) { const lastContent = await fs.readFile(filepath, 'utf8'); lastHash = createHash('md5').update(lastContent).digest('hex'); @@ -45,7 +62,7 @@ export async function generate( } } -const chunkNameCache = new Map(); +const chunkNameCache = new Map<string, string>(); /** * Generate unique chunk name given a module path. @@ -56,7 +73,7 @@ export function genChunkName( preferredName?: string, shortId: boolean = process.env.NODE_ENV === 'production', ): string { - let chunkName: string | undefined = chunkNameCache.get(modulePath); + let chunkName = chunkNameCache.get(modulePath); if (!chunkName) { if (shortId) { chunkName = simpleHash(modulePath, 8); @@ -82,6 +99,8 @@ export function genChunkName( * @returns This returns a buffer, which you have to decode string yourself if * needed. (Not always necessary since the output isn't for human consumption * anyways, and most HTML manipulation libs accept buffers) + * @throws Throws when the HTML file is not found at any of the potential paths. + * This should never happen as it would lead to a 404. */ export async function readOutputHTMLFile( permalink: string, diff --git a/packages/docusaurus-utils/src/gitUtils.ts b/packages/docusaurus-utils/src/gitUtils.ts index 9902c720b914..e2f155bb3e05 100644 --- a/packages/docusaurus-utils/src/gitUtils.ts +++ b/packages/docusaurus-utils/src/gitUtils.ts @@ -8,23 +8,67 @@ import path from 'path'; import shell from 'shelljs'; +/** Custom error thrown when git is not found in `PATH`. */ export class GitNotFoundError extends Error {} +/** Custom error thrown when the current file is not tracked by git. */ export class FileNotTrackedError extends Error {} +/** + * Fetches the git history of a file and returns a relevant commit date. + * It gets the commit date instead of author date so that amended commits + * can have their dates updated. + * + * @throws {GitNotFoundError} If git is not found in `PATH`. + * @throws {FileNotTrackedError} If the current file is not tracked by git. + * @throws Also throws when `git log` exited with non-zero, or when it outputs + * unexpected text. + */ export function getFileCommitDate( + /** Absolute path to the file. */ file: string, - args: {age?: 'oldest' | 'newest'; includeAuthor?: false}, + args: { + /** + * `"oldest"` is the commit that added the file, following renames; + * `"newest"` is the last commit that edited the file. + */ + age?: 'oldest' | 'newest'; + /** Use `includeAuthor: true` to get the author information as well. */ + includeAuthor?: false; + }, ): { + /** Relevant commit date. */ date: Date; + /** Timestamp in **seconds**, as returned from git. */ timestamp: number; }; +/** + * Fetches the git history of a file and returns a relevant commit date. + * It gets the commit date instead of author date so that amended commits + * can have their dates updated. + * + * @throws {GitNotFoundError} If git is not found in `PATH`. + * @throws {FileNotTrackedError} If the current file is not tracked by git. + * @throws Also throws when `git log` exited with non-zero, or when it outputs + * unexpected text. + */ export function getFileCommitDate( + /** Absolute path to the file. */ file: string, - args: {age?: 'oldest' | 'newest'; includeAuthor: true}, + args: { + /** + * `"oldest"` is the commit that added the file, following renames; + * `"newest"` is the last commit that edited the file. + */ + age?: 'oldest' | 'newest'; + includeAuthor: true; + }, ): { + /** Relevant commit date. */ date: Date; + /** Timestamp in **seconds**, as returned from git. */ timestamp: number; + /** The author's name, as returned from git. */ author: string; }; export function getFileCommitDate( @@ -53,8 +97,6 @@ export function getFileCommitDate( ); } - // Commit time and author name; not using author time so that amended commits - // can have their dates updated let formatArg = '--format=%ct'; if (includeAuthor) { formatArg += ',%an'; diff --git a/packages/docusaurus-utils/src/globUtils.ts b/packages/docusaurus-utils/src/globUtils.ts index fbbf8aa51baf..b70ed4cd53d3 100644 --- a/packages/docusaurus-utils/src/globUtils.ts +++ b/packages/docusaurus-utils/src/globUtils.ts @@ -10,24 +10,31 @@ import Micromatch from 'micromatch'; // Note: Micromatch is used by Globby import path from 'path'; +/** A re-export of the globby instance. */ export {default as Globby} from 'globby'; -// The default patterns we ignore when globbing -// using _ prefix for exclusion by convention +/** + * The default glob patterns we ignore when sourcing content. + * - Ignore files and folders starting with `_` recursively + * - Ignore tests + */ export const GlobExcludeDefault = [ - // Ignore files starting with _ '**/_*.{js,jsx,ts,tsx,md,mdx}', - - // Ignore folders starting with _ (including folder content) '**/_*/**', - - // Ignore tests '**/*.test.{js,jsx,ts,tsx}', '**/__tests__/**', ]; type Matcher = (str: string) => boolean; +/** + * A very thin wrapper around `Micromatch.makeRe`. + * + * @see {@link createAbsoluteFilePathMatcher} + * @param patterns A list of glob patterns. + * @returns A matcher handle that tells if a file path is matched by any of the + * patterns. + */ export function createMatcher(patterns: string[]): Matcher { const regexp = new RegExp( patterns.map((pattern) => Micromatch.makeRe(pattern).source).join('|'), @@ -35,10 +42,19 @@ export function createMatcher(patterns: string[]): Matcher { return (str) => regexp.test(str); } -// We use match patterns like '**/_*/**', -// This function permits to help to: -// Match /user/sebastien/website/docs/_partials/xyz.md -// Ignore /user/_sebastien/website/docs/partials/xyz.md +/** + * We use match patterns like `"** /_* /**"` (ignore the spaces), where `"_*"` + * should only be matched within a subfolder. This function would: + * - Match `/user/sebastien/website/docs/_partials/xyz.md` + * - Ignore `/user/_sebastien/website/docs/partials/xyz.md` + * + * @param patterns A list of glob patterns. + * @param rootFolders A list of root folders to resolve the glob from. + * @returns A matcher handle that tells if a file path is matched by any of the + * patterns, resolved from the first root folder that contains the path. + * @throws Throws when the returned matcher receives a path that doesn't belong + * to any of the `rootFolders`. + */ export function createAbsoluteFilePathMatcher( patterns: string[], rootFolders: string[], @@ -51,8 +67,8 @@ export function createAbsoluteFilePathMatcher( ); if (!rootFolder) { throw new Error( - `createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=${absoluteFilePath} was not contained in any of the root folders ${JSON.stringify( - rootFolders, + `createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=${absoluteFilePath} was not contained in any of the root folders: ${rootFolders.join( + ', ', )}`, ); } diff --git a/packages/docusaurus-utils/src/hashUtils.ts b/packages/docusaurus-utils/src/hashUtils.ts index 3ebb9bd84ef0..8d6e344b4732 100644 --- a/packages/docusaurus-utils/src/hashUtils.ts +++ b/packages/docusaurus-utils/src/hashUtils.ts @@ -9,20 +9,21 @@ import {createHash} from 'crypto'; import _ from 'lodash'; import {shortName, isNameTooLong} from './pathUtils'; +/** Thin wrapper around `crypto.createHash("md5")`. */ export function md5Hash(str: string): string { return createHash('md5').update(str).digest('hex'); } +/** Creates an MD5 hash and truncates it to the given length. */ export function simpleHash(str: string, length: number): string { - return md5Hash(str).substr(0, length); + return md5Hash(str).substring(0, length); } // Based on https://github.com/gatsbyjs/gatsby/pull/21518/files /** - * Given an input string, convert to kebab-case and append a hash. - * Avoid str collision. - * Also removes part of the string if its larger than the allowed - * filename per OS. Avoids ERRNAMETOOLONG error. + * Given an input string, convert to kebab-case and append a hash, avoiding name + * collision. Also removes part of the string if its larger than the allowed + * filename per OS, avoiding `ERRNAMETOOLONG` error. */ export function docuHash(str: string): string { if (str === '/') { diff --git a/packages/docusaurus-utils/src/i18nUtils.ts b/packages/docusaurus-utils/src/i18nUtils.ts index 3e3005fcfeb9..83bec7163ff5 100644 --- a/packages/docusaurus-utils/src/i18nUtils.ts +++ b/packages/docusaurus-utils/src/i18nUtils.ts @@ -8,16 +8,21 @@ import path from 'path'; import _ from 'lodash'; import type {TranslationFileContent, TranslationFile} from '@docusaurus/types'; -import {DEFAULT_PLUGIN_ID} from './constants'; +import {DEFAULT_PLUGIN_ID, I18N_DIR_NAME} from './constants'; +/** + * Takes a list of translation file contents, and shallow-merges them into one. + */ export function mergeTranslations( contents: TranslationFileContent[], ): TranslationFileContent { return contents.reduce((acc, content) => ({...acc, ...content}), {}); } -// Useful to update all the messages of a translation file -// Used in tests to simulate translations +/** + * Useful to update all the messages of a translation file. Used in tests to + * simulate translations. + */ export function updateTranslationFileMessages( translationFile: TranslationFile, updateMessage: (message: string) => string, @@ -31,6 +36,10 @@ export function updateTranslationFileMessages( }; } +/** + * Takes everything needed and constructs a plugin i18n path. Plugins should + * expect everything it needs for translations to be found under this path. + */ export function getPluginI18nPath({ siteDir, locale, @@ -46,7 +55,7 @@ export function getPluginI18nPath({ }): string { return path.join( siteDir, - 'i18n', + I18N_DIR_NAME, // namespace first by locale: convenient to work in a single folder for a // translator locale, diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index c3e246ce8d5c..a41197ea0666 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -13,9 +13,11 @@ export { BABEL_CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME, SRC_DIR_NAME, - STATIC_DIR_NAME, + DEFAULT_STATIC_DIR_NAME, OUTPUT_STATIC_ASSETS_DIR_NAME, THEME_PATH, + I18N_DIR_NAME, + CODE_TRANSLATIONS_FILE_NAME, DEFAULT_PORT, DEFAULT_PLUGIN_ID, WEBPACK_URL_LOADER_LIMIT, @@ -34,7 +36,6 @@ export { export { removeSuffix, removePrefix, - getElementsAround, mapAsyncSequential, findAsyncSequential, reportMessage, @@ -56,8 +57,6 @@ export { export { type Tag, type FrontMatterTag, - type TaggedItemGroup, - normalizeFrontMatterTag, normalizeFrontMatterTags, groupTaggedItems, } from './tags'; @@ -73,8 +72,6 @@ export { export { type ContentPaths, type BrokenMarkdownLink, - type ReplaceMarkdownLinksParams, - type ReplaceMarkdownLinksReturn, replaceMarkdownLinks, } from './markdownLinks'; export {type SluggerOptions, type Slugger, createSlugger} from './slugger'; diff --git a/packages/docusaurus-utils/src/jsUtils.ts b/packages/docusaurus-utils/src/jsUtils.ts index a0db09b3d1c6..1e2858fe620c 100644 --- a/packages/docusaurus-utils/src/jsUtils.ts +++ b/packages/docusaurus-utils/src/jsUtils.ts @@ -8,36 +8,27 @@ import type {ReportingSeverity} from '@docusaurus/types'; import logger from '@docusaurus/logger'; +/** Removes a given string suffix from `str`. */ export function removeSuffix(str: string, suffix: string): string { if (suffix === '') { - return str; // always returns "" otherwise! + // str.slice(0, 0) is "" + return str; } return str.endsWith(suffix) ? str.slice(0, -suffix.length) : str; } +/** Removes a given string prefix from `str`. */ export function removePrefix(str: string, prefix: string): string { return str.startsWith(prefix) ? str.slice(prefix.length) : str; } -export function getElementsAround<T>( - array: T[], - aroundIndex: number, -): { - next: T | undefined; - previous: T | undefined; -} { - const min = 0; - const max = array.length - 1; - if (aroundIndex < min || aroundIndex > max) { - throw new Error( - `Valid "aroundIndex" for array (of size ${array.length}) are between ${min} and ${max}, but you provided ${aroundIndex}.`, - ); - } - const previous = aroundIndex === min ? undefined : array[aroundIndex - 1]; - const next = aroundIndex === max ? undefined : array[aroundIndex + 1]; - return {previous, next}; -} - +/** + * `Array#map` for async operations where order matters. + * @param array The array to traverse. + * @param action An async action to be performed on every array item. Will be + * awaited before working on the next. + * @returns The list of results returned from every `action(item)` + */ export async function mapAsyncSequential<T, R>( array: T[], action: (t: T) => Promise<R>, @@ -50,6 +41,14 @@ export async function mapAsyncSequential<T, R>( return results; } +/** + * `Array#find` for async operations where order matters. + * @param array The array to traverse. + * @param predicate An async predicate to be called on every array item. Should + * return a boolean indicating whether the currently element should be returned. + * @returns The function immediately returns the first item on which `predicate` + * returns `true`, or `undefined` if none matches the predicate. + */ export async function findAsyncSequential<T>( array: T[], predicate: (t: T) => Promise<boolean>, @@ -62,6 +61,21 @@ export async function findAsyncSequential<T>( return undefined; } +/** + * Takes a message and reports it according to the severity that the user wants. + * + * - `ignore`: completely no-op + * - `log`: uses the `INFO` log level + * - `warn`: uses the `WARN` log level + * - `error`: uses the `ERROR` log level + * - `throw`: aborts the process, throws the error. + * + * Since the logger doesn't have logging level filters yet, these severities + * mostly just differ by their colors. + * + * @throws In addition to throwing when `reportingSeverity === "throw"`, this + * function also throws if `reportingSeverity` is not one of the above. + */ export function reportMessage( message: string, reportingSeverity: ReportingSeverity, diff --git a/packages/docusaurus-utils/src/markdownLinks.ts b/packages/docusaurus-utils/src/markdownLinks.ts index afbd7170cebc..c05012d902d9 100644 --- a/packages/docusaurus-utils/src/markdownLinks.ts +++ b/packages/docusaurus-utils/src/markdownLinks.ts @@ -6,41 +6,79 @@ */ import path from 'path'; +import {getContentPathList} from './dataFileUtils'; import {aliasedSitePath} from './pathUtils'; +/** + * Content plugins have a base path and a localized path to source content from. + * We will look into the localized path in priority. + */ export type ContentPaths = { + /** + * The absolute path to the base content directory, like `"<siteDir>/docs"`. + */ contentPath: string; + /** + * The absolute path to the localized content directory, like + * `"<siteDir>/i18n/zh-Hans/plugin-content-docs"`. + */ contentPathLocalized: string; }; +/** Data structure representing each broken Markdown link to be reported. */ export type BrokenMarkdownLink<T extends ContentPaths> = { + /** Absolute path to the file containing this link. */ filePath: string; + /** + * This is generic because it may contain extra metadata like version name, + * which the reporter can provide for context. + */ contentPaths: T; + /** + * The content of the link, like `"./brokenFile.md"` + */ link: string; }; -export type ReplaceMarkdownLinksParams<T extends ContentPaths> = { +/** + * Takes a Markdown file and replaces relative file references with their URL + * counterparts, e.g. `[link](./intro.md)` => `[link](/docs/intro)`, preserving + * everything else. + * + * This method uses best effort to find a matching file. The file reference can + * be relative to the directory of the current file (most likely) or any of the + * content paths (so `/tutorials/intro.md` can be resolved as + * `<siteDir>/docs/tutorials/intro.md`). Links that contain the `http(s):` or + * `@site/` prefix will always be ignored. + */ +export function replaceMarkdownLinks<T extends ContentPaths>({ + siteDir, + fileString, + filePath, + contentPaths, + sourceToPermalink, +}: { + /** Absolute path to the site directory, used to resolve aliased paths. */ siteDir: string; + /** The Markdown file content to be processed. */ fileString: string; + /** Absolute path to the current file containing `fileString`. */ filePath: string; + /** The content paths which the file reference may live in. */ contentPaths: T; + /** + * A map from source paths to their URLs. Source paths are `@site` aliased. + */ sourceToPermalink: Record<string, string>; -}; - -export type ReplaceMarkdownLinksReturn<T extends ContentPaths> = { +}): { + /** + * The content with all Markdown file references replaced with their URLs. + * Unresolved links are left as-is. + */ newContent: string; + /** The list of broken links, */ brokenMarkdownLinks: BrokenMarkdownLink<T>[]; -}; - -export function replaceMarkdownLinks<T extends ContentPaths>({ - siteDir, - fileString, - filePath, - contentPaths, - sourceToPermalink, -}: ReplaceMarkdownLinksParams<T>): ReplaceMarkdownLinksReturn<T> { - const {contentPath, contentPathLocalized} = contentPaths; - +} { const brokenMarkdownLinks: BrokenMarkdownLink<T>[] = []; // Replace internal markdown linking (except in fenced blocks). @@ -64,9 +102,8 @@ export function replaceMarkdownLinks<T extends ContentPaths>({ let modifiedLine = line; // Replace inline-style links or reference-style links e.g: - // This is [Document 1](doc1.md) -> we replace this doc1.md with correct - // ink - // [doc1]: doc1.md -> we replace this doc1.md with correct link + // This is [Document 1](doc1.md) + // [doc1]: doc1.md const mdRegex = /(?:\]\(|\]:\s*)(?!https?:\/\/|@site\/)(?<filename>[^'")\]\s>]+\.mdx?)/g; let mdMatch = mdRegex.exec(modifiedLine); @@ -75,10 +112,9 @@ export function replaceMarkdownLinks<T extends ContentPaths>({ const mdLink = mdMatch.groups!.filename!; const sourcesToTry = [ - path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)), - `${contentPathLocalized}/${decodeURIComponent(mdLink)}`, - `${contentPath}/${decodeURIComponent(mdLink)}`, - ]; + path.dirname(filePath), + ...getContentPathList(contentPaths), + ].map((p) => path.join(p, decodeURIComponent(mdLink))); const aliasedSourceMatch = sourcesToTry .map((source) => aliasedSitePath(source, siteDir)) diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index 7bc7fbafc4f2..3e0d2c615dd1 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -7,12 +7,25 @@ import logger from '@docusaurus/logger'; import matter from 'gray-matter'; -import {createSlugger, type Slugger} from './slugger'; +import {createSlugger, type Slugger, type SluggerOptions} from './slugger'; -// Input: ## Some heading {#some-heading} -// Output: {text: "## Some heading", id: "some-heading"} +// Some utilities for parsing Markdown content. These things are only used on +// server-side when we infer metadata like `title` and `description` from the +// content. Most parsing is still done in MDX through the mdx-loader. + +/** + * Parses custom ID from a heading. The ID must be composed of letters, + * underscores, and dashes only. + * + * @param heading e.g. `## Some heading {#some-heading}` where the last + * character must be `}` for the ID to be recognized + */ export function parseMarkdownHeadingId(heading: string): { + /** + * The heading content sans the ID part, right-trimmed. e.g. `## Some heading` + */ text: string; + /** The heading ID. e.g. `some-heading` */ id?: string; } { const customHeadingIdRegex = /\s*\{#(?<id>[\w-]+)\}$/; @@ -26,26 +39,40 @@ export function parseMarkdownHeadingId(heading: string): { return {text: heading, id: undefined}; } -// Hacky way of stripping out import statements from the excerpt // TODO: Find a better way to do so, possibly by compiling the Markdown content, // stripping out HTML tags and obtaining the first line. +/** + * Creates an excerpt of a Markdown file. This function will: + * + * - Ignore h1 headings (setext or atx) + * - Ignore import/export + * - Ignore code blocks + * + * And for the first contentful line, it will strip away most Markdown + * syntax, including HTML tags, emphasis, links (keeping the text), etc. + */ export function createExcerpt(fileString: string): string | undefined { const fileLines = fileString - .trimLeft() + .trimStart() // Remove Markdown alternate title .replace(/^[^\n]*\n[=]+/g, '') .split('\n'); let inCode = false; + let inImport = false; let lastCodeFence = ''; for (const fileLine of fileLines) { + if (fileLine === '' && inImport) { + inImport = false; + } // Skip empty line. if (!fileLine.trim()) { continue; } // Skip import/export declaration. - if (/^(?:import|export)\s.*/.test(fileLine)) { + if ((/^(?:import|export)\s.*/.test(fileLine) || inImport) && !inCode) { + inImport = true; continue; } @@ -102,8 +129,22 @@ export function createExcerpt(fileString: string): string | undefined { return undefined; } +/** + * Takes a raw Markdown file content, and parses the front matter using + * gray-matter. Worth noting that gray-matter accepts TOML and other markup + * languages as well. + * + * @throws Throws when gray-matter throws. e.g.: + * ```md + * --- + * foo: : bar + * --- + * ``` + */ export function parseFrontMatter(markdownFileContent: string): { + /** Front matter as parsed by gray-matter. */ frontMatter: Record<string, unknown>; + /** The remaining content, trimmed. */ content: string; } { const {data, content} = matter(markdownFileContent); @@ -113,11 +154,6 @@ export function parseFrontMatter(markdownFileContent: string): { }; } -/** - * Try to convert markdown heading to text. Does not need to be perfect, it is - * only used as a fallback when frontMatter.title is not provided. For now, we - * just unwrap possible inline code blocks (# `config.js`) - */ function toTextContentTitle(contentTitle: string): string { if (contentTitle.startsWith('`') && contentTitle.endsWith('`')) { return contentTitle.substring(1, contentTitle.length - 1); @@ -125,10 +161,36 @@ function toTextContentTitle(contentTitle: string): string { return contentTitle; } +type ParseMarkdownContentTitleOptions = { + /** + * If `true`, the matching title will be removed from the returned content. + * We can promise that at least one empty line will be left between the + * content before and after, but you shouldn't make too much assumption + * about what's left. + */ + removeContentTitle?: boolean; +}; + +/** + * Takes the raw Markdown content, without front matter, and tries to find an h1 + * title (setext or atx) to be used as metadata. + * + * It only searches until the first contentful paragraph, ignoring import/export + * declarations. + * + * It will try to convert markdown to reasonable text, but won't be best effort, + * since it's only used as a fallback when `frontMatter.title` is not provided. + * For now, we just unwrap inline code (``# `config.js` `` => `config.js`). + */ export function parseMarkdownContentTitle( contentUntrimmed: string, - options?: {removeContentTitle?: boolean}, -): {content: string; contentTitle: string | undefined} { + options?: ParseMarkdownContentTitleOptions, +): { + /** The content, optionally without the content title. */ + content: string; + /** The title, trimmed and without the `#`. */ + contentTitle: string | undefined; +} { const removeContentTitleOption = options?.removeContentTitle ?? false; const content = contentUntrimmed.trim(); @@ -171,17 +233,28 @@ export function parseMarkdownContentTitle( }; } -type ParsedMarkdown = { +/** + * Makes a full-round parse. + * + * @throws Throws when `parseFrontMatter` throws, usually because of invalid + * syntax. + */ +export function parseMarkdownString( + markdownFileContent: string, + options?: ParseMarkdownContentTitleOptions, +): { + /** @see {@link parseFrontMatter} */ frontMatter: Record<string, unknown>; - content: string; + /** @see {@link parseMarkdownContentTitle} */ contentTitle: string | undefined; + /** @see {@link createExcerpt} */ excerpt: string | undefined; -}; - -export function parseMarkdownString( - markdownFileContent: string, - options?: {removeContentTitle?: boolean}, -): ParsedMarkdown { + /** + * Content without front matter and (optionally) without title, depending on + * the `removeContentTitle` option. + */ + content: string; +} { try { const {frontMatter, content: contentWithoutFrontMatter} = parseFrontMatter(markdownFileContent); @@ -229,11 +302,16 @@ function addHeadingId( return `${headingHashes}${headingText} {#${slug}}`; } -export type WriteHeadingIDOptions = { - maintainCase?: boolean; +export type WriteHeadingIDOptions = SluggerOptions & { + /** Overwrite existing heading IDs. */ overwrite?: boolean; }; +/** + * Takes Markdown content, returns new content with heading IDs written. + * Respects existing IDs (unless `overwrite=true`) and never generates colliding + * IDs (through the slugger). + */ export function writeMarkdownHeadingId( content: string, options: WriteHeadingIDOptions = {maintainCase: false, overwrite: false}, diff --git a/packages/docusaurus-utils/src/pathUtils.ts b/packages/docusaurus-utils/src/pathUtils.ts index db005eab567c..f8380ec87d15 100644 --- a/packages/docusaurus-utils/src/pathUtils.ts +++ b/packages/docusaurus-utils/src/pathUtils.ts @@ -24,7 +24,7 @@ export const isNameTooLong = (str: string): boolean => ? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // MacOS (APFS) and Windows (NTFS) filename length limit (255 chars) : Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES; // Other (255 bytes) -export const shortName = (str: string): string => { +export function shortName(str: string): string { if (isMacOs() || isWindows()) { const overflowingChars = str.length - MAX_PATH_SEGMENT_CHARS; return str.slice( @@ -41,7 +41,7 @@ export const shortName = (str: string): string => { Buffer.byteLength(strBuffer) - overflowingBytes - SPACE_FOR_APPENDING - 1, ) .toString(); -}; +} /** * Convert Windows backslash paths to posix style paths. diff --git a/packages/docusaurus-utils/src/slugger.ts b/packages/docusaurus-utils/src/slugger.ts index f224549a6b68..5edba19b40e5 100644 --- a/packages/docusaurus-utils/src/slugger.ts +++ b/packages/docusaurus-utils/src/slugger.ts @@ -10,12 +10,24 @@ import GithubSlugger from 'github-slugger'; // We create our own abstraction on top of the lib: // - unify usage everywhere in the codebase // - ability to add extra options -export type SluggerOptions = {maintainCase?: boolean}; +export type SluggerOptions = { + /** Keep the headings' casing, otherwise make all lowercase. */ + maintainCase?: boolean; +}; export type Slugger = { + /** + * Takes a Markdown heading like "Josh Cena" and sluggifies it according to + * GitHub semantics (in this case `josh-cena`). Stateful, because if you try + * to sluggify "Josh Cena" again it would return `josh-cena-1`. + */ slug: (value: string, options?: SluggerOptions) => string; }; +/** + * A thin wrapper around github-slugger. This is a factory function that returns + * a stateful Slugger object. + */ export function createSlugger(): Slugger { const githubSlugger = new GithubSlugger(); return { diff --git a/packages/docusaurus-utils/src/tags.ts b/packages/docusaurus-utils/src/tags.ts index c854038f4dd4..fa5eb4eebd1e 100644 --- a/packages/docusaurus-utils/src/tags.ts +++ b/packages/docusaurus-utils/src/tags.ts @@ -10,12 +10,13 @@ import {normalizeUrl} from './urlUtils'; export type Tag = { label: string; + /** Permalink to this tag's page, without the `/tags/` base path. */ permalink: string; }; export type FrontMatterTag = string | Tag; -export function normalizeFrontMatterTag( +function normalizeFrontMatterTag( tagsPath: string, frontMatterTag: FrontMatterTag, ): Tag { @@ -45,8 +46,19 @@ export function normalizeFrontMatterTag( }; } +/** + * Takes tag objects as they are defined in front matter, and normalizes each + * into a standard tag object. The permalink is created by appending the + * sluggified label to `tagsPath`. Front matter tags already containing + * permalinks would still have `tagsPath` prepended. + * + * The result will always be unique by permalinks. The behavior with colliding + * permalinks is undetermined. + */ export function normalizeFrontMatterTags( + /** Base path to append the tag permalinks to. */ tagsPath: string, + /** Can be `undefined`, so that we can directly pipe in `frontMatter.tags`. */ frontMatterTags: FrontMatterTag[] | undefined = [], ): Tag[] { const tags = frontMatterTags.map((tag) => @@ -56,42 +68,42 @@ export function normalizeFrontMatterTags( return _.uniqBy(tags, (tag) => tag.permalink); } -export type TaggedItemGroup<Item> = { +type TaggedItemGroup<Item> = { tag: Tag; items: Item[]; }; /** - * Permits to group docs/blogPosts by tag (provided by front matter) - * Note: groups are indexed by permalink, because routes must be unique in the - * end. Labels may vary on 2 md files but they are normalized. Docs with - * label='some label' and label='some-label' should end-up in the same - * group/page in the end. We can't create 2 routes /some-label because one would - * override the other + * Permits to group docs/blog posts by tag (provided by front matter). + * + * @returns a map from tag permalink to the items and other relevant tag data. + * The record is indexed by permalink, because routes must be unique in the end. + * Labels may vary on 2 MD files but they are normalized. Docs with + * label='some label' and label='some-label' should end up in the same page. */ export function groupTaggedItems<Item>( items: readonly Item[], + /** + * A callback telling me how to get the tags list of the current item. Usually + * simply getting it from some metadata of the current item. + */ getItemTags: (item: Item) => readonly Tag[], -): Record<string, TaggedItemGroup<Item>> { - const result: Record<string, TaggedItemGroup<Item>> = {}; - - function handleItemTag(item: Item, tag: Tag) { - // Init missing tag groups - // TODO: it's not really clear what should be the behavior if 2 items have - // the same tag but the permalink is different for each - // For now, the first tag found wins - result[tag.permalink] ??= { - tag, - items: [], - }; - - // Add item to group - result[tag.permalink]!.items.push(item); - } +): {[permalink: string]: TaggedItemGroup<Item>} { + const result: {[permalink: string]: TaggedItemGroup<Item>} = {}; items.forEach((item) => { getItemTags(item).forEach((tag) => { - handleItemTag(item, tag); + // Init missing tag groups + // TODO: it's not really clear what should be the behavior if 2 tags have + // the same permalink but the label is different for each + // For now, the first tag found wins + result[tag.permalink] ??= { + tag, + items: [], + }; + + // Add item to group + result[tag.permalink]!.items.push(item); }); }); diff --git a/packages/docusaurus-utils/src/urlUtils.ts b/packages/docusaurus-utils/src/urlUtils.ts index 4aa7ebc97f03..1c6f6f5c8591 100644 --- a/packages/docusaurus-utils/src/urlUtils.ts +++ b/packages/docusaurus-utils/src/urlUtils.ts @@ -8,6 +8,18 @@ import {removeSuffix} from './jsUtils'; import resolvePathnameUnsafe from 'resolve-pathname'; +/** + * Much like `path.join`, but much better. Takes an array of URL segments, and + * joins them into a reasonable URL. + * + * - `["file:", "/home", "/user/", "website"]` => `file:///home/user/website` + * - `["file://", "home", "/user/", "website"]` => `file://home/user/website` (relative!) + * - Remove trailing slash before parameters or hash. + * - Replace `?` in query parameters with `&`. + * - Dedupe forward slashes in the entire path, avoiding protocol slashes. + * + * @throws {TypeError} If any of the URL segment is not a string, this throws. + */ export function normalizeUrl(rawUrls: string[]): string { const urls = [...rawUrls]; const resultArray = []; @@ -75,8 +87,8 @@ export function normalizeUrl(rawUrls: string[]): string { } let str = resultArray.join('/'); - // Each input component is now separated by a single slash - // except the possible first plain protocol part. + // Each input component is now separated by a single slash except the possible + // first plain protocol part. // Remove trailing slash before parameters or hash. str = str.replace(/\/(?<search>\?|&|#[^!])/g, '$1'); @@ -94,6 +106,11 @@ export function normalizeUrl(rawUrls: string[]): string { return str; } +/** + * Takes a file's path, relative to its content folder, and computes its edit + * URL. If `editUrl` is `undefined`, this returns `undefined`, as is the case + * when the user doesn't want an edit URL in her config. + */ export function getEditUrl( fileRelativePath: string, editUrl?: string, @@ -105,8 +122,8 @@ export function getEditUrl( } /** - * Convert filepath to url path. - * Example: 'index.md' -> '/', 'foo/bar.js' -> '/foo/bar', + * Converts file path to a reasonable URL path, e.g. `'index.md'` -> `'/'`, + * `'foo/bar.js'` -> `'/foo/bar'` */ export function fileToPath(file: string): string { const indexRE = /(?<dirname>^|.*\/)index\.(?:mdx?|jsx?|tsx?)$/i; @@ -118,6 +135,13 @@ export function fileToPath(file: string): string { return `/${file.replace(extRE, '').replace(/\\/g, '/')}`; } +/** + * Similar to `encodeURI`, but uses `encodeURIComponent` and assumes there's no + * query. + * + * `encodeURI("/question?/answer")` => `"/question?/answer#section"`; + * `encodePath("/question?/answer#section")` => `"/question%3F/answer%23foo"` + */ export function encodePath(userPath: string): string { return userPath .split('/') @@ -125,6 +149,10 @@ export function encodePath(userPath: string): string { .join('/'); } +/** + * Whether `str` is a valid pathname. It must be absolute, and not contain + * special characters. + */ export function isValidPathname(str: string): boolean { if (!str.startsWith('/')) { return false; @@ -138,22 +166,31 @@ export function isValidPathname(str: string): boolean { } } -// resolve pathname and fail fast if resolution fails +/** + * Resolve pathnames and fail-fast if resolution fails. Uses standard URL + * semantics (provided by `resolve-pathname` which is used internally by React + * router) + */ export function resolvePathname(to: string, from?: string): string { return resolvePathnameUnsafe(to, from); } +/** Appends a leading slash to `str`, if one doesn't exist. */ export function addLeadingSlash(str: string): string { return str.startsWith('/') ? str : `/${str}`; } // TODO deduplicate: also present in @docusaurus/utils-common +/** Appends a trailing slash to `str`, if one doesn't exist. */ export function addTrailingSlash(str: string): string { return str.endsWith('/') ? str : `${str}/`; } + +/** Removes the trailing slash from `str`. */ export function removeTrailingSlash(str: string): string { return removeSuffix(str, '/'); } +/** Constructs an SSH URL that can be used to push to GitHub. */ export function buildSshUrl( githubHost: string, organizationName: string, @@ -166,6 +203,7 @@ export function buildSshUrl( return `git@${githubHost}:${organizationName}/${projectName}.git`; } +/** Constructs an HTTP URL that can be used to push to GitHub. */ export function buildHttpsUrl( gitCredentials: string, githubHost: string, @@ -179,6 +217,11 @@ export function buildHttpsUrl( return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`; } +/** + * Whether the current URL is an SSH protocol. In addition to looking for + * `ssh:`, it will also allow protocol-less URLs like + * `git@github.com:facebook/docusaurus.git`. + */ export function hasSSHProtocol(sourceRepoUrl: string): boolean { try { if (new URL(sourceRepoUrl).protocol === 'ssh:') { @@ -187,6 +230,6 @@ export function hasSSHProtocol(sourceRepoUrl: string): boolean { return false; } catch { // Fails when there isn't a protocol - return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git + return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); } } diff --git a/packages/docusaurus-utils/src/webpackUtils.ts b/packages/docusaurus-utils/src/webpackUtils.ts index 94aab58558b1..608e384d50d0 100644 --- a/packages/docusaurus-utils/src/webpackUtils.ts +++ b/packages/docusaurus-utils/src/webpackUtils.ts @@ -31,7 +31,11 @@ type FileLoaderUtils = { }; }; -// Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 +/** + * Returns unified loader configurations to be used for various file types. + * + * Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 + */ export function getFileLoaderUtils(): FileLoaderUtils { // files/images < urlLoaderLimit will be inlined as base64 strings directly in // the html @@ -39,7 +43,11 @@ export function getFileLoaderUtils(): FileLoaderUtils { // defines the path/pattern of the assets handled by webpack const fileLoaderFileName = (folder: AssetFolder) => - `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[contenthash].[ext]`; + path.posix.join( + OUTPUT_STATIC_ASSETS_DIR_NAME, + folder, + '[name]-[contenthash].[ext]', + ); const loaders: FileLoaderUtils['loaders'] = { file: (options: {folder: AssetFolder}) => ({ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 19c104b08466..d4dfb2f4fdac 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -6,7 +6,10 @@ */ import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types'; -import {DEFAULT_CONFIG_FILE_NAME, STATIC_DIR_NAME} from '@docusaurus/utils'; +import { + DEFAULT_CONFIG_FILE_NAME, + DEFAULT_STATIC_DIR_NAME, +} from '@docusaurus/utils'; import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation'; const DEFAULT_I18N_LOCALE = 'en'; @@ -53,7 +56,7 @@ export const DEFAULT_CONFIG: Pick< noIndex: false, tagline: '', baseUrlIssueBanner: true, - staticDirectories: [STATIC_DIR_NAME], + staticDirectories: [DEFAULT_STATIC_DIR_NAME], }; function createPluginSchema(theme: boolean) { diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index cba14d1f3e18..1b3458b2979e 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -14,7 +14,12 @@ import type { TranslationMessage, InitializedPlugin, } from '@docusaurus/types'; -import {getPluginI18nPath, toMessageRelativeFilePath} from '@docusaurus/utils'; +import { + getPluginI18nPath, + toMessageRelativeFilePath, + I18N_DIR_NAME, + CODE_TRANSLATIONS_FILE_NAME, +} from '@docusaurus/utils'; import {Joi} from '@docusaurus/utils-validation'; import logger from '@docusaurus/logger'; @@ -140,7 +145,7 @@ Maybe you should remove them? ${unknownKeys}`; // should we make this configurable? function getTranslationsDirPath(context: TranslationContext): string { - return path.resolve(path.join(context.siteDir, `i18n`)); + return path.resolve(path.join(context.siteDir, I18N_DIR_NAME)); } export function getTranslationsLocaleDirPath( context: TranslationContext, @@ -149,7 +154,10 @@ export function getTranslationsLocaleDirPath( } function getCodeTranslationsFilePath(context: TranslationContext): string { - return path.join(getTranslationsLocaleDirPath(context), 'code.json'); + return path.join( + getTranslationsLocaleDirPath(context), + CODE_TRANSLATIONS_FILE_NAME, + ); } export async function readCodeTranslationFileContent( diff --git a/project-words.txt b/project-words.txt index f71fab6a6ca2..90473e136687 100644 --- a/project-words.txt +++ b/project-words.txt @@ -256,9 +256,13 @@ sebastienlorber sensical serializers setaf +setext sida simen slorber +sluggified +sluggifies +sluggify spâce stackblitz stackblitzrc From 22c031c0719f011b9a908fc423f17ebef5d9777d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Thu, 24 Mar 2022 15:33:21 +0100 Subject: [PATCH 054/405] fix(search): bump Infima, fix Docusaurus search issue due to broken CSS selector (#6983) --- packages/docusaurus-theme-classic/package.json | 2 +- .../src/theme/DocSidebarItem/index.tsx | 3 ++- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 5abc72141fc9..dfbe3ddf767f 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -33,7 +33,7 @@ "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.37", + "infima": "0.2.0-alpha.38", "lodash": "^4.17.21", "postcss": "^8.4.12", "prism-react-renderer": "^1.3.1", diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index 46b57ffd0a7f..a22078e5d1ba 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -160,7 +160,8 @@ function DocSidebarItemCategory({ })}> <Link className={clsx('menu__link', { - 'menu__link--sublist': collapsible && !href, + 'menu__link--sublist': collapsible, + 'menu__link--sublist-caret': !href, 'menu__link--active': isActive, })} onClick={ diff --git a/yarn.lock b/yarn.lock index 675056fc673d..a31885285b94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10599,10 +10599,10 @@ infer-owner@^1.0.4: resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== -infima@0.2.0-alpha.37: - version "0.2.0-alpha.37" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.37.tgz#b87ff42d528d6d050098a560f0294fbdd12adb78" - integrity sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q== +infima@0.2.0-alpha.38: + version "0.2.0-alpha.38" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.38.tgz#e41d95c7cd82756549b17df12f613fed4af3d528" + integrity sha512-1WsmqSMI5IqzrUx3goq+miJznHBonbE3aoqZ1AR/i/oHhroxNeSV6Awv5VoVfXBhfTzLSnxkHaRI2qpAMYcCzw== inflight@^1.0.4: version "1.0.6" From c3e7ecca17b3706cd3310270a8b722f316a2feb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Thu, 24 Mar 2022 16:09:28 +0100 Subject: [PATCH 055/405] chore: update static-site-generator-webpack-plugin (#6975) --- packages/docusaurus/package.json | 2 +- yarn.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index ecd5ad45236c..dc2c41e0cc69 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -48,7 +48,7 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-common": "2.0.0-beta.17", "@docusaurus/utils-validation": "2.0.0-beta.17", - "@slorber/static-site-generator-webpack-plugin": "^4.0.1", + "@slorber/static-site-generator-webpack-plugin": "^4.0.4", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.4", "babel-loader": "^8.2.3", diff --git a/yarn.lock b/yarn.lock index a31885285b94..0b3f7a7d3dc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3461,15 +3461,14 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@slorber/static-site-generator-webpack-plugin@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" - integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== +"@slorber/static-site-generator-webpack-plugin@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.4.tgz#2bf4a2545e027830d2aa5eb950437c26a289b0f1" + integrity sha512-FvMavoWEIePps6/JwGCOLYKCRhuwIHhMtmbKpBFgzNkxwpa/569LfTkrbRk1m1I3n+ezJK4on9E1A6cjuZmD9g== dependencies: bluebird "^3.7.1" cheerio "^0.22.0" - eval "^0.1.4" - url "^0.11.0" + eval "^0.1.8" webpack-sources "^1.4.3" "@surma/rollup-plugin-off-main-thread@^2.2.3": @@ -8580,11 +8579,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eval@^0.1.4: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" - integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== +eval@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.8.tgz#2b903473b8cc1d1989b83a1e7923f883eb357f85" + integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== dependencies: + "@types/node" "*" require-like ">= 0.1.1" eventemitter3@^4.0.0, eventemitter3@^4.0.4: From 21ff25eebbb5424e3bf1d2da3140bd74a91b16f4 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 24 Mar 2022 23:52:45 +0800 Subject: [PATCH 056/405] fix(theme-classic): minor code copy button improvements (#6986) --- .../src/theme/CodeBlock/CopyButton/index.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx index 4a02ec1306a8..dbc48c99d2f9 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useState} from 'react'; +import React, {useCallback, useState, useRef, useEffect} from 'react'; import clsx from 'clsx'; import copy from 'copy-text-to-clipboard'; import {translate} from '@docusaurus/Translate'; @@ -15,14 +15,16 @@ import styles from './styles.module.css'; export default function CopyButton({code}: Props): JSX.Element { const [isCopied, setIsCopied] = useState(false); - const handleCopyCode = () => { + const copyTimeout = useRef<number | undefined>(undefined); + const handleCopyCode = useCallback(() => { copy(code); setIsCopied(true); - - setTimeout(() => { + copyTimeout.current = window.setTimeout(() => { setIsCopied(false); - }, 2000); - }; + }, 1000); + }, [code]); + + useEffect(() => () => window.clearTimeout(copyTimeout.current), []); return ( <button From 4c0914c0350cdd2e30d222469d8388efbbedcea0 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Thu, 24 Mar 2022 19:03:59 +0300 Subject: [PATCH 057/405] refactor(theme-classic): remove span wrappers from layout links (#6985) --- .../src/theme/DocSidebarItem/index.tsx | 6 ++---- .../src/theme/Footer/LinkItem/index.tsx | 6 ++---- .../src/theme/NavbarItem/NavbarNavLink.tsx | 10 ++++------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index a22078e5d1ba..f0a422ebf161 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -269,10 +269,8 @@ function DocSidebarItemLink({ onClick: onItemClick ? () => onItemClick(item) : undefined, })} {...props}> - <span> - {label} - {!isInternalUrl(href) && <IconExternalLink />} - </span> + {label} + {!isInternalUrl(href) && <IconExternalLink />} </Link> </li> ); diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx index 7ae87c588540..f5e334acefb8 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/LinkItem/index.tsx @@ -29,10 +29,8 @@ export default function FooterLinkItem({item}: Props): JSX.Element { to: toUrl, })} {...props}> - <span> - {label} - {href && !isInternalUrl(href) && <IconExternalLink />} - </span> + {label} + {href && !isInternalUrl(href) && <IconExternalLink />} </Link> ); } diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx index ba706d46d99f..af498982f6f1 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx @@ -55,12 +55,10 @@ export default function NavbarNavLink({ : null), })} {...props}> - <span> - {label} - {isExternalLink && ( - <IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} /> - )} - </span> + {label} + {isExternalLink && ( + <IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} /> + )} </Link> ); } From c42f22b9bd4d39d48f3349031acb27d37db89bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Thu, 24 Mar 2022 19:23:44 +0100 Subject: [PATCH 058/405] refactor: extract MDX components (#6989) --- .../src/getSwizzleConfig.ts | 62 +++++++++++ .../src/theme-classic.d.ts | 91 ++++++++++++++-- .../src/theme/MDXComponents/A.tsx | 14 +++ .../src/theme/MDXComponents/Code.tsx | 37 +++++++ .../src/theme/MDXComponents/Details.tsx | 26 +++++ .../src/theme/MDXComponents/Head.tsx | 29 +++++ .../src/theme/MDXComponents/Heading.tsx | 14 +++ .../src/theme/MDXComponents/Img.module.css | 10 ++ .../src/theme/MDXComponents/Img.tsx | 20 ++++ .../src/theme/MDXComponents/Pre.tsx | 21 ++++ .../{styles.css => Ul.module.css} | 6 +- .../src/theme/MDXComponents/Ul.tsx | 28 +++++ .../src/theme/MDXComponents/index.tsx | 103 ++++-------------- project-words.txt | 1 + 14 files changed, 368 insertions(+), 94 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/A.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Heading.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.module.css create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx rename packages/docusaurus-theme-classic/src/theme/MDXComponents/{styles.css => Ul.module.css} (82%) create mode 100644 packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.tsx diff --git a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts index 3bf2cac6f652..13b9fde846f9 100644 --- a/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts +++ b/packages/docusaurus-theme-classic/src/getSwizzleConfig.ts @@ -136,6 +136,68 @@ export default function getSwizzleConfig(): SwizzleConfig { description: 'The MDX components to use for rendering MDX files. Meant to be ejected.', }, + 'MDXComponents/A': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The component used to render <a> tags and Markdown links in MDX', + }, + 'MDXComponents/Code': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The component used to render <code> tags and Markdown code blocks in MDX', + }, + 'MDXComponents/Details': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The component used to render <details> tags in MDX', + }, + 'MDXComponents/Head': { + actions: { + eject: 'forbidden', + wrap: 'forbidden', + }, + description: + 'Technical component used to assign metadata (generally for SEO purpose) to the current MDX document', + }, + 'MDXComponents/Heading': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The component used to render heading tags (<h1>, <h2>...) and Markdown headings in MDX', + }, + 'MDXComponents/Img': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The component used to render <img> tags and Markdown images in MDX', + }, + 'MDXComponents/Pre': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: 'The component used to render <pre> tags in MDX', + }, + 'MDXComponents/Ul': { + actions: { + eject: 'safe', + wrap: 'safe', + }, + description: + 'The component used to render <ul> tags and Markdown unordered lists in MDX', + }, MDXContent: { actions: { eject: 'safe', diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index a508a0c4d03d..b010f0038594 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -417,24 +417,97 @@ declare module '@theme/SkipToContent' { export default function SkipToContent(): JSX.Element; } -declare module '@theme/MDXComponents' { +declare module '@theme/MDXComponents/A' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'a'> {} + + export default function MDXA(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Code' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'code'> {} + + export default function MDXCode(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Details' { import type {ComponentProps} from 'react'; - import type CodeBlock from '@theme/CodeBlock'; - import type Head from '@docusaurus/Head'; + + export interface Props extends ComponentProps<'details'> {} + + export default function MDXDetails(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Ul' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'ul'> {} + + export default function MDXUl(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Img' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'img'> {} + + export default function MDXImg(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Head' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'head'> {} + + export default function MDXHead(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Heading' { + import type {ComponentProps} from 'react'; + import type Heading from '@theme/Heading'; + + export interface Props extends ComponentProps<typeof Heading> {} + + export default function MDXHeading(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents/Pre' { + import type {ComponentProps} from 'react'; + + export interface Props extends ComponentProps<'pre'> {} + + export default function MDXPre(props: Props): JSX.Element; +} + +declare module '@theme/MDXComponents' { + import type {ComponentType, ComponentProps} from 'react'; + + import type MDXHead from '@theme/MDXComponents/Head'; + import type MDXCode from '@theme/MDXComponents/Code'; + import type MDXA from '@theme/MDXComponents/A'; + import type MDXPre from '@theme/MDXComponents/Pre'; + import type MDXDetails from '@theme/MDXComponents/Details'; + import type MDXUl from '@theme/MDXComponents/Ul'; + import type MDXImg from '@theme/MDXComponents/Img'; export type MDXComponentsObject = { - readonly head: typeof Head; - readonly code: typeof CodeBlock; - readonly a: (props: ComponentProps<'a'>) => JSX.Element; - readonly pre: typeof CodeBlock; - readonly details: (props: ComponentProps<'details'>) => JSX.Element; + readonly head: typeof MDXHead; + readonly code: typeof MDXCode; + readonly a: typeof MDXA; + readonly pre: typeof MDXPre; + readonly details: typeof MDXDetails; + readonly ul: typeof MDXUl; + readonly img: typeof MDXImg; readonly h1: (props: ComponentProps<'h1'>) => JSX.Element; readonly h2: (props: ComponentProps<'h2'>) => JSX.Element; readonly h3: (props: ComponentProps<'h3'>) => JSX.Element; readonly h4: (props: ComponentProps<'h4'>) => JSX.Element; readonly h5: (props: ComponentProps<'h5'>) => JSX.Element; readonly h6: (props: ComponentProps<'h6'>) => JSX.Element; - }; + } & Record<string, ComponentType<unknown>>; const MDXComponents: MDXComponentsObject; export default MDXComponents; diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/A.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/A.tsx new file mode 100644 index 000000000000..9ee8333e6c80 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/A.tsx @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Link from '@docusaurus/Link'; +import type {Props} from '@theme/MDXComponents/A'; + +export default function MDXA(props: Props): JSX.Element { + return <Link {...props} />; +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx new file mode 100644 index 000000000000..4d5680ed0adb --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Code.tsx @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {ComponentProps} from 'react'; +import React, {isValidElement} from 'react'; +import CodeBlock from '@theme/CodeBlock'; +import type {Props} from '@theme/MDXComponents/Code'; + +export default function MDXCode(props: Props): JSX.Element { + const inlineElements = [ + 'a', + 'b', + 'big', + 'i', + 'span', + 'em', + 'strong', + 'sup', + 'sub', + 'small', + ]; + const shouldBeInline = React.Children.toArray(props.children).every( + (el) => + (typeof el === 'string' && !el.includes('\n')) || + (isValidElement(el) && inlineElements.includes(el.props.mdxType)), + ); + + return shouldBeInline ? ( + <code {...props} /> + ) : ( + <CodeBlock {...(props as ComponentProps<typeof CodeBlock>)} /> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx new file mode 100644 index 000000000000..d09f2d923f63 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ComponentProps, type ReactElement} from 'react'; +import Details from '@theme/Details'; +import type {Props} from '@theme/MDXComponents/Details'; + +export default function MDXDetails(props: Props): JSX.Element { + const items = React.Children.toArray(props.children) as ReactElement[]; + // Split summary item from the rest to pass it as a separate prop to the + // Details theme component + const summary: ReactElement<ComponentProps<'summary'>> = items.find( + (item) => item?.props?.mdxType === 'summary', + )!; + const children = <>{items.filter((item) => item !== summary)}</>; + + return ( + <Details {...props} summary={summary}> + {children} + </Details> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx new file mode 100644 index 000000000000..c21608e69e36 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx @@ -0,0 +1,29 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ReactElement, type ComponentProps} from 'react'; +import Head from '@docusaurus/Head'; +import type {Props} from '@theme/MDXComponents/Head'; + +// MDX elements are wrapped through the MDX pragma. In some cases (notably usage +// with Head/Helmet) we need to unwrap those elements. +function unwrapMDXElement(element: ReactElement) { + if (element?.props?.mdxType && element?.props?.originalType) { + const {mdxType, originalType, ...newProps} = element.props; + return React.createElement(element.props.originalType, newProps); + } + return element; +} + +export default function MDXHead(props: Props): JSX.Element { + const unwrappedChildren = React.Children.map(props.children, (child) => + unwrapMDXElement(child as ReactElement), + ); + return ( + <Head {...(props as ComponentProps<typeof Head>)}>{unwrappedChildren}</Head> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Heading.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Heading.tsx new file mode 100644 index 000000000000..2b6c433bc5fc --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Heading.tsx @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Heading from '@theme/Heading'; +import type {Props} from '@theme/MDXComponents/Heading'; + +export default function MDXHeading(props: Props): JSX.Element { + return <Heading {...props} />; +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.module.css b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.module.css new file mode 100644 index 000000000000..76644d485ec3 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.module.css @@ -0,0 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.img { + height: auto; +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx new file mode 100644 index 000000000000..a3b36432946d --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import type {Props} from '@theme/MDXComponents/Img'; +import styles from './Img.module.css'; +import clsx from 'clsx'; + +function transformImgClassName(className?: string): string { + return clsx(className, styles.img); +} + +export default function MDXImg(props: Props): JSX.Element { + // eslint-disable-next-line jsx-a11y/alt-text + return <img {...props} className={transformImgClassName(props.className)} />; +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx new file mode 100644 index 000000000000..36227964eb6a --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {isValidElement} from 'react'; +import CodeBlock from '@theme/CodeBlock'; + +export default function MDXPre(props: any) { + return ( + <CodeBlock + // If this pre is created by a ``` fenced codeblock, unwrap the children + {...(isValidElement(props.children) && + props.children.props.originalType === 'code' + ? props.children?.props + : {...props})} + /> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/styles.css b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.module.css similarity index 82% rename from packages/docusaurus-theme-classic/src/theme/MDXComponents/styles.css rename to packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.module.css index 3c263a233477..af91b8ee535d 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/styles.css +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.module.css @@ -5,11 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -ul.contains-task-list { +.contains-task-list { padding-left: 0; list-style: none; } - -img { - height: auto; -} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.tsx new file mode 100644 index 000000000000..c8bf10e62b9b --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Ul.tsx @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import type {Props} from '@theme/MDXComponents/Ul'; + +import styles from './Ul.module.css'; + +const containsClassListLocalClass = styles['contains-task-list']; + +function transformUlClassName(className?: string): string { + return clsx( + className, + // This class is set globally by GitHub/MDX + // We keep the global class, but apply scoped CSS + // See https://github.com/syntax-tree/mdast-util-to-hast/issues/28 + className?.includes('contains-task-list') && containsClassListLocalClass, + ); +} + +export default function MDXUl(props: Props): JSX.Element { + return <ul {...props} className={transformUlClassName(props.className)} />; +} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx index 8f9605c2a5a1..82e7c5ac6b12 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/index.tsx @@ -5,89 +5,32 @@ * LICENSE file in the root directory of this source tree. */ -import React, { - isValidElement, - type ComponentProps, - type ReactElement, -} from 'react'; -import Head from '@docusaurus/Head'; -import Link from '@docusaurus/Link'; -import CodeBlock from '@theme/CodeBlock'; -import Heading from '@theme/Heading'; -import Details from '@theme/Details'; -import type {MDXComponentsObject} from '@theme/MDXComponents'; - -import './styles.css'; +import React from 'react'; +import MDXHead from '@theme/MDXComponents/Head'; +import MDXCode from '@theme/MDXComponents/Code'; +import MDXA from '@theme/MDXComponents/A'; +import MDXPre from '@theme/MDXComponents/Pre'; +import MDXDetails from '@theme/MDXComponents/Details'; +import MDXHeading from '@theme/MDXComponents/Heading'; +import MDXUl from '@theme/MDXComponents/Ul'; +import MDXImg from '@theme/MDXComponents/Img'; -// MDX elements are wrapped through the MDX pragma. In some cases (notably usage -// with Head/Helmet) we need to unwrap those elements. -function unwrapMDXElement(element: ReactElement) { - if (element?.props?.mdxType && element?.props?.originalType) { - const {mdxType, originalType, ...newProps} = element.props; - return React.createElement(element.props.originalType, newProps); - } - return element; -} +import type {MDXComponentsObject} from '@theme/MDXComponents'; const MDXComponents: MDXComponentsObject = { - head: (props) => { - const unwrappedChildren = React.Children.map(props.children, (child) => - unwrapMDXElement(child as ReactElement), - ); - return <Head {...props}>{unwrappedChildren}</Head>; - }, - code: (props) => { - const inlineElements = [ - 'a', - 'b', - 'big', - 'i', - 'span', - 'em', - 'strong', - 'sup', - 'sub', - 'small', - ]; - const shouldBeInline = React.Children.toArray(props.children).every( - (el) => - (typeof el === 'string' && !el.includes('\n')) || - (isValidElement(el) && inlineElements.includes(el.props.mdxType)), - ); - - return shouldBeInline ? <code {...props} /> : <CodeBlock {...props} />; - }, - a: (props) => <Link {...props} />, - pre: (props) => ( - <CodeBlock - // If this pre is created by a ``` fenced codeblock, unwrap the children - {...(isValidElement(props.children) && - props.children.props.originalType === 'code' - ? props.children?.props - : {...props})} - /> - ), - details: (props): JSX.Element => { - const items = React.Children.toArray(props.children) as ReactElement[]; - // Split summary item from the rest to pass it as a separate prop to the - // Details theme component - const summary: ReactElement<ComponentProps<'summary'>> = items.find( - (item) => item?.props?.mdxType === 'summary', - )!; - const children = <>{items.filter((item) => item !== summary)}</>; - - return ( - <Details {...props} summary={summary}> - {children} - </Details> - ); - }, - h1: (props) => <Heading as="h1" {...props} />, - h2: (props) => <Heading as="h2" {...props} />, - h3: (props) => <Heading as="h3" {...props} />, - h4: (props) => <Heading as="h4" {...props} />, - h5: (props) => <Heading as="h5" {...props} />, - h6: (props) => <Heading as="h6" {...props} />, + head: MDXHead, + code: MDXCode, + a: MDXA, + pre: MDXPre, + details: MDXDetails, + ul: MDXUl, + img: MDXImg, + h1: (props) => <MDXHeading as="h1" {...props} />, + h2: (props) => <MDXHeading as="h2" {...props} />, + h3: (props) => <MDXHeading as="h3" {...props} />, + h4: (props) => <MDXHeading as="h4" {...props} />, + h5: (props) => <MDXHeading as="h5" {...props} />, + h6: (props) => <MDXHeading as="h6" {...props} />, }; export default MDXComponents; diff --git a/project-words.txt b/project-words.txt index 90473e136687..ce93c4352c27 100644 --- a/project-words.txt +++ b/project-words.txt @@ -152,6 +152,7 @@ mathjax mdast mdxast mdxhast +MDXA metadatum metastring middlewares From 395136a73112ea16a149c223c2928ea596469bd2 Mon Sep 17 00:00:00 2001 From: Kayce Basques <kayce@basqu.es> Date: Thu, 24 Mar 2022 17:54:27 -0700 Subject: [PATCH 059/405] docs: fix example admonition syntax (#6988) * Fix example admonition syntax There was a space between `::: info` should be `:::info` or else Docusaurus does not render it as an admonition. * kick CI Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../markdown-features/markdown-features-admonitions.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx index 365641ab2504..3302ee532661 100644 --- a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,14 +87,14 @@ If you use [Prettier](https://prettier.io) to format your Markdown files, Pretti <!-- prettier-ignore --> ```md <!-- Prettier doesn't change this --> -::: note +:::note Hello world ::: <!-- Prettier changes this --> -::: note +:::note Hello world ::: From d3065b8ad2916b5dcba9ba2df06d3bc700f0004c Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 10:23:42 +0800 Subject: [PATCH 060/405] refactor(lqip-loader): remove unused palette option (#6992) --- packages/lqip-loader/README.md | 15 +- packages/lqip-loader/package.json | 1 - .../lqip-loader/src/__tests__/lqip.test.ts | 10 +- .../lqip-loader/src/__tests__/utils.test.ts | 45 --- packages/lqip-loader/src/index.ts | 28 +- packages/lqip-loader/src/lqip.ts | 20 +- packages/lqip-loader/src/utils.ts | 34 -- yarn.lock | 336 +----------------- 8 files changed, 20 insertions(+), 469 deletions(-) delete mode 100644 packages/lqip-loader/src/__tests__/utils.test.ts delete mode 100644 packages/lqip-loader/src/utils.ts diff --git a/packages/lqip-loader/README.md b/packages/lqip-loader/README.md index 8e5467b911ab..a0e2f889023e 100644 --- a/packages/lqip-loader/README.md +++ b/packages/lqip-loader/README.md @@ -10,7 +10,7 @@ npm install --save-dev @docusaurus/lqip-loader ## Example -Generating Base64 & dominant colours palette for a jpeg image imported in your JS bundle: +Generating Base64 for a jpeg image imported in your JS bundle: > The large image file will be emitted & only 400byte of Base64 (if set to true in the loader options) will be bundled. @@ -26,8 +26,6 @@ Generating Base64 & dominant colours palette for a jpeg image imported in your J options: { path: '/media', // your image going to be in media folder in the output dir name: '[name].[ext]', // you can use [contenthash].[ext] too if you wish, - base64: true, // default: true, gives the base64 encoded image - palette: true // default: false, gives the dominant colours palette } } ] @@ -35,13 +33,7 @@ Generating Base64 & dominant colours palette for a jpeg image imported in your J // OPTION B: Chained with your own url-loader or file-loader test: /\.(png|jpe?g)$/, loaders: [ - { - loader: '@docusaurus/lqip-loader', - options: { - base64: true, - palette: false - } - }, + '@docusaurus/lqip-loader', { loader: 'url-loader', options: { @@ -60,9 +52,6 @@ import banner from './images/banner.jpg'; console.log(banner.preSrc); // outputs: "data:image/jpeg;base64,/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhY.... -// the object will have palette property, array will be sorted from most dominant colour to the least -console.log(banner.palette); // [ '#628792', '#bed4d5', '#5d4340', '#ba454d', '#c5dce4', '#551f24' ] - console.log(banner.src); // that's the original image URL to load later! ``` diff --git a/packages/lqip-loader/package.json b/packages/lqip-loader/package.json index 39ffb7a11cd7..66ccece761dd 100644 --- a/packages/lqip-loader/package.json +++ b/packages/lqip-loader/package.json @@ -20,7 +20,6 @@ "@docusaurus/logger": "2.0.0-beta.17", "file-loader": "^6.2.0", "lodash": "^4.17.21", - "node-vibrant": "^3.1.6", "sharp": "^0.30.3", "tslib": "^2.3.1" }, diff --git a/packages/lqip-loader/src/__tests__/lqip.test.ts b/packages/lqip-loader/src/__tests__/lqip.test.ts index 01e6255e18c6..a433f0f0459c 100644 --- a/packages/lqip-loader/src/__tests__/lqip.test.ts +++ b/packages/lqip-loader/src/__tests__/lqip.test.ts @@ -6,7 +6,7 @@ */ import path from 'path'; -import {base64, palette} from '../lqip'; +import {base64} from '../lqip'; const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg'); const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg'); @@ -23,11 +23,3 @@ describe('base64', () => { await expect(base64(imgPath)).resolves.toContain(expectedBase64); }); }); - -describe('palette', () => { - it('generates a valid color palette', async () => { - const imgPalette = await palette(imgPath); - expect(imgPalette).toHaveLength(6); - expect(imgPalette).toContain('#578ca1'); - }); -}); diff --git a/packages/lqip-loader/src/__tests__/utils.test.ts b/packages/lqip-loader/src/__tests__/utils.test.ts deleted file mode 100644 index 162f6b728afa..000000000000 --- a/packages/lqip-loader/src/__tests__/utils.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import path from 'path'; -import Vibrant from 'node-vibrant'; -import type {Palette} from 'node-vibrant/lib/color'; - -import {toPalette, toBase64} from '../utils'; - -describe('toBase64', () => { - it('returns a properly formatted Base64 image string', () => { - const mockedMimeType = 'image/jpeg'; - const mockedBase64Data = Buffer.from('hello world'); - expect(toBase64(mockedMimeType, mockedBase64Data)).toBe( - 'data:image/jpeg;base64,aGVsbG8gd29ybGQ=', - ); - }); -}); - -describe('toPalette', () => { - let correctTestSwatch: Palette = {}; - let testSwatchWithNull: Palette & {Vibrant?: null} = {}; - - beforeAll(() => { - const imgPath = path.join(__dirname, '__fixtures__/endi.jpg'); - const vibrant = new Vibrant(imgPath, {}); - - return vibrant.getPalette().then((palette) => { - correctTestSwatch = {...palette}; - testSwatchWithNull = {...palette, Vibrant: null}; - }); - }); - - it('returns 6 hex colours sorted by popularity', () => { - expect(toPalette(correctTestSwatch)).toHaveLength(6); - }); - - it('returns 5 hex colours with no errors if a palette was incomplete', () => { - expect(toPalette(testSwatchWithNull)).toHaveLength(5); - }); -}); diff --git a/packages/lqip-loader/src/index.ts b/packages/lqip-loader/src/index.ts index b491949dff4d..112851a34c01 100644 --- a/packages/lqip-loader/src/index.ts +++ b/packages/lqip-loader/src/index.ts @@ -22,13 +22,6 @@ export default async function lqipLoader( } const callback = this.async(); const imgPath = this.resourcePath; - - const config = this.getOptions() ?? {}; - config.base64 = 'base64' in config ? config.base64 : true; - // color palette generation is set to false by default - // since it is little bit slower than base64 generation - config.palette = 'palette' in config ? config.palette : false; - let content = contentBuffer.toString('utf8'); const contentIsUrlExport = /^(?:export default|module.exports =) "data:.*base64,.*/.test(content); @@ -53,24 +46,11 @@ export default async function lqipLoader( )!.groups!.source!; } - const outputPromises: [Promise<string> | null, Promise<string[]> | null] = [ - config.base64 === true ? lqip.base64(imgPath) : null, - config.palette === true ? lqip.palette(imgPath) : null, - ]; - try { - const data = await Promise.all(outputPromises); - if (data) { - const [preSrc, palette] = data; - const finalObject = JSON.stringify({src: 'STUB', preSrc, palette}); - const result = `module.exports = ${finalObject.replace( - '"STUB"', - source, - )};`; - callback(null, result); - } else { - callback(new Error('ERROR'), undefined); - } + const preSrc = await lqip.base64(imgPath); + const finalObject = JSON.stringify({src: 'STUB', preSrc}); + const result = `module.exports = ${finalObject.replace('"STUB"', source)};`; + callback(null, result); } catch (err) { console.error(err); callback(new Error('ERROR'), undefined); diff --git a/packages/lqip-loader/src/lqip.ts b/packages/lqip-loader/src/lqip.ts index 68226b0c5ba5..537e036843e5 100644 --- a/packages/lqip-loader/src/lqip.ts +++ b/packages/lqip-loader/src/lqip.ts @@ -6,10 +6,8 @@ */ import logger from '@docusaurus/logger'; -import Vibrant from 'node-vibrant'; import path from 'path'; import sharp from 'sharp'; -import {toPalette, toBase64} from './utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires const {version} = require('../package.json'); @@ -22,6 +20,13 @@ const SUPPORTED_MIMES: Record<string, string> = { png: 'image/png', }; +/** + * it returns a Base64 image string with required formatting + * to work on the web (<img src=".." /> or in CSS url('..')) + */ +const toBase64 = (extMimeType: string, data: Buffer): string => + `data:${extMimeType};base64,${data.toString('base64')}`; + export async function base64(file: string): Promise<string> { let extension = path.extname(file); extension = extension.split('.').pop()!; @@ -39,14 +44,3 @@ export async function base64(file: string): Promise<string> { throw err; } } - -export async function palette(file: string): Promise<string[]> { - const vibrant = new Vibrant(file, {}); - try { - const pal = await vibrant.getPalette(); - return toPalette(pal); - } catch (err) { - logger.error`Generation of color palette failed for image path=${file}.`; - throw err; - } -} diff --git a/packages/lqip-loader/src/utils.ts b/packages/lqip-loader/src/utils.ts deleted file mode 100644 index 063819b8a6ee..000000000000 --- a/packages/lqip-loader/src/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import _ from 'lodash'; -import type {Palette} from 'node-vibrant/lib/color'; - -/** - * it returns a Base64 image string with required formatting - * to work on the web (<img src=".." /> or in CSS url('..')) - */ -export const toBase64 = (extMimeType: string, data: Buffer): string => - `data:${extMimeType};base64,${data.toString('base64')}`; - -/** - * takes a color swatch object, converts it to an array & returns - * only hex color - */ -export const toPalette = (swatch: Palette): string[] => { - let palette = Object.keys(swatch).reduce((result, key) => { - if (swatch[key] !== null) { - result.push({ - popularity: swatch[key]!.getPopulation(), - hex: swatch[key]!.getHex(), - }); - } - return result; - }, [] as {popularity: number; hex: string}[]); - palette = _.sortBy(palette, ['popularity']); - return palette.map((color) => color.hex).reverse(); -}; diff --git a/yarn.lock b/yarn.lock index 0b3f7a7d3dc1..06769a9ddc47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1219,7 +1219,7 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== @@ -1891,105 +1891,6 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@jimp/bmp@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" - integrity sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - bmp-js "^0.1.0" - -"@jimp/core@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" - integrity sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - any-base "^1.1.0" - buffer "^5.2.0" - exif-parser "^0.1.12" - file-type "^9.0.0" - load-bmfont "^1.3.1" - mkdirp "^0.5.1" - phin "^2.9.1" - pixelmatch "^4.0.2" - tinycolor2 "^1.4.1" - -"@jimp/custom@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" - integrity sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/core" "^0.16.1" - -"@jimp/gif@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" - integrity sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - gifwrap "^0.9.2" - omggif "^1.0.9" - -"@jimp/jpeg@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" - integrity sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - jpeg-js "0.4.2" - -"@jimp/plugin-resize@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" - integrity sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - -"@jimp/png@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" - integrity sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - pngjs "^3.3.3" - -"@jimp/tiff@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" - integrity sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ== - dependencies: - "@babel/runtime" "^7.7.2" - utif "^2.0.1" - -"@jimp/types@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" - integrity sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/bmp" "^0.16.1" - "@jimp/gif" "^0.16.1" - "@jimp/jpeg" "^0.16.1" - "@jimp/png" "^0.16.1" - "@jimp/tiff" "^0.16.1" - timm "^1.6.1" - -"@jimp/utils@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" - integrity sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw== - dependencies: - "@babel/runtime" "^7.7.2" - regenerator-runtime "^0.13.3" - "@jridgewell/resolve-uri@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" @@ -4085,7 +3986,7 @@ dependencies: "@types/node" "*" -"@types/lodash@^4.14.180", "@types/lodash@^4.14.53": +"@types/lodash@^4.14.180": version "4.14.180" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== @@ -4139,16 +4040,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== -"@types/node@16.9.1": - version "16.9.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" - integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== - -"@types/node@^10.11.7": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== - "@types/node@^16.0.0": version "16.11.26" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.26.tgz#63d204d136c9916fb4dcd1b50f9740fe86884e47" @@ -5057,11 +4948,6 @@ ansi2html@^0.0.1: resolved "https://registry.yarnpkg.com/ansi2html/-/ansi2html-0.0.1.tgz#bb8800461b440af00b91bf3d7366a5e0b8473ba8" integrity sha512-M5dw9xdPrRLkLnDjle8WkXCdzJtFAhoHPemopSt7CP9/a86pRhycK9gKHIBDxt2UW3E9pqvafOM6WgFSHyrffA== -any-base@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" - integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== - any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -5680,11 +5566,6 @@ blueimp-md5@^2.10.0: resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz#b53feea5498dcb53dc6ec4b823adb84b729c4af0" integrity sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w== -bmp-js@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233" - integrity sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw== - body-parser@1.19.2: version "1.19.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" @@ -5849,11 +5730,6 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== -buffer-equal@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" - integrity sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA== - buffer-es6@^4.9.3: version "4.9.3" resolved "https://registry.yarnpkg.com/buffer-es6/-/buffer-es6-4.9.3.tgz#f26347b82df76fd37e18bcb5288c4970cfd5c404" @@ -5879,7 +5755,7 @@ buffer-indexof@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.2.1, buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -7940,11 +7816,6 @@ dom-serializer@~0.1.0: domelementtype "^1.3.0" entities "^1.1.1" -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" @@ -8634,11 +8505,6 @@ execall@^2.0.0: dependencies: clone-regexp "^2.1.0" -exif-parser@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" - integrity sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw== - exit-on-epipe@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" @@ -9035,11 +8901,6 @@ file-type@^6.1.0: resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== -file-type@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" - integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw== - file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -9562,14 +9423,6 @@ gh-release-fetch@^3.0.0: node-fetch "^2.3.0" semver "^7.0.0" -gifwrap@^0.9.2: - version "0.9.4" - resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.4.tgz#f4eb6169ba027d61df64aafbdcb1f8ae58ccc0c5" - integrity sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ== - dependencies: - image-q "^4.0.0" - omggif "^1.0.10" - git-clone@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/git-clone/-/git-clone-0.2.0.tgz#9dce00facbab227d2562150052cd4a3a7ec15c41" @@ -9728,14 +9581,6 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -10524,13 +10369,6 @@ ignore@^5.1.8, ignore@^5.1.9, ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -image-q@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/image-q/-/image-q-4.0.0.tgz#31e075be7bae3c1f42a85c469b4732c358981776" - integrity sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw== - dependencies: - "@types/node" "16.9.1" - image-size@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.1.tgz#86d6cfc2b1d19eab5d2b368d4b9194d9e48541c5" @@ -10946,11 +10784,6 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - is-generator-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -11797,11 +11630,6 @@ joi@^17.6.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" -jpeg-js@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" - integrity sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw== - js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -12346,20 +12174,6 @@ listr@^0.14.3: p-map "^2.0.0" rxjs "^6.3.3" -load-bmfont@^1.3.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" - integrity sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA== - dependencies: - buffer-equal "0.0.1" - mime "^1.3.4" - parse-bmfont-ascii "^1.0.3" - parse-bmfont-binary "^1.0.5" - parse-bmfont-xml "^1.1.4" - phin "^2.9.1" - xhr "^2.0.1" - xtend "^4.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -13094,7 +12908,7 @@ mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, dependencies: mime-db "1.52.0" -mime@1.6.0, mime@^1.2.11, mime@^1.3.4: +mime@1.6.0, mime@^1.2.11: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -13129,13 +12943,6 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -13798,19 +13605,6 @@ node-version-alias@^1.0.1: path-exists "^4.0.0" semver "^7.3.2" -node-vibrant@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/node-vibrant/-/node-vibrant-3.1.6.tgz#8554c3108903232cbe1e722f928469ee4379aa18" - integrity sha512-Wlc/hQmBMOu6xon12ZJHS2N3M+I6J8DhrD3Yo6m5175v8sFkVIN+UjhKVRcO+fqvre89ASTpmiFEP3nPO13SwA== - dependencies: - "@jimp/custom" "^0.16.1" - "@jimp/plugin-resize" "^0.16.1" - "@jimp/types" "^0.16.1" - "@types/lodash" "^4.14.53" - "@types/node" "^10.11.7" - lodash "^4.17.20" - url "^0.11.0" - nodemon@^2.0.15: version "2.0.15" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e" @@ -14200,11 +13994,6 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -omggif@^1.0.10, omggif@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" - integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== - omit.js@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/omit.js/-/omit.js-2.0.2.tgz#dd9b8436fab947a5f3ff214cb2538631e313ec2f" @@ -14627,11 +14416,6 @@ pacote@^11.2.6: ssri "^8.0.1" tar "^6.1.0" -pako@^1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - parallel-transform@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" @@ -14663,24 +14447,6 @@ parent-module@^2.0.0: dependencies: callsites "^3.1.0" -parse-bmfont-ascii@^1.0.3: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" - integrity sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA== - -parse-bmfont-binary@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" - integrity sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA== - -parse-bmfont-xml@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389" - integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ== - dependencies: - xml-parse-from-string "^1.0.0" - xml2js "^0.4.5" - parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -14703,11 +14469,6 @@ parse-gitignore@^1.0.1: resolved "https://registry.yarnpkg.com/parse-gitignore/-/parse-gitignore-1.0.1.tgz#8b9dc57f17b810d495c5dfa62eb07caffe7758c7" integrity sha512-UGyowyjtx26n65kdAMWhm6/3uy5uSrpcuH7tt+QEVudiBoVS+eqHxD5kbi9oWVRwj7sCzXqwuM+rUGw7earl6A== -parse-headers@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" - integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -14880,11 +14641,6 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -phin@^2.9.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" - integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== - picocolors@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" @@ -14942,13 +14698,6 @@ pirates@^4.0.4, pirates@^4.0.5: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== -pixelmatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" - integrity sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA== - dependencies: - pngjs "^3.0.0" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -14984,11 +14733,6 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -pngjs@^3.0.0, pngjs@^3.3.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - portfinder@^1.0.28: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -15472,11 +15216,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -15587,11 +15326,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== - punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -15655,11 +15389,6 @@ query-string@^6.13.8: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -16224,7 +15953,7 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: +regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== @@ -16823,7 +16552,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@>=0.6.0, sax@^1.2.4: +sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -18299,11 +18028,6 @@ timed-out@^4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== -timm@^1.6.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f" - integrity sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw== - timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" @@ -18319,11 +18043,6 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tinycolor2@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" - integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== - tmp-promise@^3.0.2, tmp-promise@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" @@ -19096,14 +18815,6 @@ url-to-options@^1.0.1: resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" integrity sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A== -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use-composed-ref@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" @@ -19126,13 +18837,6 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -utif@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759" - integrity sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg== - dependencies: - pako "^1.0.5" - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -19933,16 +19637,6 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== -xhr@^2.0.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - xml-js@^1.6.11: version "1.6.11" resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" @@ -19955,24 +19649,6 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml-parse-from-string@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" - integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== - -xml2js@^0.4.5: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" From fa50d09d3b22190523ad21c353e42284dbd6b307 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 10:47:08 +0800 Subject: [PATCH 061/405] chore: upgrade dependencies (#6991) * chore: upgrade dependencies * fix --- admin/new.docusaurus.io/package.json | 2 +- package.json | 18 +- .../templates/classic-typescript/package.json | 2 +- .../docusaurus-cssnano-preset/package.json | 2 +- packages/docusaurus-plugin-pwa/package.json | 8 +- .../package.json | 2 +- packages/docusaurus-utils/package.json | 2 +- packages/docusaurus/package.json | 6 +- packages/lqip-loader/README.md | 2 - website/package.json | 6 +- yarn.lock | 985 +++++++++--------- 11 files changed, 511 insertions(+), 524 deletions(-) diff --git a/admin/new.docusaurus.io/package.json b/admin/new.docusaurus.io/package.json index 7da6bb95baca..16c6bd0abef5 100644 --- a/admin/new.docusaurus.io/package.json +++ b/admin/new.docusaurus.io/package.json @@ -9,6 +9,6 @@ "@netlify/functions": "^1.0.0" }, "devDependencies": { - "netlify-cli": "^9.13.3" + "netlify-cli": "^9.13.4" } } diff --git a/package.json b/package.json index 8a79ccd54c04..25f827aa4247 100644 --- a/package.json +++ b/package.json @@ -64,30 +64,30 @@ "@babel/core": "^7.17.8", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", - "@swc/core": "^1.2.159", + "@swc/core": "^1.2.160", "@swc/jest": "^0.2.20", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", "@types/lodash": "^4.14.180", - "@types/node": "^17.0.21", + "@types/node": "^17.0.23", "@types/prompts": "^2.0.14", - "@types/react": "^17.0.41", + "@types/react": "^17.0.43", "@types/react-dev-utils": "^9.0.10", "@types/react-test-renderer": "^17.0.1", "@types/semver": "^7.3.9", "@types/shelljs": "^0.8.11", - "@typescript-eslint/eslint-plugin": "^5.15.0", - "@typescript-eslint/parser": "^5.15.0", + "@typescript-eslint/eslint-plugin": "^5.16.0", + "@typescript-eslint/parser": "^5.16.0", "concurrently": "^7.0.0", "cross-env": "^7.0.3", - "cspell": "^5.19.2", + "cspell": "^5.19.3", "eslint": "^8.11.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^26.1.2", + "eslint-plugin-jest": "^26.1.3", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", @@ -99,7 +99,7 @@ "lerna": "^4.0.0", "lerna-changelog": "^2.2.0", "lint-staged": "^12.3.7", - "netlify-cli": "^9.13.3", + "netlify-cli": "^9.13.4", "nodemon": "^2.0.15", "prettier": "^2.6.0", "react": "^17.0.2", @@ -111,7 +111,7 @@ "stylelint": "^14.6.0", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard": "^25.0.0", - "typescript": "^4.6.2", + "typescript": "^4.6.3", "unified": "^9.2.1" } } diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json index e2990456ef03..acfd86d994c4 100644 --- a/packages/create-docusaurus/templates/classic-typescript/package.json +++ b/packages/create-docusaurus/templates/classic-typescript/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.17", "@tsconfig/docusaurus": "^1.0.5", - "typescript": "^4.6.2" + "typescript": "^4.6.3" }, "browserslist": { "production": [ diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index cbf900d5c1aa..b42011147953 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -13,7 +13,7 @@ "directory": "packages/docusaurus-cssnano-preset" }, "dependencies": { - "cssnano-preset-advanced": "^5.3.0", + "cssnano-preset-advanced": "^5.3.1", "postcss": "^8.4.12", "postcss-sort-media-queries": "^4.2.1" }, diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json index 13559f33a9c8..0c29557a51bb 100644 --- a/packages/docusaurus-plugin-pwa/package.json +++ b/packages/docusaurus-plugin-pwa/package.json @@ -27,16 +27,16 @@ "@docusaurus/theme-translations": "2.0.0-beta.17", "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-validation": "2.0.0-beta.17", - "babel-loader": "^8.2.3", + "babel-loader": "^8.2.4", "clsx": "^1.1.1", "core-js": "^3.21.1", "terser-webpack-plugin": "^5.3.1", "tslib": "^2.3.1", "webpack": "^5.70.0", "webpack-merge": "^5.8.0", - "workbox-build": "^6.5.1", - "workbox-precaching": "^6.5.1", - "workbox-window": "^6.5.1" + "workbox-build": "^6.5.2", + "workbox-precaching": "^6.5.2", + "workbox-window": "^6.5.2" }, "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.17", diff --git a/packages/docusaurus-theme-search-algolia/package.json b/packages/docusaurus-theme-search-algolia/package.json index 272032d0cb24..6f47d1110da8 100644 --- a/packages/docusaurus-theme-search-algolia/package.json +++ b/packages/docusaurus-theme-search-algolia/package.json @@ -34,7 +34,7 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-validation": "2.0.0-beta.17", "algoliasearch": "^4.13.0", - "algoliasearch-helper": "^3.7.3", + "algoliasearch-helper": "^3.7.4", "clsx": "^1.1.1", "eta": "^1.12.3", "fs-extra": "^10.0.1", diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index 1988edc6155c..df9eb8ef298d 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -27,7 +27,7 @@ "gray-matter": "^4.0.3", "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "micromatch": "^4.0.4", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", "shelljs": "^0.8.5", "tslib": "^2.3.1", diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index dc2c41e0cc69..0164015184df 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -39,7 +39,7 @@ "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", "@babel/runtime": "^7.17.8", - "@babel/runtime-corejs3": "^7.17.7", + "@babel/runtime-corejs3": "^7.17.8", "@babel/traverse": "^7.17.3", "@docusaurus/cssnano-preset": "2.0.0-beta.17", "@docusaurus/logger": "2.0.0-beta.17", @@ -51,7 +51,7 @@ "@slorber/static-site-generator-webpack-plugin": "^4.0.4", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.4", - "babel-loader": "^8.2.3", + "babel-loader": "^8.2.4", "babel-plugin-dynamic-import-node": "2.3.0", "boxen": "^6.2.1", "chokidar": "^3.5.3", @@ -63,7 +63,7 @@ "core-js": "^3.21.1", "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", - "cssnano": "^5.1.4", + "cssnano": "^5.1.5", "del": "^6.0.0", "detect-port": "^1.3.0", "escape-html": "^1.0.3", diff --git a/packages/lqip-loader/README.md b/packages/lqip-loader/README.md index a0e2f889023e..458ff3654d49 100644 --- a/packages/lqip-loader/README.md +++ b/packages/lqip-loader/README.md @@ -67,8 +67,6 @@ img { More history about the issue can be [found here](https://bugs.chromium.org/p/chromium/issues/detail?id=771110#c3) and [here](https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/6L_3ZZeuA0M). -Alternatively, you can fill the container with a really cheap colour or gradient from the amazing palette we provide. - ## Credits This package has been imported from [`@endiliey/lqip-loader`](https://github.com/endiliey/lqip-loader) which was a fork of the original [`lqip-loader`](https://github.com/zouhir/lqip-loader) created exclusively for Docusaurus. diff --git a/website/package.json b/website/package.json index aeb0c1f833da..2323ae995ee4 100644 --- a/website/package.json +++ b/website/package.json @@ -49,7 +49,7 @@ "@docusaurus/utils": "2.0.0-beta.17", "@docusaurus/utils-common": "2.0.0-beta.17", "@popperjs/core": "^2.11.4", - "@swc/core": "^1.2.159", + "@swc/core": "^1.2.160", "clsx": "^1.1.1", "color": "^4.2.1", "fs-extra": "^10.0.1", @@ -63,8 +63,8 @@ "remark-math": "^3.0.1", "swc-loader": "^0.1.15", "unist-util-visit": "^2.0.2", - "workbox-routing": "^6.5.1", - "workbox-strategies": "^6.5.1" + "workbox-routing": "^6.5.2", + "workbox-strategies": "^6.5.2" }, "browserslist": { "production": [ diff --git a/yarn.lock b/yarn.lock index 06769a9ddc47..3201f262349f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1211,7 +1211,7 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.7": +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.8": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== @@ -1332,25 +1332,25 @@ dependencies: axios "0.21.3" -"@cspell/cspell-bundled-dicts@^5.19.2": - version "5.19.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.2.tgz#c20d05d0ff5f3850bb62a32a95e05abd94673936" - integrity sha512-R+12xDw5iLCJH3O0n8t1D7acZrO/bjuULU3rs3CEt+i84/85b27shywc3E/vOiOt9613bpFNOL52J27Tu52YPQ== +"@cspell/cspell-bundled-dicts@^5.19.3": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.3.tgz#826e166eb56f193c2d770575adfbb1557816f1af" + integrity sha512-YAz68AgXTFFtrBUhNJlOQ7KOjUE6ncYt578/esa2GStMJHgJoUtPnOZsE41hh+cVWXqO5yRRI+Qkwub99zLMgQ== dependencies: "@cspell/dict-ada" "^2.0.0" "@cspell/dict-aws" "^2.0.0" "@cspell/dict-bash" "^2.0.1" - "@cspell/dict-companies" "^2.0.2" + "@cspell/dict-companies" "^2.0.3" "@cspell/dict-cpp" "^2.0.0" "@cspell/dict-cryptocurrencies" "^2.0.0" "@cspell/dict-csharp" "^2.0.1" "@cspell/dict-css" "^2.0.0" "@cspell/dict-dart" "^1.1.0" "@cspell/dict-django" "^2.0.0" - "@cspell/dict-dotnet" "^2.0.0" + "@cspell/dict-dotnet" "^2.0.1" "@cspell/dict-elixir" "^2.0.1" "@cspell/dict-en-gb" "^1.1.33" - "@cspell/dict-en_us" "^2.1.7" + "@cspell/dict-en_us" "^2.2.0" "@cspell/dict-filetypes" "^2.0.1" "@cspell/dict-fonts" "^2.0.0" "@cspell/dict-fullstack" "^2.0.4" @@ -1372,20 +1372,20 @@ "@cspell/dict-ruby" "^2.0.1" "@cspell/dict-rust" "^2.0.0" "@cspell/dict-scala" "^2.0.0" - "@cspell/dict-software-terms" "^2.1.3" + "@cspell/dict-software-terms" "^2.1.4" "@cspell/dict-swift" "^1.0.2" "@cspell/dict-typescript" "^2.0.0" "@cspell/dict-vue" "^2.0.2" -"@cspell/cspell-pipe@^5.19.2": - version "5.19.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.19.2.tgz#40bf46fae7aa0697f9ab9e36d165fe149b9b5f36" - integrity sha512-mFFSn4ZgNgIOM0iBT0+xKBhRTQd/ecrWVvPfJpHxXIFwTt0neD19hqK54RDedLf8Hjds5cBHvS1EjMNARju/bQ== +"@cspell/cspell-pipe@^5.19.3": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.19.3.tgz#af818c0362786f61ac8741947e1819f94b55ec3b" + integrity sha512-3RKntgGRxYYzoxoH3VBPvnNMYkHKPq0U+U7qogcWxDkgAUgKXlBP0oc2mw96grJQ4HIzOL1vBnaVAWAqteY9Kw== -"@cspell/cspell-types@^5.19.2": - version "5.19.2" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.19.2.tgz#faae04c918dca53d6a266d86d00c3bd1682ebe16" - integrity sha512-IkMQpa7IzoFm9NXzRz8Gp38f3aoMZf6xjT7J3FvWtIntPvkIFaY53R1/I9U/gujH/zflf2VmZGxoDuFg1VcD0g== +"@cspell/cspell-types@^5.19.3": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.19.3.tgz#37a64db00e33a1c8bb8aa3bf86d503689b3afbf5" + integrity sha512-tub7PW/I6qB6o+ZtlahAZjm5O5cnzj88HRiC8nAbJFpa7q0mrdpFMYhd7ksWtyFLlNbuDkCsfzXGamAhIQnnIw== "@cspell/dict-ada@^2.0.0": version "2.0.0" @@ -1402,10 +1402,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-bash/-/dict-bash-2.0.1.tgz#76f6be974e9a968235d4e1b04c4ae76b16169057" integrity sha512-pBx3T/5w7fPF8XD5cx3NwtRFvNpQYmYqzM043NKP2hDmlx4uFwbH599Lvt5mwCMZKfIoRXaNUQvq7se2gstQjw== -"@cspell/dict-companies@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-2.0.2.tgz#de315b8315b868f877e6161f9fe70e8efc769931" - integrity sha512-LPKwBMAWRz+p1R8q+TV6E1sGOOTvxJOaJeXNN++CZQ7i6JMn5Rf+BSxagwkeK6z3o9vIC5ZE4AcQ5BMkvyjqGw== +"@cspell/dict-companies@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-2.0.3.tgz#9e0f93a2cc884ff0b98d019123d1dbfb853da872" + integrity sha512-O622rMAaHm85AmqNyMki5je8HB/1XlTKbGOXh2UUhooI5qdgdfrjTQ6VBuHwHrfEfuODBHYTNYXVB2m23XqHCg== "@cspell/dict-cpp@^2.0.0": version "2.0.0" @@ -1437,10 +1437,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-2.0.0.tgz#a5f5f693a686e5873f9dfb547ee3b3142ef760b1" integrity sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw== -"@cspell/dict-dotnet@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-2.0.0.tgz#92729d95a71b9f72bf264fbba0c66a7b29f3993a" - integrity sha512-WOHfjwMuLbo76khDsDa1lJvP/dXcwXVwonWwfUFRt82BL/GtyMalh1HEtCWwKDuK/9f8PCEt/EZMkHT3D5ZV3w== +"@cspell/dict-dotnet@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz#8ef56df758b63f0a2ba4d8681a427a6861ed34d5" + integrity sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ== "@cspell/dict-elixir@^2.0.1": version "2.0.1" @@ -1452,10 +1452,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== -"@cspell/dict-en_us@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-2.1.7.tgz#1acb710b72364898a832b300d3e77211027efac0" - integrity sha512-7IeAHZjXiWSIKFx/3CIlY6misvg2KyJ2KO3tSVSKuAlC3UXHGVOcbcY0kQ95IJeKbB6Ot6aW/Aaw73Nzhuurrg== +"@cspell/dict-en_us@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-2.2.0.tgz#33ee50fac4c42036ce98b9c9925cc86b16b0f2c3" + integrity sha512-IJWu8MI2NdLyPzekrMi9K+v71b0qjDE+z/BccoMA/APnphqgSNM8BDUAzhio6mPKi1AvPRCNUjk79oiUfp+1Gw== "@cspell/dict-filetypes@^2.0.1": version "2.0.1" @@ -1562,10 +1562,10 @@ resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-2.0.0.tgz#b8098103bb03a13406c1c79f1769052353aafac4" integrity sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g== -"@cspell/dict-software-terms@^2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-2.1.3.tgz#033f93d4cfa03e21b03ad0861ee74560b204a841" - integrity sha512-JmMfRa9Xl0MCD/z5gYUnY05BNxSMnx25Ky6kO/Cs0gBYZZdYzHZNqrbfnqBMsB9PpOzn2uqrYUmAEusoI1WyMQ== +"@cspell/dict-software-terms@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-2.1.4.tgz#4a3e1d62abcaa237b98510638e279bae7712e97f" + integrity sha512-MB2eT9qhbnIEJajGv+ndzzi6S8NCJ9cMyeGJYMoRAiJobTKP6xPrT37VjPzhckRtrHJGG//UgtQ4NsiK5aBITw== "@cspell/dict-swift@^1.0.2": version "1.0.2" @@ -2652,9 +2652,9 @@ glob-to-regexp "^0.3.0" "@netlify/build@^26.5.0": - version "26.5.0" - resolved "https://registry.yarnpkg.com/@netlify/build/-/build-26.5.0.tgz#f5fa412e917a348c70bce6e0c19fab33ea20dfd4" - integrity sha512-aF6H6CnWcggf5ObDYMzreGq9tKtny95Ys9GhxCMxoQxfhcw3kab984Xj1epk3wlKNt1vJbZ3bndlme3LDG/cOg== + version "26.5.1" + resolved "https://registry.yarnpkg.com/@netlify/build/-/build-26.5.1.tgz#cce2d91740af7a46d022dd8dd5ee693bb811c45b" + integrity sha512-sqS/7zyJwp48f1nsKJ9XaZF8FSoJpdCp1EH2g5777rc0hGyYC1AFX0NaJnT3weN47VjsLkaxcfHBUvwo6lyEJw== dependencies: "@bugsnag/js" "^7.0.0" "@netlify/cache-utils" "^4.0.0" @@ -2662,7 +2662,7 @@ "@netlify/functions-utils" "^4.0.0" "@netlify/git-utils" "^4.0.0" "@netlify/plugin-edge-handlers" "^3.0.7" - "@netlify/plugins-list" "^6.16.0" + "@netlify/plugins-list" "^6.17.0" "@netlify/run-utils" "^4.0.0" "@netlify/zip-it-and-ship-it" "5.9.0" "@sindresorhus/slugify" "^2.0.0" @@ -2726,9 +2726,9 @@ readdirp "^3.4.0" "@netlify/config@^17.0.0", "@netlify/config@^17.0.18": - version "17.0.18" - resolved "https://registry.yarnpkg.com/@netlify/config/-/config-17.0.18.tgz#c083b7e17a04cd2a6e9b53c519fb14dfd0e1403c" - integrity sha512-iHTCjGtqxwKHMxiN6sbh54u0Zn4VTTZmjjnkNABJ8PwtwyDFFbe2JkFLM7LkikKG0PwP8CeExy+0J+bDTD9RSw== + version "17.0.19" + resolved "https://registry.yarnpkg.com/@netlify/config/-/config-17.0.19.tgz#f1d7a1bc8d005ad188c2f58d6064bfaaf36d057c" + integrity sha512-GH2fKuqmNt+syuQrWIejB0FqkPZWo1/M1AmiZbcYMHh9oQFnBKo+OixD0BPl66HFKd4/rPKqqwaSg/xZ3Y9mKg== dependencies: chalk "^5.0.0" cron-parser "^4.1.0" @@ -2743,7 +2743,7 @@ is-plain-obj "^4.0.0" js-yaml "^4.0.0" map-obj "^5.0.0" - netlify "^11.0.0" + netlify "^11.0.1" netlify-headers-parser "^6.0.2" netlify-redirect-parser "13.0.5" omit.js "^2.0.2" @@ -2905,10 +2905,10 @@ rollup-plugin-node-polyfills "^0.2.1" rollup-plugin-terser "^7.0.2" -"@netlify/plugins-list@^6.16.0", "@netlify/plugins-list@^6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.16.1.tgz#6e8ba9fad984133c4492959a054b93e5a61537f8" - integrity sha512-DCgAJvCniSmXghDVvWSa5dgAWYVpOUfRLTVvv0V/GXDd1VkvpHtmZ0FD+AE8hxqSfmY8FLuagh6USi8xeBfwaA== +"@netlify/plugins-list@^6.17.0": + version "6.17.0" + resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.17.0.tgz#fd6ff86a81de0f2b4bc14ec2f0f5f9431ec54bd6" + integrity sha512-XQMijnVOxbZwkOeSzUZ8Hwon8WIv9uka5R6+mjJs25lcFiTscA8HqHWjhSHf2xPSrcKopJm4BNJZja5YHV3NQg== "@netlify/routing-local-proxy-darwin-arm64@^0.34.1": version "0.34.1" @@ -3285,9 +3285,9 @@ any-observable "^0.3.0" "@sideway/address@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" - integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== dependencies: "@hapi/hoek" "^9.0.0" @@ -3486,89 +3486,89 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" -"@swc/core-android-arm-eabi@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.159.tgz#020b3a018ba912d90f0630ca8171cb1993377433" - integrity sha512-OIHGUjHIgow0TRWQpoKzAKAzdOmZPK/aVSkctWdMJvAc0Oj6yxlj35UfOtdifJJxRej/KEMZpFeQTJ69ezycuQ== - -"@swc/core-android-arm64@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.159.tgz#438c396b01d4371e36ac4ff2f917e425df927a7b" - integrity sha512-zKMq4/a62usmD+CTEpyNNN57LBGHJMK2s2KDcU7Vu/tHoHKGkFYQi7PYBw3t6+tCyPfwoo20NONOiYZv6dm36Q== - -"@swc/core-darwin-arm64@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.159.tgz#58eb17200621c29ff5757f43478c87bab5166e0b" - integrity sha512-vZJmK7Baph2UCUIrArEt4RxnvK87OF8TSUe8VNgYPIFtoCEA6ttKXnndCI5kUKPvakpAg4NoHs1mm/x7gVZVVQ== - -"@swc/core-darwin-x64@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.159.tgz#fcf7ce53024c16255e91d10980fbda6799cc3476" - integrity sha512-hhJ336eq9QMv8PTnrCfY99xhdf8LH8RquLLfVV+XwbeXGF23fJJrsjQgv9rTC5aadIh6AxR2cHgCm4CGU/Xs0w== - -"@swc/core-freebsd-x64@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.159.tgz#84411aa22ac584e2141cfb8de249cd9e52204084" - integrity sha512-ZwJcA38AEmQp4OCkYOZD/5FjSU1VEMX/iMISEGUwDEE7d4CypFFP3mCpk5JAVEWJIhdYjgfo2SY8v9PfoSmBDg== - -"@swc/core-linux-arm-gnueabihf@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.159.tgz#744fad70e871ac045867b5a4eb76d216d86b6b69" - integrity sha512-M1QF8BBrbuXkw+T8U4xjMhGvjog83pA40PfZknGk+czQFJcNo4mq5hxMPalRbLN6olMoZNI6EM5a6zSocoDXEg== - -"@swc/core-linux-arm64-gnu@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.159.tgz#ab324d79871ba4414e84a9e7e1c7399483079c39" - integrity sha512-1uCMSEfzXtJHnuQoYHuHvzmBQ4/YlEcPydRMpc8/nO/svRGAHUZPKIz887tNk0nVtlF4Kil/LTrG+Wqxrp9z7A== - -"@swc/core-linux-arm64-musl@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.159.tgz#a9f957666ea2603ce7865cf9ff91ce63c1ffbe7c" - integrity sha512-FE+LyayWD55ESq0bV40x+Lmse7UyI/hhfrO/wvEs3v97z+fRhzPvcPAw38MoW2DVazPw3GotuBIf6Y5XkFO+fg== - -"@swc/core-linux-x64-gnu@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.159.tgz#36d5483673a96649ac5898a3b4b864b3b036f536" - integrity sha512-O7pH2A+ENjCuvMuKjv6UoIBsmwAbrTi+45WFL1snqCDZw+4p3WutFUSlhEW72uI6CEdb4kfZG0lajW2/Qbkuvg== - -"@swc/core-linux-x64-musl@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.159.tgz#a74d026cdd59118b348c0cd2c2d889d2bea67ec5" - integrity sha512-Se1EccOiN4h8/SaTZFVp7VoSUNR7ENmAmpVNROKnfZGb589THpLlC5MZtp5EFYDaLjpLHypVeqw0OO4tgwsL4w== - -"@swc/core-win32-arm64-msvc@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.159.tgz#18488c44e09ad659cc9696ccd481f2dfd013ba61" - integrity sha512-nKv1ksT3+V3xhPRXFr5Eeg0b93dqpGzKIoC13WwC0jRYbD0/SZwwcTU/XUZcm4MWQI8CG+PwwhO3SLMo747eqw== - -"@swc/core-win32-ia32-msvc@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.159.tgz#2c22f15303a133f6651f6b89e360e00a7f23eb17" - integrity sha512-24khotmSwFF2rEUeXPdqaTSOrIylroEx8MfuyG1BxfYfol+B9QyG8YqDyz713YM9dJYgs7JKuSfkK8qGQ2MbYA== - -"@swc/core-win32-x64-msvc@1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.159.tgz#f6c052ea50cb026c3af0993a46e018c3cbc42da8" - integrity sha512-Z/hcfe1DRcOQgnxZcnYy8d4lxZi1IHI2FeeRwDWtKn28cSaPca1acZVb4qA0hSfqsftKo0zTgLro6oh9gWxFng== - -"@swc/core@^1.2.159": - version "1.2.159" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.159.tgz#e4c884a00c34c9b0ce4d2669d75b3f5d1c87aea9" - integrity sha512-y+z+c4IelqaxvpQrc8hYdEpuvP1BVS9Fe5t8P8/yyP1oSrJkrLibROX4dHujg4EekFQhPCUjA29NawC4D08IQA== +"@swc/core-android-arm-eabi@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.160.tgz#f5aaf852e9d104b4ad58d34851bac3bd41a64a60" + integrity sha512-VzFP7tYgvpkUhd8wgyNtERqvoPBBDretyMFxAxPe2SxClaBs9Ka95PdiPPZalRq+vFCb/dFxD8Vhz+XO16Kpjg== + +"@swc/core-android-arm64@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.160.tgz#458f7e6aff52958e0764c34500528c18bbb31894" + integrity sha512-m+xqQaa7TqW3Vm9MUvITtdU8OlAc/9yT+TgOS4l8WlfFI87IDnLLfinKKEp+xfKwzYDdIsh+sC+jdGdIBTMB+Q== + +"@swc/core-darwin-arm64@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.160.tgz#34d48b449de0eae9fddd71b064d36aa5353f22cc" + integrity sha512-9bG70KYKvjNf7tZtjOu1h4kDZPtoidZptIXPGSHuUgJ1BbSJYpfRR5xAmq4k37+GqOjIPJp4+lSGQPa2HfejpA== + +"@swc/core-darwin-x64@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.160.tgz#109d92457df928717c73055f01c99ca88815000d" + integrity sha512-+b4HdKAVf/XPZ9DjgG2axGLbquPEuYwEP3zeWgbWn0s0FYQ7WTFxznf3YrTJE9MYadJeCOs3U80E2xVAtRRS9Q== + +"@swc/core-freebsd-x64@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.160.tgz#debdccce0129aa856e496f06981cc8e8271fcb41" + integrity sha512-E5agJwv+RVMoZ8FQIPSO5wLPDQx6jqcMpV207EB3pPaxPWGe4n3DH3vcibHp80RACDNdiaqo5lBeBnGJI4ithw== + +"@swc/core-linux-arm-gnueabihf@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.160.tgz#27669f1084c152153c017fc320b6a92cd6b71244" + integrity sha512-uCttZRNx+lWVhCYGC6/pGUej08g1SQc5am6R9NVFh111goytcdlPnC4jV8oWzq2QhDWkkKxLoP2CZOytzI4+0w== + +"@swc/core-linux-arm64-gnu@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.160.tgz#a8ecadee30639c298e9c2175099d55c1c82f912e" + integrity sha512-sB18roiv8m/zsY6tXLSrbUls0eKkSkxOEF0ennXVEtz97rMJ+WWnkOc8gI+rUpj3MHbVAIxyDNyyZU4cH5g1jQ== + +"@swc/core-linux-arm64-musl@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.160.tgz#1a2cf738c8a394fcb21fe91f13b1fb9c775cca0b" + integrity sha512-PJ7Ukb+BRR3pGYcUag8qRWOB11eByc5YLx/xAMSc3bRmaYW/oj6s8k+1DYiR//BAuNQdf14MpMFzDuWiDEUh7A== + +"@swc/core-linux-x64-gnu@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.160.tgz#f54c4e0510b69d68f56e681050b717991627ad68" + integrity sha512-wVh8Q86xz3t0y5zoUryWQ64bFG/YxdcykBgaog8lU9xkFb1KSqVRE9ia7aKA12/ZtAfpJZLRBleZxBAcaCg9FQ== + +"@swc/core-linux-x64-musl@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.160.tgz#6f8ec092d8b65a9750faf0a2323b52f39c5bd540" + integrity sha512-AnWdarl9WWuDdbc2AX1w76W1jaekSCokxRrWdSGUgQytaZRtybKZEgThvJCQDrSlYQD4XDOhhVRCurTvy4JsfQ== + +"@swc/core-win32-arm64-msvc@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.160.tgz#b4f226ab86e550762b5cc83d0ebe4cf43f1a3624" + integrity sha512-ScL27mZRTwEIqBIv9RY34nQvyBvhosiM5Lus4dCFmS71flPcAEv7hJgy4GE3YUQV0ryGNK9NaO43H8sAyNwKVQ== + +"@swc/core-win32-ia32-msvc@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.160.tgz#243bb5b15eab76f4c8f004381d63c6d72a8cef68" + integrity sha512-e75zbWlhlyrd5HdrYzELa6OlZxgyaVpJj+c9xMD95HcdklVbmsyt1vuqRxMyqaZUDLyehwwCDRX/ZeDme//M/A== + +"@swc/core-win32-x64-msvc@1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.160.tgz#8708986433e891687bb4a836a683f90bc95e1fce" + integrity sha512-GAYT+WzYQY4sr17S21yJh4flJp/sQ62mAs6RfN89p7jIWgm0Bl/SooRl6ocsftTlnZm7K7QC8zmQVeNCWDCLPw== + +"@swc/core@^1.2.160": + version "1.2.160" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.160.tgz#d91730a5021d4c8aef87855dde11fc8931496176" + integrity sha512-nXoC7HA+aY7AtBPsiqGXocoRLAzzA7MV+InWQtILN7Uru4hB9+rLnLCPc3zSdg7pgnxJLa1tHup1Rz7Vv6TcIQ== optionalDependencies: - "@swc/core-android-arm-eabi" "1.2.159" - "@swc/core-android-arm64" "1.2.159" - "@swc/core-darwin-arm64" "1.2.159" - "@swc/core-darwin-x64" "1.2.159" - "@swc/core-freebsd-x64" "1.2.159" - "@swc/core-linux-arm-gnueabihf" "1.2.159" - "@swc/core-linux-arm64-gnu" "1.2.159" - "@swc/core-linux-arm64-musl" "1.2.159" - "@swc/core-linux-x64-gnu" "1.2.159" - "@swc/core-linux-x64-musl" "1.2.159" - "@swc/core-win32-arm64-msvc" "1.2.159" - "@swc/core-win32-ia32-msvc" "1.2.159" - "@swc/core-win32-x64-msvc" "1.2.159" + "@swc/core-android-arm-eabi" "1.2.160" + "@swc/core-android-arm64" "1.2.160" + "@swc/core-darwin-arm64" "1.2.160" + "@swc/core-darwin-x64" "1.2.160" + "@swc/core-freebsd-x64" "1.2.160" + "@swc/core-linux-arm-gnueabihf" "1.2.160" + "@swc/core-linux-arm64-gnu" "1.2.160" + "@swc/core-linux-arm64-musl" "1.2.160" + "@swc/core-linux-x64-gnu" "1.2.160" + "@swc/core-linux-x64-musl" "1.2.160" + "@swc/core-win32-arm64-msvc" "1.2.160" + "@swc/core-win32-ia32-msvc" "1.2.160" + "@swc/core-win32-x64-msvc" "1.2.160" "@swc/jest@^0.2.20": version "0.2.20" @@ -4035,10 +4035,10 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@^17.0.21", "@types/node@^17.0.5": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== +"@types/node@*", "@types/node@^17.0.23", "@types/node@^17.0.5": + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/node@^16.0.0": version "16.11.26" @@ -4158,10 +4158,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.41": - version "17.0.41" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.41.tgz#6e179590d276394de1e357b3f89d05d7d3da8b85" - integrity sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA== +"@types/react@*", "@types/react@>=16.9.0", "@types/react@^17.0.43": + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -4388,14 +4388,14 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a" - integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA== +"@typescript-eslint/eslint-plugin@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" + integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== dependencies: - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/type-utils" "5.15.0" - "@typescript-eslint/utils" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/type-utils" "5.16.0" + "@typescript-eslint/utils" "5.16.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -4403,30 +4403,30 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728" - integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ== +"@typescript-eslint/parser@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" + integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== dependencies: - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/typescript-estree" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee" - integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg== +"@typescript-eslint/scope-manager@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" + integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== dependencies: - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/visitor-keys" "5.15.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" -"@typescript-eslint/type-utils@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248" - integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA== +"@typescript-eslint/type-utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" + integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== dependencies: - "@typescript-eslint/utils" "5.15.0" + "@typescript-eslint/utils" "5.16.0" debug "^4.3.2" tsutils "^3.21.0" @@ -4435,18 +4435,18 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501" - integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA== +"@typescript-eslint/types@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" + integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== -"@typescript-eslint/typescript-estree@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac" - integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA== +"@typescript-eslint/typescript-estree@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" + integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== dependencies: - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/visitor-keys" "5.15.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -4466,15 +4466,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.15.0", "@typescript-eslint/utils@^5.10.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136" - integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA== +"@typescript-eslint/utils@5.16.0", "@typescript-eslint/utils@^5.10.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" + integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/typescript-estree" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -4486,12 +4486,12 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027" - integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ== +"@typescript-eslint/visitor-keys@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" + integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== dependencies: - "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/types" "5.16.0" eslint-visitor-keys "^3.0.0" "@vercel/nft@^0.17.0": @@ -4798,19 +4798,19 @@ ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.0.1, ajv@^8.6.0, ajv@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" uri-js "^4.2.2" -algoliasearch-helper@^3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.3.tgz#4da9e68591e02bf6accb6a77b0c2d2ecefab5c07" - integrity sha512-ra+SYf+R9bFdnBVMDYxjzdX246k4LtaeTPxww9EodnQcOSKn35TOb1/LOj1nIPZla/LjDr7wczVFqeH85O9kpg== +algoliasearch-helper@^3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.4.tgz#3812ea161da52463ec88da52612c9a363c1b181d" + integrity sha512-KmJrsHVm5TmxZ9Oj53XdXuM4CQeu7eVFnB15tpSFt+7is1d1yVCv3hxCLMqYSw/rH42ccv013miQpRr268P8vw== dependencies: "@algolia/events" "^4.0.1" @@ -5320,13 +5320,13 @@ babel-jest@^27.5.1: graceful-fs "^4.2.9" slash "^3.0.0" -babel-loader@^8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -5665,7 +5665,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -5955,9 +5955,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: - version "1.0.30001319" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz#eb4da4eb3ecdd409f7ba1907820061d56096e88f" - integrity sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw== + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== caseless@~0.12.0: version "0.12.0" @@ -6521,7 +6521,7 @@ commander@^8.0.0, commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -commander@^9.0.0: +commander@^9.0.0, commander@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.1.0.tgz#a6b263b2327f2e188c6402c42623327909f2dbec" integrity sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w== @@ -7004,41 +7004,41 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -cspell-gitignore@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.19.2.tgz#8a364a18fbeef7b35356f2537933ea4fc1761063" - integrity sha512-j0iMQoLmq4J/19hM0j0rNUQoHsw1b9Yg1AZMus8WJgABPUPGgk4fRKJChUQu0+ys3wwWT/4vhKt7hU89ScphJQ== +cspell-gitignore@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.19.3.tgz#c27780dc1b43cb48705dc3695c3875f001d7b038" + integrity sha512-Q67uHcf0qNgOoanRLhatapjWpLiftT+MuLIyAaSLe5eNVzQurQIc+UnXhtaslkVyOTqQt4NJFqLgtf5ZSGz1bg== dependencies: - cspell-glob "^5.19.2" + cspell-glob "^5.19.3" find-up "^5.0.0" -cspell-glob@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.19.2.tgz#57a208bbb583d8385403d35fa2f1a1351b50e883" - integrity sha512-23pgM0KzWsnNv6zwC/xnxdE86MfLU7NWbBqDmn1KixhJjezOhg/LiSjnJuRVUuLR+4qApzjrBRpk+Rj1jzYi6A== +cspell-glob@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.19.3.tgz#f6b423523a0c2d77d244ecfc7c48ef320f4d122a" + integrity sha512-qp2Oe/euzTu3e0zZrQxHuTrqRo418tYfh4CnCa+DKU6lWKKcF4zCEhOGJHPsYak8SFIXZ4ZE360wHFxB/JDutQ== dependencies: micromatch "^4.0.4" -cspell-io@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.19.2.tgz#32ae634cccc73c8a0b8f1c83038301fbe137c85f" - integrity sha512-TLlXMmDdZQold3ZsbHEpwKjUIRtYksp7Qr9Z0Rt9JpII6riliUPdB0SMFgtrqAvV1+bhJEPPmSxts8SdtLkdnA== +cspell-io@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.19.3.tgz#89ab249dc53206651a7833399a83b04a7d8a8a63" + integrity sha512-dE9eBvHgIJ11DelWtyehMU3W3bCpcB+0nS6uOZJ2d8fDu13m5BebpLrXZ2dKfY4cjksJUhRPatt14uwQSeUp2A== -cspell-lib@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.19.2.tgz#678ade6f3217e0ca3bb12efca55871912d90d2ff" - integrity sha512-x8NhOiXKRj6PHQty9RmaujE8dywzX0ZJr6AlPE/0N8IHmOg0Y8gAs7aN45l3PjFz+vaWfCghPbCIyxE/fdXNaw== +cspell-lib@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.19.3.tgz#6efc9ee5620d427e2f20c000b60a3b3d0ce6cd4c" + integrity sha512-peMJggwJpxCXKZZ0DuHyDtZmf66POKaHf5Im8LGEyMKFARUIq6O2WvaUGggYjyRe3Ng/f5G+EYTcIHbF9pZYcg== dependencies: - "@cspell/cspell-bundled-dicts" "^5.19.2" - "@cspell/cspell-pipe" "^5.19.2" - "@cspell/cspell-types" "^5.19.2" + "@cspell/cspell-bundled-dicts" "^5.19.3" + "@cspell/cspell-pipe" "^5.19.3" + "@cspell/cspell-types" "^5.19.3" clear-module "^4.1.2" comment-json "^4.2.2" configstore "^5.0.1" cosmiconfig "^7.0.1" - cspell-glob "^5.19.2" - cspell-io "^5.19.2" - cspell-trie-lib "^5.19.2" + cspell-glob "^5.19.3" + cspell-io "^5.19.3" + cspell-trie-lib "^5.19.3" fast-equals "^3.0.0" find-up "^5.0.0" fs-extra "^10.0.1" @@ -7049,27 +7049,27 @@ cspell-lib@^5.19.2: vscode-languageserver-textdocument "^1.0.4" vscode-uri "^3.0.3" -cspell-trie-lib@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.19.2.tgz#4573f897de9ad1200390c14b73d43066acdf8746" - integrity sha512-JCPBuA6XtIRuMZtIzRAV/nk/NmTQwxcQA4GEAkdxYZ9aUPTpMDItxQkrKrlEvAuqt8hKZkOpE6ZpChdLW7aKsg== +cspell-trie-lib@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.19.3.tgz#0a0f8d9300f95188f2f2b1831bd7fea2e9c9d6ee" + integrity sha512-Io8EB7E1pmttHzZvgvPEF0b87qlq8G5uA4B+sbqCxrUf5l4JDcK/UYLih0+rekLTbv4Q68zqgCTASvqxgqnoAg== dependencies: - "@cspell/cspell-pipe" "^5.19.2" + "@cspell/cspell-pipe" "^5.19.3" fs-extra "^10.0.1" gensequence "^3.1.1" -cspell@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.19.2.tgz#79de5ab9335b089058fb9765fbdf39aebade3aa7" - integrity sha512-HqjwOZ5iJ4WBfl6TfQkGXax0uYVL3SI9XAsstFs7yQW+6/DwjgvR7GFTkGH+rZgN5hdGZPk81NYbfNLm0uyKCQ== +cspell@^5.19.3: + version "5.19.3" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.19.3.tgz#0f2c6cf529fb3f0b721b380f81b04e9c22272c05" + integrity sha512-JJBH8iqtHYmxqLQZ+7GAMTVvc6SAoHVgn1tdYknOI2/uxAbZVH29eaxINY7JfjwPuxPPVAvttRetBAIRiu6ZYw== dependencies: - "@cspell/cspell-pipe" "^5.19.2" + "@cspell/cspell-pipe" "^5.19.3" chalk "^4.1.2" - commander "^9.0.0" + commander "^9.1.0" comment-json "^4.2.2" - cspell-gitignore "^5.19.2" - cspell-glob "^5.19.2" - cspell-lib "^5.19.2" + cspell-gitignore "^5.19.3" + cspell-glob "^5.19.3" + cspell-lib "^5.19.3" fast-json-stable-stringify "^2.1.0" file-entry-cache "^6.0.1" fs-extra "^10.0.1" @@ -7170,64 +7170,64 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.0.tgz#c3a0d9ad38a61fa6966feaa9281bf438530c8207" - integrity sha512-sPqGL/9BZo4cEI3r+ENfF9442uth8XaEX1oZ6wOGdMErFSwjEip5PM+lEP/snZIMCUVR3PfU1w8cL9WzB7bN4A== +cssnano-preset-advanced@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.1.tgz#f4fa7006aab67e354289b3efd512c93a272b3874" + integrity sha512-kfCknalY5VX/JKJ3Iri5/5rhZmQIqkbqgXsA6oaTnfA4flY/tt+w0hMxbExr0/fVuJL8w56j211op+pkQoNzoQ== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^*" - postcss-discard-unused "^*" - postcss-merge-idents "^*" - postcss-reduce-idents "^*" - postcss-zindex "^*" + cssnano-preset-default "^5.2.5" + postcss-discard-unused "^5.1.0" + postcss-merge-idents "^5.1.1" + postcss-reduce-idents "^5.2.0" + postcss-zindex "^5.1.0" -cssnano-preset-default@^*: - version "5.2.4" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.4.tgz#eced79bbc1ab7270337c4038a21891daac2329bc" - integrity sha512-w1Gg8xsebln6/axZ6qDFQHuglrGfbIHOIx0g4y9+etRlRab8CGpSpe6UMsrgJe4zhCaJ0LwLmc+PhdLRTwnhIA== +cssnano-preset-default@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" + integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== dependencies: css-declaration-sorter "^6.0.3" - cssnano-utils "^*" + cssnano-utils "^3.1.0" postcss-calc "^8.2.3" - postcss-colormin "^*" - postcss-convert-values "^*" - postcss-discard-comments "^*" - postcss-discard-duplicates "^*" - postcss-discard-empty "^*" - postcss-discard-overridden "^*" - postcss-merge-longhand "^*" - postcss-merge-rules "^*" - postcss-minify-font-values "^*" - postcss-minify-gradients "^*" - postcss-minify-params "^*" - postcss-minify-selectors "^*" - postcss-normalize-charset "^*" - postcss-normalize-display-values "^*" - postcss-normalize-positions "^*" - postcss-normalize-repeat-style "^*" - postcss-normalize-string "^*" - postcss-normalize-timing-functions "^*" - postcss-normalize-unicode "^*" - postcss-normalize-url "^*" - postcss-normalize-whitespace "^*" - postcss-ordered-values "^*" - postcss-reduce-initial "^*" - postcss-reduce-transforms "^*" - postcss-svgo "^*" - postcss-unique-selectors "^*" - -cssnano-utils@^*, cssnano-utils@^3.1.0: + postcss-colormin "^5.3.0" + postcss-convert-values "^5.1.0" + postcss-discard-comments "^5.1.1" + postcss-discard-duplicates "^5.1.0" + postcss-discard-empty "^5.1.1" + postcss-discard-overridden "^5.1.0" + postcss-merge-longhand "^5.1.3" + postcss-merge-rules "^5.1.1" + postcss-minify-font-values "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.2" + postcss-minify-selectors "^5.2.0" + postcss-normalize-charset "^5.1.0" + postcss-normalize-display-values "^5.1.0" + postcss-normalize-positions "^5.1.0" + postcss-normalize-repeat-style "^5.1.0" + postcss-normalize-string "^5.1.0" + postcss-normalize-timing-functions "^5.1.0" + postcss-normalize-unicode "^5.1.0" + postcss-normalize-url "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.1" + postcss-reduce-initial "^5.1.0" + postcss-reduce-transforms "^5.1.0" + postcss-svgo "^5.1.0" + postcss-unique-selectors "^5.1.1" + +cssnano-utils@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.6, cssnano@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.4.tgz#c648192e8e2f1aacb7d839e6aa3706b50cc7f8e4" - integrity sha512-hbfhVZreEPyzl+NbvRsjNo54JOX80b+j6nqG2biLVLaZHJEiqGyMh4xDGHtwhUKd5p59mj2GlDqlUBwJUuIu5A== +cssnano@^5.0.6, cssnano@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" + integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== dependencies: - cssnano-preset-default "^*" + cssnano-preset-default "^5.2.5" lilconfig "^2.0.3" yaml "^1.10.2" @@ -7973,9 +7973,9 @@ ejs@^3.1.6: jake "^10.6.1" electron-to-chromium@^1.4.84: - version "1.4.88" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.88.tgz#ebe6a2573b563680c7a7bf3a51b9e465c9c501db" - integrity sha512-oA7mzccefkvTNi9u7DXmT0LqvhnOiN2BhSrKerta7HeUC1cLoIwtbf2wL+Ah2ozh5KQd3/1njrGrwDBXx6d14Q== + version "1.4.92" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz#88996e9aceb3a500710fd439abfa89b6cc1ac56c" + integrity sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA== elegant-spinner@^1.0.1: version "1.0.1" @@ -8244,10 +8244,10 @@ eslint-plugin-import@^2.25.4: resolve "^1.20.0" tsconfig-paths "^3.12.0" -eslint-plugin-jest@^26.1.2: - version "26.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.2.tgz#0f1a15c62889fffc3f78a773749d672f1bedb15f" - integrity sha512-1bXCoRODPkGN06n9KAMls4Jm0eyS+0Q/LWcIxhqWR2ycV0Z7lnx2c10idk4dtFIJY5xStgiIr5snC6/rxcXpbw== +eslint-plugin-jest@^26.1.3: + version "26.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.3.tgz#e722e5efeea18aa9dec7c7349987b641db19feb7" + integrity sha512-Pju+T7MFpo5VFhFlwrkK/9jRUu18r2iugvgyrWOnnGRaVTFFmFXp+xFJpHyqmjjLmGJPKLeEFLVTAxezkApcpQ== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -9412,9 +9412,9 @@ getpass@^0.1.1: assert-plus "^1.0.0" gh-release-fetch@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/gh-release-fetch/-/gh-release-fetch-3.0.1.tgz#6db98465e90e635f4dff90c65a3ccb56455ba897" - integrity sha512-gV6V6+T0kKppzh/+YXpI/jl8ZgvjMY4oyWR3DAmPsqk9ILhk8TEneLFjBBM3kO7OfZ3dWCvuQu5M0DSh/Hz21w== + version "3.0.2" + resolved "https://registry.yarnpkg.com/gh-release-fetch/-/gh-release-fetch-3.0.2.tgz#18119c47a4babb918b525cd1c0cb2de50fd96be2" + integrity sha512-xcX1uaOVDvsm+io4bvJfBFpQCLfoI3DsFay2GBMUtEnNInbNFFZqxTh7X0WIorCDtOmtos5atp2BGHAGEzmlAg== dependencies: "@types/download" "^8.0.0" "@types/node-fetch" "^2.1.6" @@ -11038,9 +11038,9 @@ is-unicode-supported@^0.1.0: integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== is-unicode-supported@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.1.0.tgz#9127b71f9fa82f52ca5c20e982e7bec0ee31ee1e" - integrity sha512-lDcxivp8TJpLG75/DpatAqNzOpDPSpED8XNtrpBHTdQ2InQ1PbW78jhwSxyxhhu+xbVSast2X38bwj8atwoUQA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz#f4f54f34d8ebc84a46b93559a036763b6d3e1014" + integrity sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ== is-url@^1.2.4: version "1.2.4" @@ -11791,11 +11791,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2, json5@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^6.0.1: version "6.1.0" @@ -12199,15 +12197,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" @@ -12876,13 +12865,13 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: version "1.52.0" @@ -12998,10 +12987,10 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" @@ -13103,11 +13092,11 @@ mkdirp-infer-owner@^2.0.0: mkdirp "^1.0.3" "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" @@ -13284,17 +13273,17 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== -netlify-cli@^9.13.3: - version "9.13.3" - resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.3.tgz#61183a7e2d780fc6ec44ef35f377a7fed0afb9b2" - integrity sha512-kxaRPiVUikPXmmOX+w8qAqN69zC0Wqe12xhDfcKntS5GbMp1BpDwzqAlQCB76n36HJxzsBTjDR5KRM2Vo86HvA== +netlify-cli@^9.13.4: + version "9.13.4" + resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.4.tgz#362f34b28b5c76b1b6eea74096e6957fa4440eda" + integrity sha512-Ws9qKeeGqmHezoKVzGKCfYr+gh2LJZ1RfCjRX8US+3S1YxFyiHpbR8LN7lNDbZj34jEhZeOrwYwS5zbwJtqHCQ== dependencies: "@netlify/build" "^26.5.0" "@netlify/config" "^17.0.18" "@netlify/framework-info" "^9.0.2" "@netlify/local-functions-proxy" "^1.1.1" "@netlify/plugin-edge-handlers" "^3.0.7" - "@netlify/plugins-list" "^6.16.1" + "@netlify/plugins-list" "^6.17.0" "@netlify/routing-local-proxy" "^0.34.1" "@netlify/zip-it-and-ship-it" "^5.9.0" "@octokit/rest" "^18.0.0" @@ -13439,10 +13428,10 @@ netlify-redirector@^0.2.1: resolved "https://registry.yarnpkg.com/netlify-redirector/-/netlify-redirector-0.2.1.tgz#efdb761ea2c52edb3ecb5f237db0e10861f2ff0e" integrity sha512-17vDR9p1Loanp+vd57y+b6WlKb5X+qb0LZ44oTYsKJbdonz4Md+Ybv1lzH1w1aKm5YWWXHR8LMpWyY9bjlAJKw== -netlify@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/netlify/-/netlify-11.0.0.tgz#4f0362ccac8a6f4288738ff33cff0e7b0a01b482" - integrity sha512-y5wVBOCRneW43AI+sODsmGW+rJR11/Dhv/c12bPxdUxfpp0xyPccQLHGb3m+XbgtkQ+XioYBm2Ys1Rnxem1vrw== +netlify@^11.0.0, netlify@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/netlify/-/netlify-11.0.1.tgz#ab2551001e3d2d845ac0c14c2138427c90a3935e" + integrity sha512-TkVuTvmhlAtvAdgqb+iA5wMehEHS5QcPOrULm1t809Q6KmZIhe+7b0+jwZSsDqgX3OWK/P3xgk/AU0ZbTv7ufw== dependencies: "@netlify/open-api" "^2.8.0" lodash.camelcase "^4.3.0" @@ -14755,7 +14744,7 @@ postcss-calc@^8.2.3: postcss-selector-parser "^6.0.9" postcss-value-parser "^4.2.0" -postcss-colormin@^*: +postcss-colormin@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== @@ -14765,34 +14754,34 @@ postcss-colormin@^*: colord "^2.9.1" postcss-value-parser "^4.2.0" -postcss-convert-values@^*: +postcss-convert-values@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.0.tgz#f8d3abe40b4ce4b1470702a0706343eac17e7c10" integrity sha512-GkyPbZEYJiWtQB0KZ0X6qusqFHUepguBCNFi9t5JJc7I2OTXG7C0twbTLvCfaKOLl3rSXmpAwV7W5txd91V84g== dependencies: postcss-value-parser "^4.2.0" -postcss-discard-comments@^*: +postcss-discard-comments@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== -postcss-discard-duplicates@^*: +postcss-discard-duplicates@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@^*: +postcss-discard-empty@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== -postcss-discard-overridden@^*: +postcss-discard-overridden@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== -postcss-discard-unused@^*: +postcss-discard-unused@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz#8974e9b143d887677304e558c1166d3762501142" integrity sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw== @@ -14821,58 +14810,58 @@ postcss-media-query-parser@^0.2.3: resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== -postcss-merge-idents@^*: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.0.tgz#948e1183cd659cfb5f99c7389f5fcec83c8f9a00" - integrity sha512-l+awq6+uUiCILsHahWK5KE25495I4oCKlUrIA+EdBvklnVdWlBEsbkzq5+ouPKb8OAe4WwRBgFvaSq7f77FY+w== +postcss-merge-idents@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz#7753817c2e0b75d0853b56f78a89771e15ca04a1" + integrity sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^*: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.2.tgz#fe3002f38ad5827c1d6f7d5bb3f71d2566a2a138" - integrity sha512-18/bp9DZnY1ai9RlahOfLBbmIUKfKFPASxRCiZ1vlpZqWPCn8qWPFlEozqmWL+kBtcEQmG8W9YqGCstDImvp/Q== +postcss-merge-longhand@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" + integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== dependencies: postcss-value-parser "^4.2.0" - stylehacks "^*" + stylehacks "^5.1.0" -postcss-merge-rules@^*: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.0.tgz#a2d5117eba09c8686a5471d97bd9afcf30d1b41f" - integrity sha512-NecukEJovQ0mG7h7xV8wbYAkXGTO3MPKnXvuiXzOKcxoOodfTTKYjeo8TMhAswlSkjcPIBlnKbSFcTuVSDaPyQ== +postcss-merge-rules@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" + integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== dependencies: browserslist "^4.16.6" caniuse-api "^3.0.0" cssnano-utils "^3.1.0" postcss-selector-parser "^6.0.5" -postcss-minify-font-values@^*: +postcss-minify-font-values@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@^*: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.0.tgz#de0260a67a13b7b321a8adc3150725f2c6612377" - integrity sha512-J/TMLklkONn3LuL8wCwfwU8zKC1hpS6VcxFkNUNjmVt53uKqrrykR3ov11mdUYyqVMEx67slMce0tE14cE4DTg== +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== dependencies: colord "^2.9.1" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^*: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.1.tgz#c5f8e7dac565e577dd99904787fbec576cbdbfb2" - integrity sha512-WCpr+J9Uz8XzMpAfg3UL8z5rde6MifBbh5L8bn8S2F5hq/YDJJzASYCnCHvAB4Fqb94ys8v95ULQkW2EhCFvNg== +postcss-minify-params@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" + integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== dependencies: browserslist "^4.16.6" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-selectors@^*: +postcss-minify-selectors@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.0.tgz#17c2be233e12b28ffa8a421a02fc8b839825536c" integrity sha512-vYxvHkW+iULstA+ctVNx0VoRAR4THQQRkG77o0oa4/mBS0OzGvvzLIvHDv/nNEM0crzN2WIyFU5X7wZhaUK3RA== @@ -14907,47 +14896,47 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-normalize-charset@^*: +postcss-normalize-charset@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== -postcss-normalize-display-values@^*: +postcss-normalize-display-values@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-positions@^*: +postcss-normalize-positions@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.0.tgz#902a7cb97cf0b9e8b1b654d4a43d451e48966458" integrity sha512-8gmItgA4H5xiUxgN/3TVvXRoJxkAWLW6f/KKhdsH03atg0cB8ilXnrB5PpSshwVu/dD2ZsRFQcR1OEmSBDAgcQ== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-repeat-style@^*: +postcss-normalize-repeat-style@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.0.tgz#f6d6fd5a54f51a741cc84a37f7459e60ef7a6398" integrity sha512-IR3uBjc+7mcWGL6CtniKNQ4Rr5fTxwkaDHwMBDGGs1x9IVRkYIT/M4NelZWkAOBdV6v3Z9S46zqaKGlyzHSchw== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-string@^*: +postcss-normalize-string@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-timing-functions@^*: +postcss-normalize-timing-functions@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-unicode@^*: +postcss-normalize-unicode@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75" integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== @@ -14955,7 +14944,7 @@ postcss-normalize-unicode@^*: browserslist "^4.16.6" postcss-value-parser "^4.2.0" -postcss-normalize-url@^*: +postcss-normalize-url@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== @@ -14963,29 +14952,29 @@ postcss-normalize-url@^*: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@^*: +postcss-normalize-whitespace@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@^*: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.0.tgz#04ef429e0991b0292bc918b135cd4c038f7b889f" - integrity sha512-wU4Z4D4uOIH+BUKkYid36gGDJNQtkVJT7Twv8qH6UyfttbbJWyw4/xIPuVEkkCtQLAJ0EdsNSh8dlvqkXb49TA== +postcss-ordered-values@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" + integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@^*: +postcss-reduce-idents@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" -postcss-reduce-initial@^*: +postcss-reduce-initial@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6" integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== @@ -14993,7 +14982,7 @@ postcss-reduce-initial@^*: browserslist "^4.16.6" caniuse-api "^3.0.0" -postcss-reduce-transforms@^*: +postcss-reduce-transforms@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== @@ -15025,7 +15014,7 @@ postcss-sort-media-queries@^4.2.1: dependencies: sort-css-media-queries "2.0.4" -postcss-svgo@^*: +postcss-svgo@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== @@ -15033,7 +15022,7 @@ postcss-svgo@^*: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@^*: +postcss-unique-selectors@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== @@ -15054,7 +15043,7 @@ postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-zindex@^*: +postcss-zindex@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== @@ -17588,7 +17577,7 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -stylehacks@^*: +stylehacks@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== @@ -18277,13 +18266,13 @@ ts-node@10.4.0: yn "3.1.1" tsconfig-paths@^3.12.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976" - integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g== + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" tslib@^1.8.1, tslib@^1.9.0: @@ -18409,10 +18398,10 @@ typescript@^3.9.10: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== -typescript@^4.5.4, typescript@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +typescript@^4.5.4, typescript@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== ua-parser-js@^0.7.30: version "0.7.31" @@ -19364,25 +19353,25 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -workbox-background-sync@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.5.1.tgz#df79c6a4a22945d8a44493a4947a6ed0f720ef86" - integrity sha512-T5a35fagLXQvV8Dr4+bDU+XYsP90jJ3eBLjZMKuCNELMQZNj+VekCODz1QK44jgoBeQk+vp94pkZV6G+e41pgg== +workbox-background-sync@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.5.2.tgz#28be9bf89b8e4e0379d45903280c7c12f4df836f" + integrity sha512-EjG37LSMDJ1TFlFg56wx6YXbH4/NkG09B9OHvyxx+cGl2gP5OuOzsCY3rOPJSpbcz6jpuA40VIC3HzSD4OvE1g== dependencies: idb "^6.1.4" - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-broadcast-update@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-6.5.1.tgz#9aecb116979b0709480b84cfd1beca7a901d01d4" - integrity sha512-mb/oyblyEpDbw167cCTyHnC3RqCnCQHtFYuYZd+QTpuExxM60qZuBH1AuQCgvLtDcztBKdEYK2VFD9SZYgRbaQ== +workbox-broadcast-update@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-6.5.2.tgz#b1f32bb40a9dcb5b05ca27e09fb7c01a0a126182" + integrity sha512-DjJYraYnprTZE/AQNoeogaxI1dPuYmbw+ZJeeP8uXBSbg9SNv5wLYofQgywXeRepv4yr/vglMo9yaHUmBMc+4Q== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-build@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-6.5.1.tgz#6b5e8f090bb608267868540d3072b44b8531b3bc" - integrity sha512-coDUDzHvFZ1ADOl3wKCsCSyOBvkPKlPgcQDb6LMMShN1zgF31Mev/1HzN3+9T2cjjWAgFwZKkuRyExqc1v21Zw== +workbox-build@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-6.5.2.tgz#774faafd84b1dc94b74739ceb5d8ff367748523b" + integrity sha512-TVi4Otf6fgwikBeMpXF9n0awHfZTMNu/nwlMIT9W+c13yvxkmDFMPb7vHYK6RUmbcxwPnz4I/R+uL76+JxG4JQ== dependencies: "@apideck/better-ajv-errors" "^0.3.1" "@babel/core" "^7.11.1" @@ -19406,121 +19395,121 @@ workbox-build@^6.5.1: strip-comments "^2.0.1" tempy "^0.6.0" upath "^1.2.0" - workbox-background-sync "6.5.1" - workbox-broadcast-update "6.5.1" - workbox-cacheable-response "6.5.1" - workbox-core "6.5.1" - workbox-expiration "6.5.1" - workbox-google-analytics "6.5.1" - workbox-navigation-preload "6.5.1" - workbox-precaching "6.5.1" - workbox-range-requests "6.5.1" - workbox-recipes "6.5.1" - workbox-routing "6.5.1" - workbox-strategies "6.5.1" - workbox-streams "6.5.1" - workbox-sw "6.5.1" - workbox-window "6.5.1" - -workbox-cacheable-response@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-6.5.1.tgz#f71d0a75b3d6846e39594955e99ac42fd26f8693" - integrity sha512-3TdtH/luDiytmM+Cn72HCBLZXmbeRNJqZx2yaVOfUZhj0IVwZqQXhNarlGE9/k6U5Jelb+TtpH2mLVhnzfiSMg== + workbox-background-sync "6.5.2" + workbox-broadcast-update "6.5.2" + workbox-cacheable-response "6.5.2" + workbox-core "6.5.2" + workbox-expiration "6.5.2" + workbox-google-analytics "6.5.2" + workbox-navigation-preload "6.5.2" + workbox-precaching "6.5.2" + workbox-range-requests "6.5.2" + workbox-recipes "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" + workbox-streams "6.5.2" + workbox-sw "6.5.2" + workbox-window "6.5.2" + +workbox-cacheable-response@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-6.5.2.tgz#d9252eb99f0d0fceb70f63866172f4eaac56a3e8" + integrity sha512-UnHGih6xqloV808T7ve1iNKZMbpML0jGLqkkmyXkJbZc5j16+HRSV61Qrh+tiq3E3yLvFMGJ3AUBODOPNLWpTg== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-core@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-6.5.1.tgz#0dba3bccf883a46dfa61cc412eaa3cb09bb549e6" - integrity sha512-qObXZ39aFJ2N8X7IUbGrJHKWguliCuU1jOXM/I4MTT84u9BiKD2rHMkIzgeRP1Ixu9+cXU4/XHJq3Cy0Qqc5hw== +workbox-core@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-6.5.2.tgz#f5e06a22c6cb4651d3e13107443d972fdbd47364" + integrity sha512-IlxLGQf+wJHCR+NM0UWqDh4xe/Gu6sg2i4tfZk6WIij34IVk9BdOQgi6WvqSHd879jbQIUgL2fBdJUJyAP5ypQ== -workbox-expiration@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.5.1.tgz#9f105fcf3362852754884ad153888070ce98b692" - integrity sha512-iY/cTADAQATMmPkUBRmQdacqq0TJd2wMHimBQz+tRnPGHSMH+/BoLPABPnu7O7rT/g/s59CUYYRGxe3mEgoJCA== +workbox-expiration@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.5.2.tgz#ee6ed755a220a0b375d67831f9237e4dcbccb59c" + integrity sha512-5Hfp0uxTZJrgTiy9W7AjIIec+9uTOtnxY/tRBm4DbqcWKaWbVTa+izrKzzOT4MXRJJIJUmvRhWw4oo8tpmMouw== dependencies: idb "^6.1.4" - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-google-analytics@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-6.5.1.tgz#685224d439c1e7a943f8241d65e2a34ee95a4ba0" - integrity sha512-qZU46/h4dbionYT6Yk6iBkUwpiEzAfnO1W7KkI+AMmY7G9/gA03dQQ7rpTw8F4vWrG7ahTUGWDFv6fERtaw1BQ== +workbox-google-analytics@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-6.5.2.tgz#a79fa7a40824873baaa333dcd72d1fdf1c53adf5" + integrity sha512-8SMar+N0xIreP5/2we3dwtN1FUmTMScoopL86aKdXBpio8vXc8Oqb5fCJG32ialjN8BAOzDqx/FnGeCtkIlyvw== dependencies: - workbox-background-sync "6.5.1" - workbox-core "6.5.1" - workbox-routing "6.5.1" - workbox-strategies "6.5.1" + workbox-background-sync "6.5.2" + workbox-core "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" -workbox-navigation-preload@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-6.5.1.tgz#a244e3bdf99ce86da7210315ca1ba5aef3710825" - integrity sha512-aKrgAbn2IMgzTowTi/ZyKdQUcES2m++9aGtpxqsX7Gn9ovCY8zcssaMEAMMwrIeveij5HiWNBrmj6MWDHi+0rg== +workbox-navigation-preload@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-6.5.2.tgz#ffb3d9d5cdb881a3824851707da221dbb0bb3f23" + integrity sha512-iqDNWWMswjCsZuvGFDpcX1Z8InBVAlVBELJ28xShsWWntALzbtr0PXMnm2WHkXCc56JimmGldZi1N5yDPiTPOg== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-precaching@6.5.1, workbox-precaching@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-6.5.1.tgz#177b6424f1e71e601b9c3d6864decad2655f9ff9" - integrity sha512-EzlPBxvmjGfE56YZzsT/vpVkpLG1XJhoplgXa5RPyVWLUL1LbwEAxhkrENElSS/R9tgiTw80IFwysidfUqLihg== +workbox-precaching@6.5.2, workbox-precaching@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-6.5.2.tgz#a3117b4d3eb61ce8d01b9dfc063c48155bd7f9d3" + integrity sha512-OZAlQ8AAT20KugGKKuJMHdQ8X1IyNQaLv+mPTHj+8Dmv8peBq5uWNzs4g/1OSFmXsbXZ6a1CBC6YtQWVPhJQ9w== dependencies: - workbox-core "6.5.1" - workbox-routing "6.5.1" - workbox-strategies "6.5.1" + workbox-core "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" -workbox-range-requests@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-6.5.1.tgz#f40f84aa8765940543eba16131d02f12b38e2fdc" - integrity sha512-57Da/qRbd9v33YlHX0rlSUVFmE4THCjKqwkmfhY3tNLnSKN2L5YBS3qhWeDO0IrMNgUj+rGve2moKYXeUqQt4A== +workbox-range-requests@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-6.5.2.tgz#b8b7e5b5830fecc22f0a1d8815457921df2e5bf9" + integrity sha512-zi5VqF1mWqfCyJLTMXn1EuH/E6nisqWDK1VmOJ+TnjxGttaQrseOhMn+BMvULFHeF8AvrQ0ogfQ6bSv0rcfAlg== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-recipes@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-recipes/-/workbox-recipes-6.5.1.tgz#d2fb21743677cc3ca9e1fc9e3b68f0d1587df205" - integrity sha512-DGsyKygHggcGPQpWafC/Nmbm1Ny3sB2vE9r//3UbeidXiQ+pLF14KEG1/0NNGRaY+lfOXOagq6d1H7SC8KA+rA== +workbox-recipes@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-recipes/-/workbox-recipes-6.5.2.tgz#19f47ec25a8788c65d0cc8d217cbebc0bbbb5c63" + integrity sha512-2lcUKMYDiJKvuvRotOxLjH2z9K7jhj8GNUaHxHNkJYbTCUN3LsX1cWrsgeJFDZ/LgI565t3fntpbG9J415ZBXA== dependencies: - workbox-cacheable-response "6.5.1" - workbox-core "6.5.1" - workbox-expiration "6.5.1" - workbox-precaching "6.5.1" - workbox-routing "6.5.1" - workbox-strategies "6.5.1" + workbox-cacheable-response "6.5.2" + workbox-core "6.5.2" + workbox-expiration "6.5.2" + workbox-precaching "6.5.2" + workbox-routing "6.5.2" + workbox-strategies "6.5.2" -workbox-routing@6.5.1, workbox-routing@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-6.5.1.tgz#5488795ae850fe3ae435241143b54ff25ab0db70" - integrity sha512-yAAncdTwanvlR8KPjubyvFKeAok8ZcIws6UKxvIAg0I+wsf7UYi93DXNuZr6RBSQrByrN6HkCyjuhmk8P63+PA== +workbox-routing@6.5.2, workbox-routing@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-6.5.2.tgz#e0ad46246ba51224fd57eff0dd46891b3220cb9a" + integrity sha512-nR1w5PjF6IVwo0SX3oE88LhmGFmTnqqU7zpGJQQPZiKJfEKgDENQIM9mh3L1ksdFd9Y3CZVkusopHfxQvit/BA== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-strategies@6.5.1, workbox-strategies@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-6.5.1.tgz#51cabbddad5a1956eb9d51cf6ce01ab0a6372756" - integrity sha512-JNaTXPy8wXzKkr+6za7/eJX9opoZk7UgY261I2kPxl80XQD8lMjz0vo9EOcBwvD72v3ZhGJbW84ZaDwFEhFvWA== +workbox-strategies@6.5.2, workbox-strategies@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-6.5.2.tgz#56b02e6959c6391351011fc2e5b0829aff1ed859" + integrity sha512-fgbwaUMxbG39BHjJIs2y2X21C0bmf1Oq3vMQxJ1hr6y5JMJIm8rvKCcf1EIdAr+PjKdSk4ddmgyBQ4oO8be4Uw== dependencies: - workbox-core "6.5.1" + workbox-core "6.5.2" -workbox-streams@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-6.5.1.tgz#12036817385fa4449a86a3ef77fce1cb00ecad9f" - integrity sha512-7jaTWm6HRGJ/ewECnhb+UgjTT50R42E0/uNCC4eTKQwnLO/NzNGjoXTdQgFjo4zteR+L/K6AtFAiYKH3ZJbAYw== +workbox-streams@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-6.5.2.tgz#2fb6ba307f7d2cbda63f64522a197be868b4ea25" + integrity sha512-ovD0P4UrgPtZ2Lfc/8E8teb1RqNOSZr+1ZPqLR6sGRZnKZviqKbQC3zVvvkhmOIwhWbpL7bQlWveLVONHjxd5w== dependencies: - workbox-core "6.5.1" - workbox-routing "6.5.1" + workbox-core "6.5.2" + workbox-routing "6.5.2" -workbox-sw@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.5.1.tgz#f9256b40f0a7e94656ccd06f127ba19a92cd23c5" - integrity sha512-hVrQa19yo9wzN1fQQ/h2JlkzFpkuH2qzYT2/rk7CLaWt6tLnTJVFCNHlGRRPhytZSf++LoIy7zThT714sowT/Q== +workbox-sw@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.5.2.tgz#2f5dca0e96c61a450fccf0405095ddf1b6f43bc7" + integrity sha512-2KhlYqtkoqlnPdllj2ujXUKRuEFsRDIp6rdE4l1PsxiFHRAFaRTisRQpGvRem5yxgXEr+fcEKiuZUW2r70KZaw== -workbox-window@6.5.1, workbox-window@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.5.1.tgz#7b5ca29467b1da45dc9e2b5a1b89159d3eb9957a" - integrity sha512-oRlun9u7b7YEjo2fIDBqJkU2hXtrEljXcOytRhfeQRbqXxjUOpFgXSGRSAkmDx1MlKUNOSbr+zfi8h5n7In3yA== +workbox-window@6.5.2, workbox-window@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.5.2.tgz#46d6412cd57039bdf3d5dd914ad21fb3f98fe980" + integrity sha512-2kZH37r9Wx8swjEOL4B8uGM53lakMxsKkQ7mOKzGA/QAn/DQTEZGrdHWtypk2tbhKY5S0jvPS+sYDnb2Z3378A== dependencies: "@types/trusted-types" "^2.0.2" - workbox-core "6.5.1" + workbox-core "6.5.2" wrap-ansi@^3.0.1: version "3.0.1" From dc95cb86ca07303c285ef4ef5194ef7cf14284d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Fri, 25 Mar 2022 09:12:17 +0100 Subject: [PATCH 062/405] feat: lazy-load external images + ability to customize image display (#6990) --- .../__snapshots__/index.test.ts.snap | 28 +++++++++---------- .../src/remark/transformImage/index.ts | 2 +- .../__snapshots__/index.test.ts.snap | 2 +- .../src/theme/MDXComponents/Img.tsx | 10 +++++-- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap index 7602293159e2..e8540eda835d 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`transformImage plugin does not choke on invalid image 1`] = ` -"<img loading=\\"lazy\\" alt={\\"invalid image\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png\\").default} /> +"<img alt={\\"invalid image\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png\\").default} /> " `; @@ -19,29 +19,29 @@ exports[`transformImage plugin pathname protocol 1`] = ` exports[`transformImage plugin transform md images to <img /> 1`] = ` "![img](https://example.com/img.png) -<img loading=\\"lazy\\" src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> -<img loading=\\"lazy\\" alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> -<img loading=\\"lazy\\" alt={\\"img with URL encoded chars\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={\\"img with URL encoded chars\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png\\").default} width=\\"256\\" height=\\"82\\" /> -<img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" width=\\"200\\" height=\\"200\\" /> <img loading=\\"lazy\\" alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" width=\\"200\\" height=\\"200\\" /> <img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with "quotes"\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with "quotes"\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"site alias\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"site alias\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#dark'} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#dark'} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default} width=\\"200\\" height=\\"200\\" /> -<img loading=\\"lazy\\" alt={\\"img with both\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> +<img alt={\\"img with both\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> ## Heading diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts index bcc37f633508..8dc6bbca3e50 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts @@ -80,7 +80,7 @@ ${(err as Error).message}`; ); (jsxNode as Literal).type = 'jsx'; - jsxNode.value = `<img loading="lazy" ${alt}src={${src}}${title}${width}${height} />`; + jsxNode.value = `<img ${alt}src={${src}}${title}${width}${height} />`; } async function ensureImageFileExist(imagePath: string, sourceFilePath: string) { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap index baa694b15625..810a5542ed2b 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap @@ -46,7 +46,7 @@ exports[`transformAsset plugin transform md links to <a /> 1`] = ` <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img loading=\\"lazy\\" alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} width=\\"200\\" height=\\"200\\" /></a> +<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} width=\\"200\\" height=\\"200\\" /></a> <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}><span style={{color: \\"red\\"}}>Stylized link to asset file</span></a> diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx index a3b36432946d..a97bedc3e028 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Img.tsx @@ -15,6 +15,12 @@ function transformImgClassName(className?: string): string { } export default function MDXImg(props: Props): JSX.Element { - // eslint-disable-next-line jsx-a11y/alt-text - return <img {...props} className={transformImgClassName(props.className)} />; + return ( + // eslint-disable-next-line jsx-a11y/alt-text + <img + loading="lazy" + {...props} + className={transformImgClassName(props.className)} + /> + ); } From e8800b9d494193f5641a9eed9894c40526f74ce5 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 16:40:56 +0800 Subject: [PATCH 063/405] fix(core): prevent useBaseUrl returning /base/base when on /base (#6993) --- .../src/client/exports/__tests__/useBaseUrl.test.tsx | 2 ++ packages/docusaurus/src/client/exports/useBaseUrl.ts | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx index 4cca965759fb..5478f7c358f9 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.test.tsx @@ -77,6 +77,7 @@ describe('useBaseUrl', () => { expect(mockUseBaseUrl('/hello/foo', {absolute: true})).toBe( 'https://docusaurus.io/docusaurus/hello/foo', ); + expect(mockUseBaseUrl('/docusaurus')).toBe('/docusaurus/'); expect(mockUseBaseUrl('/docusaurus/')).toBe('/docusaurus/'); expect(mockUseBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); expect(mockUseBaseUrl('#hello')).toBe('#hello'); @@ -143,6 +144,7 @@ describe('useBaseUrlUtils().withBaseUrl()', () => { expect(withBaseUrl('/hello/foo', {absolute: true})).toBe( 'https://docusaurus.io/docusaurus/hello/foo', ); + expect(withBaseUrl('/docusaurus')).toBe('/docusaurus/'); expect(withBaseUrl('/docusaurus/')).toBe('/docusaurus/'); expect(withBaseUrl('/docusaurus/hello')).toBe('/docusaurus/hello'); expect(withBaseUrl('#hello')).toBe('#hello'); diff --git a/packages/docusaurus/src/client/exports/useBaseUrl.ts b/packages/docusaurus/src/client/exports/useBaseUrl.ts index a709e293809f..5ae4640a150c 100644 --- a/packages/docusaurus/src/client/exports/useBaseUrl.ts +++ b/packages/docusaurus/src/client/exports/useBaseUrl.ts @@ -33,6 +33,12 @@ function addBaseUrl( return baseUrl + url.replace(/^\//, ''); } + // /baseUrl -> /baseUrl/ + // https://github.com/facebook/docusaurus/issues/6315 + if (url === baseUrl.replace(/\/$/, '')) { + return baseUrl; + } + // We should avoid adding the baseurl twice if it's already there const shouldAddBaseUrl = !url.startsWith(baseUrl); From 87592bca0398435409a06541cb7d60642db06633 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 18:06:30 +0800 Subject: [PATCH 064/405] refactor: ensure all types are using index signature instead of Record (#6995) * refactor: ensure all types are using index signature instead of Record * kick CI --- .eslintrc.js | 4 ++ .../functionUtils/playgroundUtils.ts | 14 +++--- jest/snapshotPathNormalizer.ts | 4 +- packages/create-docusaurus/src/index.ts | 2 +- packages/docusaurus-mdx-loader/src/index.ts | 8 ++-- .../docusaurus-mdx-loader/src/mdx-loader.d.ts | 2 +- packages/docusaurus-migrate/src/index.ts | 14 +++--- packages/docusaurus-migrate/src/types.ts | 18 ++++---- .../src/index.d.ts | 38 ++++++++-------- .../src/createRedirectPageContent.ts | 2 +- .../src/__tests__/frontMatter.test.ts | 4 +- .../src/authors.ts | 2 +- .../src/blogUtils.ts | 6 +-- .../src/deps.d.ts | 2 +- .../src/frontMatter.ts | 6 +-- .../src/index.ts | 4 +- .../src/plugin-content-blog.d.ts | 8 ++-- .../src/types.ts | 2 +- .../__snapshots__/index.test.ts.snap | 4 -- .../src/__tests__/docs.test.ts | 2 +- .../src/__tests__/frontMatter.test.ts | 4 +- .../src/__tests__/index.test.ts | 2 +- .../src/categoryGeneratedIndex.ts | 2 +- .../client/__tests__/docsClientUtils.test.ts | 2 +- .../src/client/docsClientUtils.ts | 6 +-- .../src/client/index.ts | 2 +- .../src/deps.d.ts | 2 +- .../src/docs.ts | 2 +- .../src/frontMatter.ts | 6 +-- .../src/globalData.ts | 2 +- .../src/index.ts | 3 +- .../src/plugin-content-docs.d.ts | 10 ++--- .../src/sidebars/__tests__/processor.test.ts | 5 +-- .../src/sidebars/__tests__/utils.test.ts | 2 +- .../src/sidebars/processor.ts | 13 ++---- .../src/sidebars/types.ts | 9 ++-- .../src/sidebars/utils.ts | 14 +++--- .../src/sidebars/validation.ts | 6 +-- .../src/translations.ts | 6 +-- .../src/types.ts | 4 +- .../src/deps.d.ts | 2 +- .../src/frontMatter.ts | 6 +-- .../src/plugin-content-pages.d.ts | 4 +- .../src/theme/DebugContent/index.tsx | 2 +- .../docusaurus-plugin-google-gtag/src/gtag.ts | 2 +- .../src/deps.d.ts | 4 +- .../src/__tests__/__fixtures__/sync.md | 11 +++++ .../__snapshots__/index.test.ts.snap | 39 ++++++++++++++--- .../src/__tests__/index.test.ts | 13 +++--- .../src/__tests__/validateThemeConfig.test.ts | 4 +- .../src/theme-classic.d.ts | 6 +-- .../src/theme/DocVersionBanner/index.tsx | 7 ++- .../src/theme/MDXComponents/Pre.tsx | 3 +- .../src/theme/NavbarItem/index.tsx | 7 ++- .../src/translations.ts | 2 +- .../src/contexts/docsPreferredVersion.tsx | 9 ++-- .../src/contexts/tabGroupChoice.tsx | 2 +- .../src/utils/tagsUtils.ts | 8 ++-- .../src/utils/useThemeConfig.ts | 6 +-- .../src/__tests__/validateThemeConfig.test.ts | 4 +- .../src/theme-search-algolia.d.ts | 2 +- .../src/theme/SearchPage/index.tsx | 19 ++++---- .../locales/__tests__/locales.test.ts | 2 +- .../src/index.ts | 2 +- packages/docusaurus-types/src/index.d.ts | 43 ++++++++++--------- .../src/validationUtils.ts | 2 +- .../src/__tests__/emitUtils.test.ts | 6 +-- .../src/__tests__/hashUtils.test.ts | 4 +- .../src/__tests__/jsUtils.test.ts | 6 +-- .../src/__tests__/pathUtils.test.ts | 6 +-- .../src/__tests__/urlUtils.test.ts | 2 +- .../docusaurus-utils/src/markdownLinks.ts | 2 +- .../docusaurus-utils/src/markdownUtils.ts | 4 +- packages/docusaurus/src/choosePort.ts | 19 ++++---- packages/docusaurus/src/client/docusaurus.ts | 4 +- .../src/client/exports/ComponentCreator.tsx | 5 +-- .../src/client/exports/useGlobalData.ts | 15 ++++--- packages/docusaurus/src/client/flat.ts | 6 ++- .../src/client/normalizeLocation.ts | 2 +- packages/docusaurus/src/client/prefetch.ts | 2 +- packages/docusaurus/src/commands/build.ts | 2 +- .../docusaurus/src/commands/swizzle/common.ts | 7 ++- packages/docusaurus/src/deps.d.ts | 8 ++-- packages/docusaurus/src/server/brokenLinks.ts | 16 +++---- packages/docusaurus/src/server/index.ts | 2 +- .../docusaurus/src/server/plugins/index.ts | 5 ++- .../docusaurus/src/server/plugins/init.ts | 9 ++-- packages/docusaurus/src/server/routes.ts | 4 +- .../src/server/translations/translations.ts | 8 ++-- .../translations/translationsExtractor.ts | 4 +- .../docusaurus/src/server/versions/index.ts | 4 +- packages/docusaurus/src/webpack/base.ts | 6 ++- packages/docusaurus/src/webpack/server.ts | 2 +- packages/lqip-loader/src/lqip.ts | 2 +- website/docs/docusaurus-core.md | 4 +- website/src/data/users.tsx | 2 +- website/src/utils/colorUtils.ts | 9 ++-- .../version-2.0.0-beta.16/docusaurus-core.md | 4 +- .../version-2.0.0-beta.17/docusaurus-core.md | 4 +- 99 files changed, 338 insertions(+), 306 deletions(-) create mode 100644 packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/sync.md diff --git a/.eslintrc.js b/.eslintrc.js index 04e9657ae9fb..e30864158b11 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -269,6 +269,10 @@ module.exports = { ERROR, {'ts-expect-error': 'allow-with-description'}, ], + '@typescript-eslint/consistent-indexed-object-style': [ + WARNING, + 'index-signature', + ], '@typescript-eslint/consistent-type-imports': [ WARNING, {disallowTypeAnnotations: false}, diff --git a/admin/new.docusaurus.io/functionUtils/playgroundUtils.ts b/admin/new.docusaurus.io/functionUtils/playgroundUtils.ts index b8a7f84ca996..85bd7ef4bd81 100644 --- a/admin/new.docusaurus.io/functionUtils/playgroundUtils.ts +++ b/admin/new.docusaurus.io/functionUtils/playgroundUtils.ts @@ -26,9 +26,11 @@ const PlaygroundDocumentationUrl = 'https://docusaurus.io/docs/playground'; export type PlaygroundName = keyof typeof PlaygroundConfigs; function isValidPlaygroundName( - playgroundName: string, + playgroundName: string | undefined, ): playgroundName is PlaygroundName { - return Object.keys(PlaygroundConfigs).includes(playgroundName); + return ( + !!playgroundName && Object.keys(PlaygroundConfigs).includes(playgroundName) + ); } export function createPlaygroundDocumentationResponse(): HandlerResponse { @@ -54,10 +56,10 @@ export function createPlaygroundResponse( } // Inspired by https://stackoverflow.com/a/3409200/82609 -function parseCookieString(cookieString: string): Record<string, string> { - const result: Record<string, string> = {}; +function parseCookieString(cookieString: string): {[key: string]: string} { + const result: {[key: string]: string} = {}; cookieString.split(';').forEach((cookie) => { - const [name, value] = cookie.split('='); + const [name, value] = cookie.split('=') as [string, string]; result[name.trim()] = decodeURI(value); }); return result; @@ -66,7 +68,7 @@ function parseCookieString(cookieString: string): Record<string, string> { export function readPlaygroundName( event: HandlerEvent, ): PlaygroundName | undefined { - const parsedCookie: Record<string, string> = event.headers.cookie + const parsedCookie: {[key: string]: string} = event.headers.cookie ? parseCookieString(event.headers.cookie) : {}; const playgroundName: string | undefined = parsedCookie[CookieName]; diff --git a/jest/snapshotPathNormalizer.ts b/jest/snapshotPathNormalizer.ts index ad642a561ae3..d8b2d7a14e45 100644 --- a/jest/snapshotPathNormalizer.ts +++ b/jest/snapshotPathNormalizer.ts @@ -31,7 +31,7 @@ export function print( }); return serialize(error); } else if (val && typeof val === 'object') { - const normalizedValue = _.cloneDeep(val) as Record<string, unknown>; + const normalizedValue = _.cloneDeep(val) as {[key: string]: unknown}; Object.keys(normalizedValue).forEach((key) => { normalizedValue[key] = normalizePaths(normalizedValue[key]); @@ -46,7 +46,7 @@ export function test(val: unknown): boolean { (typeof val === 'object' && val && Object.keys(val).some((key) => - shouldUpdate((val as Record<string, unknown>)[key]), + shouldUpdate((val as {[key: string]: unknown})[key]), )) || // val.message is non-enumerable in an error (val instanceof Error && shouldUpdate(val.message)) || diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 1562e756b511..f6b276585cd0 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -102,7 +102,7 @@ function isValidGitRepoUrl(gitRepoUrl: string) { return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item)); } -async function updatePkg(pkgPath: string, obj: Record<string, unknown>) { +async function updatePkg(pkgPath: string, obj: {[key: string]: unknown}) { const content = await fs.readFile(pkgPath, 'utf-8'); const pkg = JSON.parse(content); const newPkg = Object.assign(pkg, obj); diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index 38c97ccc7475..ae3336d169a1 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -43,9 +43,9 @@ type Options = RemarkAndRehypePluginOptions & { removeContentTitle?: boolean; metadataPath?: string | ((filePath: string) => string); createAssets?: (metadata: { - frontMatter: Record<string, unknown>; - metadata: Record<string, unknown>; - }) => Record<string, unknown>; + frontMatter: {[key: string]: unknown}; + metadata: {[key: string]: unknown}; + }) => {[key: string]: unknown}; filepath: string; }; @@ -72,7 +72,7 @@ async function readMetadataPath(metadataPath: string) { * * `{image: "./myImage.png"}` => `{image: require("./myImage.png")}` */ -function createAssetsExportCode(assets: Record<string, unknown>) { +function createAssetsExportCode(assets: {[key: string]: unknown}) { if (Object.keys(assets).length === 0) { return 'undefined'; } diff --git a/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts b/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts index 99d781b4363f..e1fff7113ef8 100644 --- a/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts +++ b/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts @@ -9,7 +9,7 @@ import type {Plugin} from 'unified'; export type RemarkOrRehypePlugin = // eslint-disable-next-line @typescript-eslint/no-explicit-any - [Plugin<any[]>, Record<string, unknown>] | Plugin<any[]>; + [Plugin<any[]>, any] | Plugin<any[]>; export type RemarkAndRehypePluginOptions = { remarkPlugins: RemarkOrRehypePlugin[]; rehypePlugins: RemarkOrRehypePlugin[]; diff --git a/packages/docusaurus-migrate/src/index.ts b/packages/docusaurus-migrate/src/index.ts index bbb05714337c..764718fc5441 100644 --- a/packages/docusaurus-migrate/src/index.ts +++ b/packages/docusaurus-migrate/src/index.ts @@ -67,7 +67,7 @@ ${ type MigrationContext = { siteDir: string; newDir: string; - deps: Record<string, string>; + deps: {[key: string]: string}; shouldMigrateMdFiles: boolean; shouldMigratePages: boolean; v1Config: VersionOneConfig; @@ -83,7 +83,7 @@ export async function migrateDocusaurusProject( async function createMigrationContext(): Promise<MigrationContext> { const v1Config = importFresh(`${siteDir}/siteConfig`) as VersionOneConfig; logger.info('Starting migration from v1 to v2...'); - const deps: Record<string, string> = { + const deps = { '@docusaurus/core': DOCUSAURUS_VERSION, '@docusaurus/preset-classic': DOCUSAURUS_VERSION, clsx: '^1.1.1', @@ -206,7 +206,7 @@ export function createConfigFile({ 'v1Config' | 'siteDir' | 'newDir' >): VersionTwoConfig { const siteConfig = v1Config; - const customConfigFields: Record<string, unknown> = {}; + const customConfigFields: {[key: string]: unknown} = {}; // add fields that are unknown to v2 to customConfigFields Object.keys(siteConfig).forEach((key) => { const knownFields = [ @@ -564,7 +564,7 @@ async function migrateVersionedSidebar( }; }); return acc; - }, {} as Record<string, Array<string | Record<string, unknown>>>); + }, {} as {[key: string]: Array<string | {[key: string]: unknown}>}); return topLevel; }, {}, @@ -702,9 +702,9 @@ async function migrateLatestDocs(context: MigrationContext) { async function migratePackageFile(context: MigrationContext): Promise<void> { const {deps, siteDir, newDir} = context; const packageFile = importFresh(`${siteDir}/package.json`) as { - scripts?: Record<string, string>; - dependencies?: Record<string, string>; - devDependencies?: Record<string, string>; + scripts?: {[key: string]: string}; + dependencies?: {[key: string]: string}; + devDependencies?: {[key: string]: string}; [otherKey: string]: unknown; }; packageFile.scripts = { diff --git a/packages/docusaurus-migrate/src/types.ts b/packages/docusaurus-migrate/src/types.ts index 1da33918953c..8a3583fcfad2 100644 --- a/packages/docusaurus-migrate/src/types.ts +++ b/packages/docusaurus-migrate/src/types.ts @@ -33,8 +33,8 @@ export type SidebarEntry = export type SidebarEntries = { [key: string]: - | Record<string, unknown> - | Array<Record<string, unknown> | string>; + | {[key: string]: unknown} + | Array<{[key: string]: unknown} | string>; }; export interface VersionTwoConfig { @@ -58,7 +58,7 @@ export interface VersionTwoConfig { logo?: { src?: string; }; - items: Array<Record<string, unknown> | null>; + items: Array<{[key: string]: unknown} | null>; }; image?: string; footer: { @@ -74,7 +74,7 @@ export interface VersionTwoConfig { src?: string; }; }; - algolia?: Record<string, unknown>; + algolia?: {[key: string]: unknown}; }; customFields: { [key: string]: unknown; @@ -111,16 +111,16 @@ export type VersionOneConfig = { copyright?: string; editUrl?: string; customDocsPath?: string; - users?: Array<Record<string, unknown>>; + users?: Array<{[key: string]: unknown}>; disableHeaderTitle?: string; disableTitleTagline?: string; - separateCss?: Array<Record<string, unknown>>; + separateCss?: Array<{[key: string]: unknown}>; footerIcon?: string; translationRecruitingLink?: string; - algolia?: Record<string, unknown>; + algolia?: {[key: string]: unknown}; gaTrackingId?: string; gaGtag?: boolean; - highlight?: Record<string, unknown>; + highlight?: {[key: string]: unknown}; markdownPlugins?: Array<() => void>; scripts?: Array<{src: string; [key: string]: unknown} | string>; stylesheets?: Array<{href: string; [key: string]: unknown} | string>; @@ -133,5 +133,5 @@ export type VersionOneConfig = { ogImage?: string; cleanUrl?: boolean; scrollToTop?: boolean; - scrollToTopOptions?: Record<string, unknown>; + scrollToTopOptions?: {[key: string]: unknown}; }; diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index d8d8b53f4273..5cc70d825d4d 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -44,13 +44,14 @@ declare module '@generated/routes' { declare module '@generated/routesChunkNames' { import type {RouteChunksTree} from '@docusaurus/types'; - const routesChunkNames: Record<string, RouteChunksTree>; + const routesChunkNames: {[route: string]: RouteChunksTree}; export = routesChunkNames; } declare module '@generated/globalData' { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const globalData: Record<string, any>; + import type {GlobalData} from '@docusaurus/types'; + + const globalData: GlobalData; export = globalData; } @@ -59,20 +60,19 @@ declare module '@generated/i18n' { defaultLocale: string; locales: [string, ...string[]]; currentLocale: string; - localeConfigs: Record< - string, - { + localeConfigs: { + [localeName: string]: { label: string; direction: string; htmlLang: string; - } - >; + }; + }; }; export = i18n; } declare module '@generated/codeTranslations' { - const codeTranslations: Record<string, string>; + const codeTranslations: {[msgId: string]: string}; export = codeTranslations; } @@ -172,10 +172,9 @@ declare module '@docusaurus/Interpolate' { ? Key | ExtractInterpolatePlaceholders<Rest> : never; - export type InterpolateValues< - Str extends string, - Value extends ReactNode, - > = Record<ExtractInterpolatePlaceholders<Str>, Value>; + export type InterpolateValues<Str extends string, Value extends ReactNode> = { + [key in ExtractInterpolatePlaceholders<Str>]: Value; + }; // If all the values are plain strings, interpolate returns a simple string export function interpolate<Str extends string>( @@ -320,17 +319,18 @@ declare module '@docusaurus/renderRoutes' { } declare module '@docusaurus/useGlobalData' { - export function useAllPluginInstancesData<T = unknown>( + import type {GlobalData} from '@docusaurus/types'; + + export function useAllPluginInstancesData( pluginName: string, - ): Record<string, T>; + ): GlobalData[string]; - export function usePluginData<T = unknown>( + export function usePluginData( pluginName: string, pluginId?: string, - ): T; + ): GlobalData[string][string]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - export default function useGlobalData(): Record<string, any>; + export default function useGlobalData(): GlobalData; } declare module '*.svg' { diff --git a/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts b/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts index 557ea9c3816c..b7bdd7f61c6d 100644 --- a/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts +++ b/packages/docusaurus-plugin-client-redirects/src/createRedirectPageContent.ts @@ -13,7 +13,7 @@ const getCompiledRedirectPageTemplate = _.memoize(() => eta.compile(redirectPageTemplate.trim()), ); -function renderRedirectPageTemplate(data: Record<string, unknown>) { +function renderRedirectPageTemplate(data: {toUrl: string}) { const compiled = getCompiledRedirectPageTemplate(); return compiled(data, eta.defaultConfig); } diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts index 5a8dc0ebd8a0..99e3c694bfbd 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts @@ -15,11 +15,11 @@ function testField(params: { fieldName: keyof BlogPostFrontMatter; validFrontMatters: BlogPostFrontMatter[]; convertibleFrontMatter?: [ - ConvertibleFrontMatter: Record<string, unknown>, + ConvertibleFrontMatter: {[key: string]: unknown}, ConvertedFrontMatter: BlogPostFrontMatter, ][]; invalidFrontMatters?: [ - InvalidFrontMatter: Record<string, unknown>, + InvalidFrontMatter: {[key: string]: unknown}, ErrorMessage: string, ][]; }) { diff --git a/packages/docusaurus-plugin-content-blog/src/authors.ts b/packages/docusaurus-plugin-content-blog/src/authors.ts index 1de62ec0c8c6..e8e2be323127 100644 --- a/packages/docusaurus-plugin-content-blog/src/authors.ts +++ b/packages/docusaurus-plugin-content-blog/src/authors.ts @@ -15,7 +15,7 @@ import type { BlogPostFrontMatterAuthors, } from '@docusaurus/plugin-content-blog'; -export type AuthorsMap = Record<string, Author>; +export type AuthorsMap = {[authorKey: string]: Author}; const AuthorsMapSchema = Joi.object<AuthorsMap>() .pattern( diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 59b38a5e5e87..b1823bb6d68d 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -43,9 +43,9 @@ export function truncate(fileString: string, truncateMarker: RegExp): string { return fileString.split(truncateMarker, 1).shift()!; } -export function getSourceToPermalink( - blogPosts: BlogPost[], -): Record<string, string> { +export function getSourceToPermalink(blogPosts: BlogPost[]): { + [aliasedPath: string]: string; +} { return Object.fromEntries( blogPosts.map(({metadata: {source, permalink}}) => [source, permalink]), ); diff --git a/packages/docusaurus-plugin-content-blog/src/deps.d.ts b/packages/docusaurus-plugin-content-blog/src/deps.d.ts index c9976d8a584b..6b8b33906b54 100644 --- a/packages/docusaurus-plugin-content-blog/src/deps.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/deps.d.ts @@ -6,7 +6,7 @@ */ declare module 'remark-admonitions' { - type Options = Record<string, unknown>; + type Options = {[key: string]: unknown}; const plugin: (options?: Options) => void; export = plugin; diff --git a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts index 49a872b6507e..417bf1df00fb 100644 --- a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts @@ -74,8 +74,8 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({ '{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.', }); -export function validateBlogPostFrontMatter( - frontMatter: Record<string, unknown>, -): BlogPostFrontMatter { +export function validateBlogPostFrontMatter(frontMatter: { + [key: string]: unknown; +}): BlogPostFrontMatter { return validateFrontMatter(frontMatter, BlogFrontMatterSchema); } diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index d8338c97ce73..93cf975f8be3 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -205,7 +205,7 @@ export default async function pluginContentBlog( blogTagsListPath, } = blogContents; - const blogItemsToMetadata: Record<string, BlogPostMetadata> = {}; + const blogItemsToMetadata: {[postId: string]: BlogPostMetadata} = {}; const sidebarBlogPosts = options.blogSidebarCount === 'ALL' @@ -316,7 +316,7 @@ export default async function pluginContentBlog( return; } - const tagsModule: Record<string, TagModule> = Object.fromEntries( + const tagsModule: {[tagName: string]: TagModule} = Object.fromEntries( Object.entries(blogTags).map(([, tag]) => { const tagModule: TagModule = { allTagsPath: blogTagsListPath, diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index b369cd978644..10e4fd654752 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -232,7 +232,7 @@ declare module '@docusaurus/plugin-content-blog' { /** * Front matter, as-is. */ - readonly frontMatter: BlogPostFrontMatter & Record<string, unknown>; + readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown}; /** * Tags, normalized. */ @@ -301,7 +301,7 @@ declare module '@docusaurus/plugin-content-blog' { /** Markdown content. */ content: string; /** Front matter. */ - frontMatter?: BlogPostFrontMatter & Record<string, unknown>; + frontMatter?: BlogPostFrontMatter & {[key: string]: unknown}; /** Options accepted by ngryman/reading-time. */ options?: ReadingTimeOptions; }) => number; @@ -402,7 +402,7 @@ declare module '@docusaurus/plugin-content-blog' { * unlocalized file. Ignored when `editUrl` is a function. */ editLocalizedFiles?: boolean; - admonitions: Record<string, unknown>; + admonitions: {[key: string]: unknown}; /** Path to the authors map file, relative to the blog content directory. */ authorsMapPath: string; /** A callback to customize the reading time number displayed. */ @@ -545,7 +545,7 @@ declare module '@theme/BlogTagsListPage' { /** Blog sidebar. */ readonly sidebar: BlogSidebar; /** A map from tag names to the full tag module. */ - readonly tags: Readonly<Record<string, TagModule>>; + readonly tags: Readonly<{[tagName: string]: TagModule}>; } export default function BlogTagsListPage(props: Props): JSX.Element; diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index a83cc76abfab..a96390f71d51 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -50,6 +50,6 @@ export type BlogMarkdownLoaderOptions = { siteDir: string; contentPaths: BlogContentPaths; truncateMarker: RegExp; - sourceToPermalink: Record<string, string>; + sourceToPermalink: {[aliasedPath: string]: string}; onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void; }; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index b65e9956e345..3c40354723ff 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1535,10 +1535,6 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "type": "autogenerated", }, "numberPrefixParser": [Function], - "options": { - "sidebarCollapsed": true, - "sidebarCollapsible": true, - }, "version": { "contentPath": "docs", "versionName": "current", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index eed15f05763f..730e3d787e54 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -43,7 +43,7 @@ const createFakeDocFile = ({ markdown = 'some markdown content', }: { source: string; - frontMatter?: Record<string, string>; + frontMatter?: {[key: string]: string}; markdown?: string; }): DocFile => { const content = `--- diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index 1fa4809c48db..734e7e0bbf49 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -13,11 +13,11 @@ function testField(params: { prefix: string; validFrontMatters: DocFrontMatter[]; convertibleFrontMatter?: [ - ConvertibleFrontMatter: Record<string, unknown>, + ConvertibleFrontMatter: {[key: string]: unknown}, ConvertedFrontMatter: DocFrontMatter, ][]; invalidFrontMatters?: [ - InvalidFrontMatter: Record<string, unknown>, + InvalidFrontMatter: {[key: string]: unknown}, ErrorMessage: string, ][]; }) { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 0d6df18fe915..382b0f636580 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -52,7 +52,7 @@ Available ids are:\n- ${version.docs.map((d) => d.unversionedId).join('\n- ')}`, const createFakeActions = (contentDir: string) => { const routeConfigs: RouteConfig[] = []; - const dataContainer: Record<string, unknown> = {}; + const dataContainer: {[key: string]: unknown} = {}; const globalDataContainer: {pluginName?: {pluginId: unknown}} = {}; const actions = { diff --git a/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts b/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts index 522ae1455656..b3785f6fe9ec 100644 --- a/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts +++ b/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts @@ -17,7 +17,7 @@ function getCategoryGeneratedIndexMetadata({ }: { category: SidebarItemCategoryWithGeneratedIndex; sidebarsUtils: SidebarsUtils; - docsById: Record<string, DocMetadataBase>; + docsById: {[docId: string]: DocMetadataBase}; }): CategoryGeneratedIndexMetadata { const {sidebarName, previous, next} = sidebarsUtils.getCategoryGeneratedIndexNavigation(category.link.permalink); diff --git a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts index 5576af633260..9663b014627c 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts @@ -21,7 +21,7 @@ import _ from 'lodash'; describe('docsClientUtils', () => { it('getActivePlugin', () => { - const data: Record<string, GlobalPluginData> = { + const data: {[key: string]: GlobalPluginData} = { pluginIosId: { path: '/ios', versions: [], diff --git a/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts b/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts index ad40156a7e38..1a07cd180735 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts @@ -23,11 +23,11 @@ import type { // ie the docs of that plugin are currently browsed // it is useful to support multiple docs plugin instances export function getActivePlugin( - allPluginDatas: Record<string, GlobalPluginData>, + allPluginData: {[pluginId: string]: GlobalPluginData}, pathname: string, options: GetActivePluginOptions = {}, ): ActivePlugin | undefined { - const activeEntry = Object.entries(allPluginDatas) + const activeEntry = Object.entries(allPluginData) // Route sorting: '/android/foo' should match '/android' instead of '/' .sort((a, b) => b[1].path.localeCompare(a[1].path)) .find( @@ -46,7 +46,7 @@ export function getActivePlugin( if (!activePlugin && options.failfast) { throw new Error( `Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values( - allPluginDatas, + allPluginData, ) .map((plugin) => plugin.path) .join(', ')}`, diff --git a/packages/docusaurus-plugin-content-docs/src/client/index.ts b/packages/docusaurus-plugin-content-docs/src/client/index.ts index 5529d38739aa..803456fbbe7d 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/index.ts @@ -31,7 +31,7 @@ const StableEmptyObject = {}; // Not using useAllPluginInstancesData() because in blog-only mode, docs hooks // are still used by the theme. We need a fail-safe fallback when the docs // plugin is not in use -export const useAllDocsData = (): Record<string, GlobalPluginData> => +export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} => useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject; export const useDocsData = (pluginId: string | undefined): GlobalPluginData => diff --git a/packages/docusaurus-plugin-content-docs/src/deps.d.ts b/packages/docusaurus-plugin-content-docs/src/deps.d.ts index c9976d8a584b..6b8b33906b54 100644 --- a/packages/docusaurus-plugin-content-docs/src/deps.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/deps.d.ts @@ -6,7 +6,7 @@ */ declare module 'remark-admonitions' { - type Options = Record<string, unknown>; + type Options = {[key: string]: unknown}; const plugin: (options?: Options) => void; export = plugin; diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index c94ff470b0f2..631daef5f73e 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -424,7 +424,7 @@ export function getDocIds(doc: DocMetadataBase): [string, string] { // to "id") export function createDocsByIdIndex< Doc extends {id: string; unversionedId: string}, ->(docs: Doc[]): Record<string, Doc> { +>(docs: Doc[]): {[docId: string]: Doc} { return Object.fromEntries( docs.flatMap((doc) => [ [doc.unversionedId, doc], diff --git a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts index da4b86ca3723..fe53b0573dec 100644 --- a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts @@ -41,8 +41,8 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({ ...FrontMatterTOCHeadingLevels, }).unknown(); -export function validateDocFrontMatter( - frontMatter: Record<string, unknown>, -): DocFrontMatter { +export function validateDocFrontMatter(frontMatter: { + [key: string]: unknown; +}): DocFrontMatter { return validateFrontMatter(frontMatter, DocFrontMatterSchema); } diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index bc974d527c87..302fb77328de 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -40,7 +40,7 @@ function toGlobalDataGeneratedIndex( function toGlobalSidebars( sidebars: Sidebars, version: LoadedVersion, -): Record<string, GlobalSidebar> { +): {[sidebarId: string]: GlobalSidebar} { const {getFirstLink} = createSidebarsUtils(sidebars); return _.mapValues(sidebars, (sidebar, sidebarId) => { const firstLink = getFirstLink(sidebarId); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 4e6d19f4bcad..4b659f48fa57 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -56,7 +56,6 @@ import type { PropTagsListPage, PluginOptions, } from '@docusaurus/plugin-content-docs'; -import type {GlobalPluginData} from '@docusaurus/plugin-content-docs/client'; import {createSidebarsUtils} from './sidebars/utils'; import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex'; @@ -293,7 +292,7 @@ export default async function pluginContentDocs( // TODO tags should be a sub route of the version route await Promise.all(loadedVersions.map(createVersionTagsRoutes)); - setGlobalData<GlobalPluginData>({ + setGlobalData({ path: normalizeUrl([baseUrl, options.routeBasePath]), versions: loadedVersions.map(toGlobalDataVersion), breadcrumbs, diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 5d7aa1e04d21..3d3898e0cf86 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -68,7 +68,7 @@ declare module '@docusaurus/plugin-content-docs' { }; export type VersionsOptions = { lastVersion?: string; - versions: Record<string, VersionOptions>; + versions: {[versionName: string]: VersionOptions}; onlyIncludeVersions?: string[]; }; export type SidebarOptions = { @@ -89,7 +89,7 @@ declare module '@docusaurus/plugin-content-docs' { docTagDocListComponent: string; docTagsListComponent: string; docCategoryGeneratedIndexComponent: string; - admonitions: Record<string, unknown>; + admonitions: {[key: string]: unknown}; disableVersioning: boolean; includeCurrentVersion: boolean; sidebarItemsGenerator: import('./sidebars/types').SidebarItemsGeneratorOption; @@ -282,7 +282,7 @@ declare module '@docusaurus/plugin-content-docs/client' { export type ActiveDocContext = { activeVersion?: GlobalVersion; activeDoc?: GlobalDoc; - alternateDocVersions: Record<string, GlobalDoc>; + alternateDocVersions: {[versionName: string]: GlobalDoc}; }; export type GlobalDoc = { id: string; @@ -297,7 +297,7 @@ declare module '@docusaurus/plugin-content-docs/client' { path: string; mainDocId: string; // home doc (if docs homepage configured), or first doc docs: GlobalDoc[]; - sidebars?: Record<string, GlobalSidebar>; + sidebars?: {[sidebarId: string]: GlobalSidebar}; }; export type GlobalSidebarLink = { @@ -322,7 +322,7 @@ declare module '@docusaurus/plugin-content-docs/client' { }; export type GetActivePluginOptions = {failfast?: boolean}; // use fail-fast option if you know for sure one plugin instance is active - export const useAllDocsData: () => Record<string, GlobalPluginData>; + export const useAllDocsData: () => {[pluginId: string]: GlobalPluginData}; export const useDocsData: (pluginId?: string) => GlobalPluginData; export const useActivePlugin: ( options?: GetActivePluginOptions, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts index 15390eb4b89a..1dad824917f9 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts @@ -57,7 +57,7 @@ describe('processSidebars', () => { async function testProcessSidebars( unprocessedSidebars: NormalizedSidebars, - categoriesMetadata: Record<string, CategoryMetadataFile> = {}, + categoriesMetadata: {[filePath: string]: CategoryMetadataFile} = {}, paramsOverrides: Partial<SidebarProcessorParams> = {}, ) { return processSidebars(unprocessedSidebars, categoriesMetadata, { @@ -142,7 +142,6 @@ describe('processSidebars', () => { }, numberPrefixParser: DefaultNumberPrefixParser, isCategoryIndex, - options: params.sidebarOptions, }); expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({ defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator, @@ -154,7 +153,6 @@ describe('processSidebars', () => { }, numberPrefixParser: DefaultNumberPrefixParser, isCategoryIndex, - options: params.sidebarOptions, }); expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({ defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator, @@ -166,7 +164,6 @@ describe('processSidebars', () => { }, numberPrefixParser: DefaultNumberPrefixParser, isCategoryIndex, - options: params.sidebarOptions, }); expect(processedSidebar).toEqual({ diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index 1b75e8e65ee0..540f379a7f06 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -680,7 +680,7 @@ describe('toNavigationLink', () => { return {...data, frontMatter: {}} as DocMetadataBase; } - const docsById: Record<string, DocMetadataBase> = { + const docsById: {[docId: string]: DocMetadataBase} = { doc1: testDoc({ title: 'Doc 1', permalink: '/doc1', diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts index 6f99428f6e29..7e5fa5b6a557 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts @@ -48,16 +48,10 @@ function toSidebarItemsGeneratorVersion( // post-processing checks async function processSidebar( unprocessedSidebar: NormalizedSidebar, - categoriesMetadata: Record<string, CategoryMetadataFile>, + categoriesMetadata: {[filePath: string]: CategoryMetadataFile}, params: SidebarProcessorParams, ): Promise<ProcessedSidebar> { - const { - sidebarItemsGenerator, - numberPrefixParser, - docs, - version, - sidebarOptions, - } = params; + const {sidebarItemsGenerator, numberPrefixParser, docs, version} = params; // Just a minor lazy transformation optimization const getSidebarItemsGeneratorDocsAndVersion = _.memoize(() => ({ @@ -74,7 +68,6 @@ async function processSidebar( defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator, isCategoryIndex, ...getSidebarItemsGeneratorDocsAndVersion(), - options: sidebarOptions, categoriesMetadata, }); // Process again... weird but sidebar item generated might generate some @@ -113,7 +106,7 @@ async function processSidebar( export async function processSidebars( unprocessedSidebars: NormalizedSidebars, - categoriesMetadata: Record<string, CategoryMetadataFile>, + categoriesMetadata: {[filePath: string]: CategoryMetadataFile}, params: SidebarProcessorParams, ): Promise<ProcessedSidebars> { const processedSidebars = await combinePromises( diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index f9f6895ec96b..8ad3c310b7a6 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -15,11 +15,11 @@ import type { import type {Slugger} from '@docusaurus/utils'; // Makes all properties visible when hovering over the type -type Expand<T extends Record<string, unknown>> = {[P in keyof T]: T[P]}; +type Expand<T extends {[x: string]: unknown}> = {[P in keyof T]: T[P]}; export type SidebarItemBase = { className?: string; - customProps?: Record<string, unknown>; + customProps?: {[key: string]: unknown}; }; export type SidebarItemDoc = SidebarItemBase & { @@ -216,7 +216,7 @@ export type CategoryMetadataFile = { collapsible?: boolean; className?: string; link?: SidebarItemCategoryLinkConfig | null; - customProps?: Record<string, unknown>; + customProps?: {[key: string]: unknown}; // TODO should we allow "items" here? how would this work? would an // "autogenerated" type be allowed? @@ -247,8 +247,7 @@ export type SidebarItemsGeneratorArgs = { docs: SidebarItemsGeneratorDoc[]; numberPrefixParser: NumberPrefixParser; isCategoryIndex: CategoryIndexMatcher; - categoriesMetadata: Record<string, CategoryMetadataFile>; - options: SidebarOptions; + categoriesMetadata: {[filePath: string]: CategoryMetadataFile}; }; export type SidebarItemsGenerator = ( generatorArgs: SidebarItemsGeneratorArgs, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index 6f8875f985e0..5caa93d94884 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -107,15 +107,15 @@ export function collectSidebarNavigation( }); } -export function collectSidebarsDocIds( - sidebars: Sidebars, -): Record<string, string[]> { +export function collectSidebarsDocIds(sidebars: Sidebars): { + [sidebarId: string]: string[]; +} { return _.mapValues(sidebars, collectSidebarDocIds); } -export function collectSidebarsNavigations( - sidebars: Sidebars, -): Record<string, SidebarNavigationItem[]> { +export function collectSidebarsNavigations(sidebars: Sidebars): { + [sidebarId: string]: SidebarNavigationItem[]; +} { return _.mapValues(sidebars, collectSidebarNavigation); } @@ -360,7 +360,7 @@ export function toDocNavigationLink(doc: DocMetadataBase): DocNavLink { export function toNavigationLink( navigationItem: SidebarNavigationItem | undefined, - docsById: Record<string, DocMetadataBase>, + docsById: {[docId: string]: DocMetadataBase}, ): DocNavLink | undefined { function getDocById(docId: string) { const doc = docsById[docId]; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/validation.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/validation.ts index 9ee2115e131c..22ddcfbf77ce 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/validation.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/validation.ts @@ -149,9 +149,9 @@ function validateSidebarItem( } } -export function validateSidebars( - sidebars: Record<string, unknown>, -): asserts sidebars is NormalizedSidebars { +export function validateSidebars(sidebars: { + [sidebarId: string]: unknown; +}): asserts sidebars is NormalizedSidebars { Object.values(sidebars as NormalizedSidebars).forEach((sidebar) => { sidebar.forEach(validateSidebarItem); }); diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index ea902a72764d..40d9e24f0a6b 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -269,7 +269,7 @@ function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles { } function translateVersion( version: LoadedVersion, - translationFiles: Record<string, TranslationFile>, + translationFiles: {[fileName: string]: TranslationFile}, ): LoadedVersion { const versionTranslations = translationFiles[getVersionFileName(version.versionName)]!.content; @@ -289,7 +289,7 @@ function getVersionsTranslationFiles( } function translateVersions( versions: LoadedVersion[], - translationFiles: Record<string, TranslationFile>, + translationFiles: {[fileName: string]: TranslationFile}, ): LoadedVersion[] { return versions.map((version) => translateVersion(version, translationFiles)); } @@ -303,7 +303,7 @@ export function translateLoadedContent( loadedContent: LoadedContent, translationFiles: TranslationFile[], ): LoadedContent { - const translationFilesMap: Record<string, TranslationFile> = _.keyBy( + const translationFilesMap: {[fileName: string]: TranslationFile} = _.keyBy( translationFiles, (f) => f.path, ); diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 67ba6366b5dd..7da32a8a3691 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -59,7 +59,7 @@ export type DocFrontMatter = { sidebar_label?: string; sidebar_position?: number; sidebar_class_name?: string; - sidebar_custom_props?: Record<string, unknown>; + sidebar_custom_props?: {[key: string]: unknown}; displayed_sidebar?: string | null; pagination_label?: string; custom_edit_url?: string | null; @@ -83,7 +83,7 @@ export type DocMetadataBase = LastUpdateData & { sidebarPosition?: number; editUrl?: string | null; tags: Tag[]; - frontMatter: DocFrontMatter & Record<string, unknown>; + frontMatter: DocFrontMatter & {[key: string]: unknown}; }; export type DocNavLink = { diff --git a/packages/docusaurus-plugin-content-pages/src/deps.d.ts b/packages/docusaurus-plugin-content-pages/src/deps.d.ts index c9976d8a584b..6b8b33906b54 100644 --- a/packages/docusaurus-plugin-content-pages/src/deps.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/deps.d.ts @@ -6,7 +6,7 @@ */ declare module 'remark-admonitions' { - type Options = Record<string, unknown>; + type Options = {[key: string]: unknown}; const plugin: (options?: Options) => void; export = plugin; diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 3f5162925594..8c9247da710a 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -20,8 +20,8 @@ const PageFrontMatterSchema = Joi.object<FrontMatter>({ ...FrontMatterTOCHeadingLevels, }); -export function validatePageFrontMatter( - frontMatter: Record<string, unknown>, -): FrontMatter { +export function validatePageFrontMatter(frontMatter: { + [key: string]: unknown; +}): FrontMatter { return validateFrontMatter(frontMatter, PageFrontMatterSchema); } diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index 7993b6abdc7f..fabded2ba633 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -15,7 +15,7 @@ declare module '@docusaurus/plugin-content-pages' { include: string[]; exclude: string[]; mdxPageComponent: string; - admonitions: Record<string, unknown>; + admonitions: {[key: string]: unknown}; }; export type Options = Partial<PluginOptions>; @@ -39,7 +39,7 @@ declare module '@docusaurus/plugin-content-pages' { type: 'mdx'; permalink: string; source: string; - frontMatter: FrontMatter & Record<string, unknown>; + frontMatter: FrontMatter & {[key: string]: unknown}; title?: string; description?: string; }; diff --git a/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx b/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx index 362252d71958..ceac7dea5d19 100644 --- a/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx +++ b/packages/docusaurus-plugin-debug/src/theme/DebugContent/index.tsx @@ -31,7 +31,7 @@ function PluginContent({ pluginContent, }: { pluginName: string; - pluginContent: Record<string, unknown>; + pluginContent: {[pluginId: string]: unknown}; }) { return ( <section style={{marginBottom: 60}}> diff --git a/packages/docusaurus-plugin-google-gtag/src/gtag.ts b/packages/docusaurus-plugin-google-gtag/src/gtag.ts index 9cf397488f7f..77024f7bb5ed 100644 --- a/packages/docusaurus-plugin-google-gtag/src/gtag.ts +++ b/packages/docusaurus-plugin-google-gtag/src/gtag.ts @@ -14,7 +14,7 @@ export default (function gtagModule() { return null; } - const {trackingID} = globalData['docusaurus-plugin-google-gtag'] + const {trackingID} = globalData['docusaurus-plugin-google-gtag']! .default as PluginOptions; return { diff --git a/packages/docusaurus-plugin-ideal-image/src/deps.d.ts b/packages/docusaurus-plugin-ideal-image/src/deps.d.ts index 187065004d85..769d0561cc60 100644 --- a/packages/docusaurus-plugin-ideal-image/src/deps.d.ts +++ b/packages/docusaurus-plugin-ideal-image/src/deps.d.ts @@ -68,7 +68,7 @@ declare module '@endiliey/react-ideal-image' { * from material design, Implemented as React components with the SVG * element. You can customize icons */ - icons?: Partial<Record<IconKey, ComponentType>>; + icons?: Partial<{[icon in IconKey]: ComponentType}>; /** * This prop takes one of the 2 options, xhr and image. * Read more about it: @@ -102,7 +102,7 @@ declare module '@endiliey/react-ideal-image' { * inline styles, but it is also possible to use CSS modules and override * all styles. */ - theme?: Partial<Record<ThemeKey, string | CSSProperties>>; + theme?: Partial<{[key in ThemeKey]: string | CSSProperties}>; /** * Tells how much to wait in milliseconds until consider the download to be * slow. diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/sync.md b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/sync.md new file mode 100644 index 000000000000..4da6d88d3410 --- /dev/null +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__fixtures__/sync.md @@ -0,0 +1,11 @@ +```bash npm2yarn +npm install --global docusaurus +``` + +```bash npm2yarn +npm install --save docusaurus-plugin-name +``` + +```bash npm2yarn +npm run build +``` diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap index 9b3a2be47cab..d00ba962a458 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap @@ -48,6 +48,21 @@ import TabItem from '@theme/TabItem'; " `; +exports[`npm2yarn plugin does not work when language is not set 1`] = ` +"\`\`\`npm2yarn +npm install --save docusaurus-plugin-name +\`\`\` + +\`\`\`bash +npm install --save docusaurus-plugin-name +\`\`\` + +\`\`\`shell +npm install --save docusaurus-plugin-name +\`\`\` +" +`; + exports[`npm2yarn plugin works on installation file 1`] = ` "import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -98,17 +113,29 @@ yarn add docusaurus-plugin-name " `; -exports[`npm2yarn plugin works when language is not set 1`] = ` -"\`\`\`npm2yarn -npm install --save docusaurus-plugin-name -\`\`\` +exports[`npm2yarn plugin works with sync option 1`] = ` +"import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Installing a plugin + +A plugin is usually a npm package, so you install them like other npm packages using npm. + +<Tabs groupId=\\"npm2yarn\\"> +<TabItem value=\\"npm\\"> \`\`\`bash npm install --save docusaurus-plugin-name \`\`\` -\`\`\`shell -npm install --save docusaurus-plugin-name +</TabItem> +<TabItem value=\\"yarn\\" label=\\"Yarn\\"> + +\`\`\`bash +yarn add docusaurus-plugin-name \`\`\` + +</TabItem> +</Tabs> " `; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts index c8425b874f61..4887b0ac9d23 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/index.test.ts @@ -16,10 +16,7 @@ import mdx from 'remark-mdx'; const processFixture = async (name: string, options?: {sync?: boolean}) => { const filePath = path.join(__dirname, '__fixtures__', `${name}.md`); const file = await vfile.read(filePath); - const result = await remark() - .use(mdx) - .use(npm2yarn, {...options, filePath}) - .process(file); + const result = await remark().use(mdx).use(npm2yarn, options).process(file); return result.toString(); }; @@ -37,7 +34,13 @@ describe('npm2yarn plugin', () => { expect(result).toMatchSnapshot(); }); - it('works when language is not set', async () => { + it('works with sync option', async () => { + const result = await processFixture('plugin', {sync: true}); + + expect(result).toMatchSnapshot(); + }); + + it('does not work when language is not set', async () => { const result = await processFixture('syntax-not-properly-set'); expect(result).toMatchSnapshot(); diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index 1b0abbe7bb8e..d2cb4d7184bf 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -12,14 +12,14 @@ import {normalizeThemeConfig} from '@docusaurus/utils-validation'; import theme from 'prism-react-renderer/themes/github'; import darkTheme from 'prism-react-renderer/themes/dracula'; -function testValidateThemeConfig(partialThemeConfig: Record<string, unknown>) { +function testValidateThemeConfig(partialThemeConfig: {[key: string]: unknown}) { return normalizeThemeConfig(ThemeConfigSchema, { ...DEFAULT_CONFIG, ...partialThemeConfig, }); } -function testOk(partialThemeConfig: Record<string, unknown>) { +function testOk(partialThemeConfig: {[key: string]: unknown}) { expect( testValidateThemeConfig({...DEFAULT_CONFIG, ...partialThemeConfig}), ).toEqual({ diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index b010f0038594..440eb8bbfc41 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -507,7 +507,7 @@ declare module '@theme/MDXComponents' { readonly h4: (props: ComponentProps<'h4'>) => JSX.Element; readonly h5: (props: ComponentProps<'h5'>) => JSX.Element; readonly h6: (props: ComponentProps<'h6'>) => JSX.Element; - } & Record<string, ComponentType<unknown>>; + } & {[tagName: string]: ComponentType<unknown>}; const MDXComponents: MDXComponentsObject; export default MDXComponents; @@ -768,7 +768,7 @@ declare module '@theme/TabItem' { readonly label?: string; readonly hidden?: boolean; readonly className?: string; - readonly attributes?: Record<string, unknown>; + readonly attributes?: {[key: string]: unknown}; } export default function TabItem(props: Props): JSX.Element; @@ -786,7 +786,7 @@ declare module '@theme/Tabs' { readonly values?: readonly { value: string; label?: string; - attributes?: Record<string, unknown>; + attributes?: {[key: string]: unknown}; }[]; readonly groupId?: string; readonly className?: string; diff --git a/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx index 679feaf85897..daadce8000be 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx @@ -70,10 +70,9 @@ function UnmaintainedVersionLabel({ ); } -const BannerLabelComponents: Record< - VersionBanner, - ComponentType<BannerLabelComponentProps> -> = { +const BannerLabelComponents: { + [banner in VersionBanner]: ComponentType<BannerLabelComponentProps>; +} = { unreleased: UnreleasedVersionLabel, unmaintained: UnmaintainedVersionLabel, }; diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx index 36227964eb6a..bfaf413fd04b 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx @@ -7,8 +7,9 @@ import React, {isValidElement} from 'react'; import CodeBlock from '@theme/CodeBlock'; +import type {Props} from '@theme/MDXComponents/Pre'; -export default function MDXPre(props: any) { +export default function MDXPre(props: Props): JSX.Element { return ( <CodeBlock // If this pre is created by a ``` fenced codeblock, unwrap the children diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx index 33985d537e3e..d9c5e9d30df8 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx @@ -14,12 +14,11 @@ import LocaleDropdownNavbarItem from '@theme/NavbarItem/LocaleDropdownNavbarItem import SearchNavbarItem from '@theme/NavbarItem/SearchNavbarItem'; import type {Types, Props} from '@theme/NavbarItem'; -const NavbarItemComponents: Record< - Exclude<Types, undefined>, +const NavbarItemComponents: { // Not really worth typing, as we pass all props down immediately // eslint-disable-next-line @typescript-eslint/no-explicit-any - () => (props: any) => JSX.Element -> = { + [type in Exclude<Types, undefined>]: () => (props: any) => JSX.Element; +} = { default: () => DefaultNavbarItem, localeDropdown: () => LocaleDropdownNavbarItem, search: () => SearchNavbarItem, diff --git a/packages/docusaurus-theme-classic/src/translations.ts b/packages/docusaurus-theme-classic/src/translations.ts index 2ec3f977098a..8d8bd673b48d 100644 --- a/packages/docusaurus-theme-classic/src/translations.ts +++ b/packages/docusaurus-theme-classic/src/translations.ts @@ -184,7 +184,7 @@ export function translateThemeConfig({ themeConfig: ThemeConfig; translationFiles: TranslationFile[]; }): ThemeConfig { - const translationFilesMap: Record<string, TranslationFile> = _.keyBy( + const translationFilesMap: {[fileName: string]: TranslationFile} = _.keyBy( translationFiles, (f) => f.path, ); diff --git a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx index cd4bb935b683..a2da2c71b699 100644 --- a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx @@ -84,7 +84,7 @@ function readStorageState({ }: { pluginIds: string[]; versionPersistence: DocsVersionPersistence; - allDocsData: Record<string, GlobalPluginData>; + allDocsData: {[pluginId: string]: GlobalPluginData}; }): DocsPreferredVersionState { /** * The storage value we read might be stale, and belong to a version that does @@ -227,10 +227,9 @@ export function useDocsPreferredVersion( return {preferredVersion, savePreferredVersionName}; } -export function useDocsPreferredVersionByPluginId(): Record< - string, - GlobalVersion | null -> { +export function useDocsPreferredVersionByPluginId(): { + [pluginId: string]: GlobalVersion | null; +} { const allDocsData = useAllDocsData(); const [state] = useDocsPreferredVersionContext(); diff --git a/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx index 72b561d053b3..47919921e851 100644 --- a/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx +++ b/packages/docusaurus-theme-common/src/contexts/tabGroupChoice.tsx @@ -37,7 +37,7 @@ function useContextValue(): ContextValue { useEffect(() => { try { - const localStorageChoices: Record<string, string> = {}; + const localStorageChoices: {[groupId: string]: string} = {}; listStorageKeys().forEach((storageKey) => { if (storageKey.startsWith(TAB_CHOICE_PREFIX)) { const groupId = storageKey.substring(TAB_CHOICE_PREFIX.length); diff --git a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts index 4405a8631d27..99dfdc9d379f 100644 --- a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts @@ -33,11 +33,11 @@ function getTagLetter(tag: string): string { export function listTagsByLetters( tags: readonly TagsListItem[], ): TagLetterEntry[] { - const groups: Record<string, TagsListItem[]> = {}; + const groups: {[initial: string]: TagsListItem[]} = {}; Object.values(tags).forEach((tag) => { - const letter = getTagLetter(tag.name); - groups[letter] ??= []; - groups[letter]!.push(tag); + const initial = getTagLetter(tag.name); + groups[initial] ??= []; + groups[initial]!.push(tag); }); return ( diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index 8d301370883f..684b573b96cf 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -17,7 +17,7 @@ export type NavbarItem = { items?: NavbarItem[]; label?: string; position?: 'left' | 'right'; -} & Record<string, unknown>; +} & {[key: string]: unknown}; export type NavbarLogo = { src: string; @@ -65,7 +65,7 @@ export type FooterLinkItem = { href?: string; html?: string; prependBaseUrlToHref?: string; -} & Record<string, unknown>; +} & {[key: string]: unknown}; export type FooterLogo = { alt?: string; @@ -119,7 +119,7 @@ export type ThemeConfig = { hideableSidebar: boolean; autoCollapseSidebarCategories: boolean; image?: string; - metadata: Array<Record<string, string>>; + metadata: Array<{[key: string]: string}>; sidebarCollapsible: boolean; tableOfContents: TableOfContents; }; diff --git a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts index 7f753e496ef9..6d0cb4cfca1c 100644 --- a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts @@ -8,8 +8,8 @@ import type {Joi} from '@docusaurus/utils-validation'; import {validateThemeConfig, DEFAULT_CONFIG} from '../validateThemeConfig'; -function testValidateThemeConfig(themeConfig: Record<string, unknown>) { - function validate(schema: Joi.Schema, cfg: Record<string, unknown>) { +function testValidateThemeConfig(themeConfig: {[key: string]: unknown}) { + function validate(schema: Joi.Schema, cfg: {[key: string]: unknown}) { const {value, error} = schema.validate(cfg, { convert: false, }); diff --git a/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts b/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts index 3689679f1f26..1aea75deabb3 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts +++ b/packages/docusaurus-theme-search-algolia/src/theme-search-algolia.d.ts @@ -15,7 +15,7 @@ declare module '@docusaurus/theme-search-algolia' { appId: string; apiKey: string; indexName: string; - searchParameters: Record<string, unknown>; + searchParameters: {[key: string]: unknown}; searchPagePath: string | false | null; }; }; diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx index 8ce17fa12a75..5a79ce31050f 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchPage/index.tsx @@ -54,15 +54,16 @@ function useDocsSearchVersionsHelpers() { // State of the version select menus / algolia facet filters // docsPluginId -> versionName map - const [searchVersions, setSearchVersions] = useState<Record<string, string>>( - () => - Object.entries(allDocsData).reduce( - (acc, [pluginId, pluginData]) => ({ - ...acc, - [pluginId]: pluginData.versions[0]!.name, - }), - {}, - ), + const [searchVersions, setSearchVersions] = useState<{ + [pluginId: string]: string; + }>(() => + Object.entries(allDocsData).reduce( + (acc, [pluginId, pluginData]) => ({ + ...acc, + [pluginId]: pluginData.versions[0]!.name, + }), + {}, + ), ); // Set the value of a single select menu diff --git a/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts index e88aa90f14d5..0dc8db25977f 100644 --- a/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts +++ b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts @@ -26,7 +26,7 @@ describe('theme translations', () => { (await fs.readJSON( path.join(baseMessagesDirPath, baseMessagesFile), 'utf-8', - )) as Record<string, string>, + )) as {[key: string]: string}, ), ), ).then((translations) => diff --git a/packages/docusaurus-theme-translations/src/index.ts b/packages/docusaurus-theme-translations/src/index.ts index ef39ca61e987..f586fe0d9ffd 100644 --- a/packages/docusaurus-theme-translations/src/index.ts +++ b/packages/docusaurus-theme-translations/src/index.ts @@ -39,7 +39,7 @@ export async function readDefaultCodeTranslationMessages({ dirPath?: string; locale: string; name: string; -}): Promise<Record<string, string>> { +}): Promise<{[msgId: string]: string}> { const localesToTry = codeTranslationLocalesToTry(locale); // Return the content of the first file that match diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 21bcdf60c9b0..41866831df71 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -91,7 +91,7 @@ export type Config = Overwrite< * package.json. * - `type: 'synthetic'`, docusaurus generated internal plugin. */ -export type DocusaurusPluginVersionInformation = +export type PluginVersionInformation = | { readonly type: 'package'; readonly name?: string; @@ -104,7 +104,7 @@ export type DocusaurusPluginVersionInformation = export interface DocusaurusSiteMetadata { readonly docusaurusVersion: string; readonly siteVersion?: string; - readonly pluginVersions: Record<string, DocusaurusPluginVersionInformation>; + readonly pluginVersions: {[pluginName: string]: PluginVersionInformation}; } // Inspired by Chrome JSON, because it's a widely supported i18n format @@ -114,7 +114,7 @@ export interface DocusaurusSiteMetadata { // https://docs.transifex.com/formats/chrome-json // https://help.phrase.com/help/chrome-json-messages export type TranslationMessage = {message: string; description?: string}; -export type TranslationFileContent = Record<string, TranslationMessage>; +export type TranslationFileContent = {[key: string]: TranslationMessage}; export type TranslationFile = {path: string; content: TranslationFileContent}; export type TranslationFiles = TranslationFile[]; @@ -127,22 +127,24 @@ export type I18nLocaleConfig = { export type I18nConfig = { defaultLocale: string; locales: [string, ...string[]]; - localeConfigs: Record<string, Partial<I18nLocaleConfig>>; + localeConfigs: {[locale: string]: Partial<I18nLocaleConfig>}; }; export type I18n = { defaultLocale: string; locales: [string, ...string[]]; currentLocale: string; - localeConfigs: Record<string, I18nLocaleConfig>; + localeConfigs: {[locale: string]: I18nLocaleConfig}; }; +export type GlobalData = {[pluginName: string]: {[pluginId: string]: unknown}}; + export interface DocusaurusContext { siteConfig: DocusaurusConfig; siteMetadata: DocusaurusSiteMetadata; - globalData: Record<string, unknown>; + globalData: GlobalData; i18n: I18n; - codeTranslations: Record<string, string>; + codeTranslations: {[msgId: string]: string}; // Don't put mutable values here, to avoid triggering re-renders // We could reconsider that choice if context selectors are implemented @@ -162,7 +164,7 @@ export type ImportedPresetModule = PresetModule & { default?: PresetModule; }; -export type PresetConfig = string | [string, Record<string, unknown>]; +export type PresetConfig = string | [string, {[key: string]: unknown}]; export type HostPortCLIOptions = { host?: string; @@ -207,7 +209,7 @@ export interface LoadContext { baseUrl: string; // TODO to remove: useless, there's already siteConfig.baseUrl! i18n: I18n; ssrTemplate: string; - codeTranslations: Record<string, string>; + codeTranslations: {[msgId: string]: string}; } export interface InjectedHtmlTags { @@ -228,7 +230,7 @@ export interface Props extends LoadContext, InjectedHtmlTags { export interface PluginContentLoadedActions { addRoute: (config: RouteConfig) => void; createData: (name: string, data: string) => Promise<string>; - setGlobalData: <T = unknown>(data: T) => void; + setGlobalData: (data: unknown) => void; } export type AllContent = { @@ -238,7 +240,7 @@ export type AllContent = { }; // TODO improve type (not exposed by postcss-loader) -export type PostCssOptions = Record<string, unknown> & {plugins: unknown[]}; +export type PostCssOptions = {[key: string]: unknown} & {plugins: unknown[]}; export interface Plugin<Content = unknown> { name: string; @@ -290,7 +292,7 @@ export interface Plugin<Content = unknown> { export type InitializedPlugin<Content = unknown> = Plugin<Content> & { readonly options: Required<PluginOptions>; - readonly version: DocusaurusPluginVersionInformation; + readonly version: PluginVersionInformation; /** * The absolute path to the folder containing the entry point file. */ @@ -305,12 +307,12 @@ export type SwizzleAction = 'eject' | 'wrap'; export type SwizzleActionStatus = 'safe' | 'unsafe' | 'forbidden'; export type SwizzleComponentConfig = { - actions: Record<SwizzleAction, SwizzleActionStatus>; + actions: {[action in SwizzleAction]: SwizzleActionStatus}; description?: string; }; export type SwizzleConfig = { - components: Record<string, SwizzleComponentConfig>; + components: {[componentName: string]: SwizzleComponentConfig}; // Other settings could be added here, // For example: the ability to declare the config as exhaustive // so that we can emit errors @@ -332,13 +334,12 @@ export type ImportedPluginModule = PluginModule & { }; export type ConfigureWebpackFn = Plugin<unknown>['configureWebpack']; -export type ConfigureWebpackFnMergeStrategy = Record< - string, - CustomizeRuleString ->; +export type ConfigureWebpackFnMergeStrategy = { + [key: string]: CustomizeRuleString; +}; export type ConfigurePostCssFn = Plugin<unknown>['configurePostCss']; -export type PluginOptions = {id?: string} & Record<string, unknown>; +export type PluginOptions = {id?: string} & {[key: string]: unknown}; export type PluginConfig = | string @@ -416,7 +417,7 @@ export interface ConfigureWebpackUtils { ) => RuleSetRule[]; getJSLoader: (options: { isServer: boolean; - babelOptions?: Record<string, unknown>; + babelOptions?: {[key: string]: unknown}; }) => RuleSetRule; } @@ -425,7 +426,7 @@ interface HtmlTagObject { * Attributes of the html tag * E.g. `{'disabled': true, 'value': 'demo', 'rel': 'preconnect'}` */ - attributes?: Partial<Record<string, string | boolean>>; + attributes?: Partial<{[key: string]: string | boolean}>; /** * The tag name e.g. `div`, `script`, `link`, `meta` */ diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index fed60afc8e22..33145624da4d 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -77,7 +77,7 @@ export function normalizeThemeConfig<T>( * Validate front matter with better error message */ export function validateFrontMatter<T>( - frontMatter: Record<string, unknown>, + frontMatter: {[key: string]: unknown}, schema: Joi.ObjectSchema<T>, ): T { const {value, error, warning} = schema.validate(frontMatter, { diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index a84e8f7a727c..2fe8cb7d34e3 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -12,7 +12,7 @@ import fs from 'fs-extra'; describe('genChunkName', () => { it('works', () => { - const firstAssert: Record<string, string> = { + const firstAssert: {[key: string]: string} = { '/docs/adding-blog': 'docs-adding-blog-062', '/docs/versioning': 'docs-versioning-8a8', '/': 'index', @@ -34,7 +34,7 @@ describe('genChunkName', () => { }); it('emits different chunk names for different paths even with same preferred name', () => { - const secondAssert: Record<string, string> = { + const secondAssert: {[key: string]: string} = { '/blog/1': 'blog-85-f-089', '/blog/2': 'blog-353-489', }; @@ -44,7 +44,7 @@ describe('genChunkName', () => { }); it('only generates short unique IDs', () => { - const thirdAssert: Record<string, string> = { + const thirdAssert: {[key: string]: string} = { a: '0cc175b9', b: '92eb5ffe', c: '4a8a08f0', diff --git a/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts b/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts index ab73d5073701..6cc32c0e4640 100644 --- a/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/hashUtils.test.ts @@ -9,7 +9,7 @@ import {simpleHash, docuHash} from '../hashUtils'; describe('hashUtils', () => { it('simpleHash', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { '': 'd41', '/foo-bar': '096', '/foo/bar': '1df', @@ -30,7 +30,7 @@ describe('hashUtils', () => { describe('docuHash', () => { it('docuHash works', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { '': '-d41', '/': 'index', '/foo-bar': 'foo-bar-096', diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index b196e2a45b10..49a2844b4721 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -45,15 +45,15 @@ describe('mapAsyncSequential', () => { } it('maps sequentially', async () => { - const itemToTimeout: Record<string, number> = { + const itemToTimeout: {[key: string]: number} = { '1': 200, '2': 600, '3': 400, }; const items = Object.keys(itemToTimeout); - const itemMapStartsAt: Record<string, number> = {}; - const itemMapEndsAt: Record<string, number> = {}; + const itemMapStartsAt: {[key: string]: number} = {}; + const itemMapEndsAt: {[key: string]: number} = {}; const timeBefore = Date.now(); await expect( diff --git a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts index 2eebb267eae6..eaf2b61cd906 100644 --- a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts @@ -131,7 +131,7 @@ describe('toMessageRelativeFilePath', () => { describe('escapePath', () => { it('works', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { 'c:/aaaa\\bbbb': 'c:/aaaa\\\\bbbb', 'c:\\aaaa\\bbbb\\★': 'c:\\\\aaaa\\\\bbbb\\\\★', '\\\\?\\c:\\aaaa\\bbbb': '\\\\\\\\?\\\\c:\\\\aaaa\\\\bbbb', @@ -148,7 +148,7 @@ describe('escapePath', () => { describe('posixPath', () => { it('works', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { 'c:/aaaa\\bbbb': 'c:/aaaa/bbbb', 'c:\\aaaa\\bbbb\\★': 'c:\\aaaa\\bbbb\\★', '\\\\?\\c:\\aaaa\\bbbb': '\\\\?\\c:\\aaaa\\bbbb', @@ -165,7 +165,7 @@ describe('posixPath', () => { describe('aliasedSitePath', () => { it('works', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { 'user/website/docs/asd.md': '@site/docs/asd.md', 'user/website/versioned_docs/foo/bar.md': '@site/versioned_docs/foo/bar.md', diff --git a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts index ce067a14899c..30625e400554 100644 --- a/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/urlUtils.test.ts @@ -170,7 +170,7 @@ describe('getEditUrl', () => { describe('fileToPath', () => { it('works', () => { - const asserts: Record<string, string> = { + const asserts: {[key: string]: string} = { 'index.md': '/', 'hello/index.md': '/hello/', 'foo.md': '/foo', diff --git a/packages/docusaurus-utils/src/markdownLinks.ts b/packages/docusaurus-utils/src/markdownLinks.ts index c05012d902d9..fe8353646cd1 100644 --- a/packages/docusaurus-utils/src/markdownLinks.ts +++ b/packages/docusaurus-utils/src/markdownLinks.ts @@ -69,7 +69,7 @@ export function replaceMarkdownLinks<T extends ContentPaths>({ /** * A map from source paths to their URLs. Source paths are `@site` aliased. */ - sourceToPermalink: Record<string, string>; + sourceToPermalink: {[aliasedPath: string]: string}; }): { /** * The content with all Markdown file references replaced with their URLs. diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index 3e0d2c615dd1..de92ce0f33b3 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -143,7 +143,7 @@ export function createExcerpt(fileString: string): string | undefined { */ export function parseFrontMatter(markdownFileContent: string): { /** Front matter as parsed by gray-matter. */ - frontMatter: Record<string, unknown>; + frontMatter: {[key: string]: unknown}; /** The remaining content, trimmed. */ content: string; } { @@ -244,7 +244,7 @@ export function parseMarkdownString( options?: ParseMarkdownContentTitleOptions, ): { /** @see {@link parseFrontMatter} */ - frontMatter: Record<string, unknown>; + frontMatter: {[key: string]: unknown}; /** @see {@link parseMarkdownContentTitle} */ contentTitle: string | undefined; /** @see {@link createExcerpt} */ diff --git a/packages/docusaurus/src/choosePort.ts b/packages/docusaurus/src/choosePort.ts index 618df3e69ea0..8fec0ff0b9c8 100644 --- a/packages/docusaurus/src/choosePort.ts +++ b/packages/docusaurus/src/choosePort.ts @@ -18,12 +18,12 @@ import prompts from 'prompts'; const isInteractive = process.stdout.isTTY; -const execOptions: Record<string, unknown> = { - encoding: 'utf8', +const execOptions = { + encoding: 'utf8' as const, stdio: [ - 'pipe', // stdin (default) - 'pipe', // stdout (default) - 'ignore', // stderr + 'pipe' as const, // stdin (default) + 'pipe' as const, // stdout (default) + 'ignore' as const, // stderr ], }; @@ -37,19 +37,18 @@ function clearConsole(): void { // Gets process id of what is on port function getProcessIdOnPort(port: number): string { return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions) - .toString() .split('\n')[0]! .trim(); } // Gets process command function getProcessCommand(processId: string): string { - const command: Buffer = execSync( + const command = execSync( `ps -o command -p ${processId} | sed -n 2p`, execOptions, ); - return command.toString().replace(/\n$/, ''); + return command.replace(/\n$/, ''); } // Gets directory of a process from its process id @@ -57,9 +56,7 @@ function getDirectoryOfProcessById(processId: string): string { return execSync( `lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions, - ) - .toString() - .trim(); + ).trim(); } // Gets process on port diff --git a/packages/docusaurus/src/client/docusaurus.ts b/packages/docusaurus/src/client/docusaurus.ts index 0c024c0fc43b..20923a84d48e 100644 --- a/packages/docusaurus/src/client/docusaurus.ts +++ b/packages/docusaurus/src/client/docusaurus.ts @@ -12,8 +12,8 @@ import prefetchHelper from './prefetch'; import preloadHelper from './preload'; import flat from './flat'; -const fetched: Record<string, boolean> = {}; -const loaded: Record<string, boolean> = {}; +const fetched: {[key: string]: boolean} = {}; +const loaded: {[key: string]: boolean} = {}; declare global { // eslint-disable-next-line camelcase, no-underscore-dangle diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index b33b8cff35ed..9d59a19492be 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -13,8 +13,6 @@ import registry from '@generated/registry'; import flat from '../flat'; import {RouteContextProvider} from '../routeContext'; -type OptsLoader = Record<string, typeof registry[keyof typeof registry][0]>; - export default function ComponentCreator( path: string, hash: string, @@ -40,7 +38,8 @@ export default function ComponentCreator( const chunkNames = routesChunkNames[chunkNamesKey]!; const optsModules: string[] = []; const optsWebpack: string[] = []; - const optsLoader: OptsLoader = {}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const optsLoader: {[key: string]: () => Promise<any>} = {}; /* Prepare opts data that react-loadable needs https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded diff --git a/packages/docusaurus/src/client/exports/useGlobalData.ts b/packages/docusaurus/src/client/exports/useGlobalData.ts index 155ee22e6fe6..598f87dfe972 100644 --- a/packages/docusaurus/src/client/exports/useGlobalData.ts +++ b/packages/docusaurus/src/client/exports/useGlobalData.ts @@ -7,8 +7,9 @@ import useDocusaurusContext from './useDocusaurusContext'; import {DEFAULT_PLUGIN_ID} from './constants'; +import type {GlobalData} from '@docusaurus/types'; -export default function useGlobalData(): Record<string, unknown> { +export default function useGlobalData(): GlobalData { const {globalData} = useDocusaurusContext(); if (!globalData) { throw new Error('Docusaurus global data not found.'); @@ -16,9 +17,9 @@ export default function useGlobalData(): Record<string, unknown> { return globalData; } -export function useAllPluginInstancesData<T = unknown>( +export function useAllPluginInstancesData( pluginName: string, -): Record<string, T> { +): GlobalData[string] { const globalData = useGlobalData(); const pluginGlobalData = globalData[pluginName]; if (!pluginGlobalData) { @@ -26,13 +27,13 @@ export function useAllPluginInstancesData<T = unknown>( `Docusaurus plugin global data not found for "${pluginName}" plugin.`, ); } - return pluginGlobalData as Record<string, T>; + return pluginGlobalData; } -export function usePluginData<T = unknown>( +export function usePluginData( pluginName: string, pluginId: string = DEFAULT_PLUGIN_ID, -): T { +): GlobalData[string][string] { const pluginGlobalData = useAllPluginInstancesData(pluginName); const pluginInstanceGlobalData = pluginGlobalData[pluginId]; if (!pluginInstanceGlobalData) { @@ -40,5 +41,5 @@ export function usePluginData<T = unknown>( `Docusaurus plugin global data not found for "${pluginName}" plugin with id "${pluginId}".`, ); } - return pluginInstanceGlobalData as T; + return pluginInstanceGlobalData; } diff --git a/packages/docusaurus/src/client/flat.ts b/packages/docusaurus/src/client/flat.ts index d1c7fe5fea46..76b2f57a378c 100644 --- a/packages/docusaurus/src/client/flat.ts +++ b/packages/docusaurus/src/client/flat.ts @@ -10,9 +10,11 @@ import type {RouteChunksTree} from '@docusaurus/types'; const isTree = (x: string | RouteChunksTree): x is RouteChunksTree => typeof x === 'object' && !!x && Object.keys(x).length > 0; -export default function flat(target: RouteChunksTree): Record<string, string> { +export default function flat(target: RouteChunksTree): { + [keyPath: string]: string; +} { const delimiter = '.'; - const output: Record<string, string> = {}; + const output: {[keyPath: string]: string} = {}; function step(object: RouteChunksTree, prefix?: string | number) { Object.entries(object).forEach(([key, value]) => { diff --git a/packages/docusaurus/src/client/normalizeLocation.ts b/packages/docusaurus/src/client/normalizeLocation.ts index 6d443c316ec0..94a74da70044 100644 --- a/packages/docusaurus/src/client/normalizeLocation.ts +++ b/packages/docusaurus/src/client/normalizeLocation.ts @@ -8,7 +8,7 @@ import type {Location} from 'history'; // Memoize previously normalized pathnames. -const pathnames: Record<string, string> = {}; +const pathnames: {[rawPathname: string]: string} = {}; export default function normalizeLocation<T extends Location>(location: T): T { if (pathnames[location.pathname]) { diff --git a/packages/docusaurus/src/client/prefetch.ts b/packages/docusaurus/src/client/prefetch.ts index 338f1b14fbf2..8223c7d89d56 100644 --- a/packages/docusaurus/src/client/prefetch.ts +++ b/packages/docusaurus/src/client/prefetch.ts @@ -65,7 +65,7 @@ const supportedPrefetchStrategy = support('prefetch') ? linkPrefetchStrategy : xhrPrefetchStrategy; -const preFetched: Record<string, boolean> = {}; +const preFetched: {[url: string]: boolean} = {}; export default function prefetch(url: string): Promise<void> { return new Promise((resolve) => { diff --git a/packages/docusaurus/src/commands/build.ts b/packages/docusaurus/src/commands/build.ts index bc1e7f557a18..e72761653397 100644 --- a/packages/docusaurus/src/commands/build.ts +++ b/packages/docusaurus/src/commands/build.ts @@ -146,7 +146,7 @@ async function buildLocale({ }, ); - const allCollectedLinks: Record<string, string[]> = {}; + const allCollectedLinks: {[location: string]: string[]} = {}; let serverConfig: Configuration = await createServerConfig({ props, diff --git a/packages/docusaurus/src/commands/swizzle/common.ts b/packages/docusaurus/src/commands/swizzle/common.ts index 84449a009d0a..1dfdb04cf3ae 100644 --- a/packages/docusaurus/src/commands/swizzle/common.ts +++ b/packages/docusaurus/src/commands/swizzle/common.ts @@ -29,10 +29,9 @@ export function actionStatusLabel(status: SwizzleActionStatus): string { return _.capitalize(status); } -const SwizzleActionStatusColors: Record< - SwizzleActionStatus, - (str: string) => string -> = { +const SwizzleActionStatusColors: { + [status in SwizzleActionStatus]: (str: string) => string; +} = { safe: logger.green, unsafe: logger.yellow, forbidden: logger.red, diff --git a/packages/docusaurus/src/deps.d.ts b/packages/docusaurus/src/deps.d.ts index fc3a7287ff55..f977549c7c7a 100644 --- a/packages/docusaurus/src/deps.d.ts +++ b/packages/docusaurus/src/deps.d.ts @@ -17,8 +17,8 @@ declare module 'react-loadable-ssr-addon-v5-slorber' { export type Manifest = { entrypoints: string[]; - origins: Record<string, number[]>; - assets: Array<Record<string, Asset[]>>; + origins: {[key: string]: number[]}; + assets: Array<{[key: string]: Asset[]}>; }; export function getBundles( @@ -36,7 +36,7 @@ declare module 'react-loadable-ssr-addon-v5-slorber' { declare module '@slorber/static-site-generator-webpack-plugin' { export type Locals = { - routesLocation: Record<string, string>; + routesLocation: {[filePath: string]: string}; generatedFilesDir: string; headTags: string; preBodyTags: string; @@ -53,7 +53,7 @@ declare module '@slorber/static-site-generator-webpack-plugin' { locals: Locals; paths: string[]; preferFoldersOutput?: boolean; - globals: Record<string, unknown>; + globals: {[key: string]: unknown}; }); } diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts index e156599ce61f..c213ca19ef84 100644 --- a/packages/docusaurus/src/server/brokenLinks.ts +++ b/packages/docusaurus/src/server/brokenLinks.ts @@ -75,9 +75,9 @@ function getAllBrokenLinks({ allCollectedLinks, routes, }: { - allCollectedLinks: Record<string, string[]>; + allCollectedLinks: {[location: string]: string[]}; routes: RouteConfig[]; -}): Record<string, BrokenLink[]> { +}): {[location: string]: BrokenLink[]} { const filteredRoutes = filterIntermediateRoutes(routes); const allBrokenLinks = _.mapValues(allCollectedLinks, (pageLinks, pagePath) => @@ -88,9 +88,9 @@ function getAllBrokenLinks({ return _.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0); } -function getBrokenLinksErrorMessage( - allBrokenLinks: Record<string, BrokenLink[]>, -): string | undefined { +function getBrokenLinksErrorMessage(allBrokenLinks: { + [location: string]: BrokenLink[]; +}): string | undefined { if (Object.keys(allBrokenLinks).length === 0) { return undefined; } @@ -177,8 +177,8 @@ async function filterExistingFileLinks({ }: { baseUrl: string; outDir: string; - allCollectedLinks: Record<string, string[]>; -}): Promise<Record<string, string[]>> { + allCollectedLinks: {[location: string]: string[]}; +}): Promise<{[location: string]: string[]}> { async function linkFileExists(link: string) { // /baseUrl/javadoc/ -> /outDir/javadoc const baseFilePath = onlyPathname( @@ -222,7 +222,7 @@ export async function handleBrokenLinks({ baseUrl, outDir, }: { - allCollectedLinks: Record<string, string[]>; + allCollectedLinks: {[location: string]: string[]}; onBrokenLinks: ReportingSeverity; routes: RouteConfig[]; baseUrl: string; diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index a45418ced64c..ae4c371c1f7b 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -404,7 +404,7 @@ ${Object.entries(registry) JSON.stringify(i18n, null, 2), ); - const codeTranslationsWithFallbacks: Record<string, string> = { + const codeTranslationsWithFallbacks: {[msgId: string]: string} = { ...(await getPluginsDefaultCodeTranslationMessages(plugins)), ...codeTranslations, }; diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 56142e8c66ae..fc2cf0cff7ef 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -14,6 +14,7 @@ import type { PluginContentLoadedActions, RouteConfig, AllContent, + GlobalData, TranslationFiles, ThemeConfig, LoadedPlugin, @@ -75,7 +76,7 @@ export async function loadPlugins({ }): Promise<{ plugins: LoadedPlugin[]; pluginsRouteConfigs: RouteConfig[]; - globalData: unknown; + globalData: GlobalData; themeConfigTranslated: ThemeConfig; }> { // 1. Plugin Lifecycle - Initialization/Constructor. @@ -135,7 +136,7 @@ export async function loadPlugins({ // 3. Plugin Lifecycle - contentLoaded. const pluginsRouteConfigs: RouteConfig[] = []; - const globalData: Record<string, Record<string, unknown>> = {}; + const globalData: GlobalData = {}; await Promise.all( contentLoadedTranslatedPlugins.map( diff --git a/packages/docusaurus/src/server/plugins/init.ts b/packages/docusaurus/src/server/plugins/init.ts index 918476e983f3..410eb96f7ca6 100644 --- a/packages/docusaurus/src/server/plugins/init.ts +++ b/packages/docusaurus/src/server/plugins/init.ts @@ -9,7 +9,7 @@ import {createRequire} from 'module'; import path from 'path'; import importFresh from 'import-fresh'; import type { - DocusaurusPluginVersionInformation, + PluginVersionInformation, ImportedPluginModule, LoadContext, PluginModule, @@ -151,7 +151,7 @@ export default async function initPlugins({ async function doGetPluginVersion( normalizedPluginConfig: NormalizedPluginConfig, - ): Promise<DocusaurusPluginVersionInformation> { + ): Promise<PluginVersionInformation> { // get plugin version if (normalizedPluginConfig.pluginModule?.path) { const pluginPath = pluginRequire.resolve( @@ -198,8 +198,9 @@ export default async function initPlugins({ async function initializePlugin( normalizedPluginConfig: NormalizedPluginConfig, ): Promise<InitializedPlugin> { - const pluginVersion: DocusaurusPluginVersionInformation = - await doGetPluginVersion(normalizedPluginConfig); + const pluginVersion: PluginVersionInformation = await doGetPluginVersion( + normalizedPluginConfig, + ); const pluginOptions = doValidatePluginOptions(normalizedPluginConfig); // Side-effect: merge the normalized theme config in the original one diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index ba5508bfd97c..b6221ec4b277 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -103,8 +103,8 @@ function isModule(value: unknown): value is Module { if ( typeof value === 'object' && // eslint-disable-next-line no-underscore-dangle - (value as Record<string, unknown>)?.__import && - (value as Record<string, unknown>)?.path + (value as {[key: string]: unknown})?.__import && + (value as {[key: string]: unknown})?.path ) { return true; } diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index 1b3458b2979e..0cd6b0b37313 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -265,7 +265,7 @@ export async function localizePluginTranslationFile({ export async function getPluginsDefaultCodeTranslationMessages( plugins: InitializedPlugin[], -): Promise<Record<string, string>> { +): Promise<{[msgId: string]: string}> { const pluginsMessages = await Promise.all( plugins.map((plugin) => plugin.getDefaultCodeTranslationMessages?.() ?? {}), ); @@ -280,9 +280,9 @@ export function applyDefaultCodeTranslations({ extractedCodeTranslations, defaultCodeMessages, }: { - extractedCodeTranslations: Record<string, TranslationMessage>; - defaultCodeMessages: Record<string, string>; -}): Record<string, TranslationMessage> { + extractedCodeTranslations: {[msgId: string]: TranslationMessage}; + defaultCodeMessages: {[msgId: string]: string}; +}): {[msgId: string]: TranslationMessage} { const unusedDefaultCodeMessages = _.difference( Object.keys(defaultCodeMessages), Object.keys(extractedCodeTranslations), diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index 0c74a548e4ac..3be8f1f13b34 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -130,7 +130,7 @@ function logSourceCodeFileTranslationsWarnings( type SourceCodeFileTranslations = { sourceCodeFilePath: string; - translations: Record<string, TranslationMessage>; + translations: {[msgId: string]: TranslationMessage}; warnings: string[]; }; @@ -189,7 +189,7 @@ function extractSourceCodeAstTranslations( Full code: ${generate(node).code}`; } - const translations: Record<string, TranslationMessage> = {}; + const translations: {[msgId: string]: TranslationMessage} = {}; const warnings: string[] = []; let translateComponentName: string | undefined; let translateFunctionName: string | undefined; diff --git a/packages/docusaurus/src/server/versions/index.ts b/packages/docusaurus/src/server/versions/index.ts index e2f717419bc9..54a3777fd1d3 100644 --- a/packages/docusaurus/src/server/versions/index.ts +++ b/packages/docusaurus/src/server/versions/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {DocusaurusPluginVersionInformation} from '@docusaurus/types'; +import type {PluginVersionInformation} from '@docusaurus/types'; import fs from 'fs-extra'; import path from 'path'; @@ -29,7 +29,7 @@ async function getPackageJsonName( export async function getPluginVersion( pluginPath: string, siteDir: string, -): Promise<DocusaurusPluginVersionInformation> { +): Promise<PluginVersionInformation> { let potentialPluginPackageJsonDirectory = path.dirname(pluginPath); while (potentialPluginPackageJsonDirectory !== '/') { const packageJsonPath = path.join( diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 7f4f9631397f..8754e70c9d3b 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -44,11 +44,13 @@ export function excludeJS(modulePath: string): boolean { ); } -export async function getDocusaurusAliases(): Promise<Record<string, string>> { +export async function getDocusaurusAliases(): Promise<{ + [aliasName: string]: string; +}> { const dirPath = path.resolve(__dirname, '../client/exports'); const extensions = ['.js', '.ts', '.tsx']; - const aliases: Record<string, string> = {}; + const aliases: {[key: string]: string} = {}; (await fs.readdir(dirPath)) .filter((fileName) => extensions.includes(path.extname(fileName))) diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts index cc3578d05865..3adc362a41da 100644 --- a/packages/docusaurus/src/webpack/server.ts +++ b/packages/docusaurus/src/webpack/server.ts @@ -37,7 +37,7 @@ export default async function createServerConfig({ } = props; const config = await createBaseConfig(props, true); - const routesLocation: Record<string, string> = {}; + const routesLocation: {[filePath: string]: string} = {}; // Array of paths to be rendered. Relative to output directory const ssgPaths = routesPaths.map((str) => { const ssgPath = diff --git a/packages/lqip-loader/src/lqip.ts b/packages/lqip-loader/src/lqip.ts index 537e036843e5..f6ab095a1868 100644 --- a/packages/lqip-loader/src/lqip.ts +++ b/packages/lqip-loader/src/lqip.ts @@ -14,7 +14,7 @@ const {version} = require('../package.json'); const ERROR_EXT = `Error: Input file is missing or uses unsupported image format, lqip v${version}`; -const SUPPORTED_MIMES: Record<string, string> = { +const SUPPORTED_MIMES: {[ext: string]: string} = { jpeg: 'image/jpeg', jpg: 'image/jpeg', png: 'image/png', diff --git a/website/docs/docusaurus-core.md b/website/docs/docusaurus-core.md index 6fec152f626a..00a2848715c9 100644 --- a/website/docs/docusaurus-core.md +++ b/website/docs/docusaurus-core.md @@ -335,7 +335,7 @@ You can even omit the children prop and specify a translation string in your `co React hook to access Docusaurus Context. The context contains the `siteConfig` object from [docusaurus.config.js](api/docusaurus.config.js.md) and some additional site metadata. ```ts -type DocusaurusPluginVersionInformation = +type PluginVersionInformation = | {readonly type: 'package'; readonly version?: string} | {readonly type: 'project'} | {readonly type: 'local'} @@ -344,7 +344,7 @@ type DocusaurusPluginVersionInformation = interface DocusaurusSiteMetadata { readonly docusaurusVersion: string; readonly siteVersion?: string; - readonly pluginVersions: Record<string, DocusaurusPluginVersionInformation>; + readonly pluginVersions: Record<string, PluginVersionInformation>; } interface I18nLocaleConfig { diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index cd9fe43af7b2..624ca2c8d42f 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -74,7 +74,7 @@ export type User = { // Available tags to assign to your site // Please choose all tags that you think might apply. // We'll remove inappropriate tags, but it's less likely that we add tags. -export const Tags: Record<TagType, Tag> = { +export const Tags: {[type in TagType]: Tag} = { // DO NOT USE THIS TAG: we choose sites to add to favorites favorite: { label: 'Favorite', diff --git a/website/src/utils/colorUtils.ts b/website/src/utils/colorUtils.ts index 78c4895c4b24..faecb4341ba1 100644 --- a/website/src/utils/colorUtils.ts +++ b/website/src/utils/colorUtils.ts @@ -19,15 +19,14 @@ export type ColorState = { shades: Shades; }; -export type Shades = Record< - string, - { +export type Shades = { + [cssVar: string]: { adjustment: number; adjustmentInput: string; displayOrder: number; codeOrder: number; - } ->; + }; +}; export const COLOR_SHADES: Shades = { '--ifm-color-primary': { adjustment: 0, diff --git a/website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md b/website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md index 6fec152f626a..00a2848715c9 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md +++ b/website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md @@ -335,7 +335,7 @@ You can even omit the children prop and specify a translation string in your `co React hook to access Docusaurus Context. The context contains the `siteConfig` object from [docusaurus.config.js](api/docusaurus.config.js.md) and some additional site metadata. ```ts -type DocusaurusPluginVersionInformation = +type PluginVersionInformation = | {readonly type: 'package'; readonly version?: string} | {readonly type: 'project'} | {readonly type: 'local'} @@ -344,7 +344,7 @@ type DocusaurusPluginVersionInformation = interface DocusaurusSiteMetadata { readonly docusaurusVersion: string; readonly siteVersion?: string; - readonly pluginVersions: Record<string, DocusaurusPluginVersionInformation>; + readonly pluginVersions: Record<string, PluginVersionInformation>; } interface I18nLocaleConfig { diff --git a/website/versioned_docs/version-2.0.0-beta.17/docusaurus-core.md b/website/versioned_docs/version-2.0.0-beta.17/docusaurus-core.md index 6fec152f626a..00a2848715c9 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/docusaurus-core.md +++ b/website/versioned_docs/version-2.0.0-beta.17/docusaurus-core.md @@ -335,7 +335,7 @@ You can even omit the children prop and specify a translation string in your `co React hook to access Docusaurus Context. The context contains the `siteConfig` object from [docusaurus.config.js](api/docusaurus.config.js.md) and some additional site metadata. ```ts -type DocusaurusPluginVersionInformation = +type PluginVersionInformation = | {readonly type: 'package'; readonly version?: string} | {readonly type: 'project'} | {readonly type: 'local'} @@ -344,7 +344,7 @@ type DocusaurusPluginVersionInformation = interface DocusaurusSiteMetadata { readonly docusaurusVersion: string; readonly siteVersion?: string; - readonly pluginVersions: Record<string, DocusaurusPluginVersionInformation>; + readonly pluginVersions: Record<string, PluginVersionInformation>; } interface I18nLocaleConfig { From e606e62a6a6478da4808c210eeef6a10d9e73984 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Fri, 25 Mar 2022 13:06:47 +0300 Subject: [PATCH 065/405] refactor: better external link icon positioning (#6994) --- .../src/theme/DocSidebarItem/index.tsx | 15 ++++++++++----- .../src/theme/DocSidebarItem/styles.module.css | 4 ++++ .../src/theme/IconExternalLink/styles.module.css | 2 -- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index f0a422ebf161..eca309416aa5 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -250,6 +250,7 @@ function DocSidebarItemLink({ }: Props & {item: PropSidebarItemLink}) { const {href, label, className} = item; const isActive = isActiveSidebarItem(item, activePath); + const isInternalLink = isInternalUrl(href); return ( <li className={clsx( @@ -260,17 +261,21 @@ function DocSidebarItemLink({ )} key={label}> <Link - className={clsx('menu__link', { - 'menu__link--active': isActive, - })} + className={clsx( + 'menu__link', + !isInternalLink && styles.menuExternalLink, + { + 'menu__link--active': isActive, + }, + )} aria-current={isActive ? 'page' : undefined} to={href} - {...(isInternalUrl(href) && { + {...(isInternalLink && { onClick: onItemClick ? () => onItemClick(item) : undefined, })} {...props}> {label} - {!isInternalUrl(href) && <IconExternalLink />} + {!isInternalLink && <IconExternalLink />} </Link> </li> ); diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css index 2bb6934d33ee..e8a2d6c96052 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css @@ -11,3 +11,7 @@ var(--ifm-menu-link-padding-horizontal); } } + +.menuExternalLink { + align-items: center; +} diff --git a/packages/docusaurus-theme-classic/src/theme/IconExternalLink/styles.module.css b/packages/docusaurus-theme-classic/src/theme/IconExternalLink/styles.module.css index 1e8964ae9a9c..7b0a5ad13d39 100644 --- a/packages/docusaurus-theme-classic/src/theme/IconExternalLink/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/IconExternalLink/styles.module.css @@ -7,6 +7,4 @@ .iconExternalLink { margin-left: 0.3rem; - position: relative; - top: 1px; } From 78ecff907a0992e3ee9d58ce565d59d84c530935 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Fri, 25 Mar 2022 14:17:42 +0300 Subject: [PATCH 066/405] refactor(theme-classic): clean up CSS of doc cards (#6950) Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../src/theme/DocCard/index.tsx | 41 +++++++++++-------- .../src/theme/DocCard/styles.module.css | 25 ++++------- .../src/theme/DocCardList/index.tsx | 17 ++++++-- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx index de65d3d642b5..15c8ac155d51 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx @@ -22,20 +22,15 @@ function CardContainer({ href, children, }: { - href?: string; + href: string; children: ReactNode; }): JSX.Element { - const className = clsx( - 'card margin-bottom--lg padding--lg', - styles.cardContainer, - href && styles.cardContainerLink, - ); - return href ? ( - <Link href={href} className={className}> + return ( + <Link + href={href} + className={clsx('card padding--lg', styles.cardContainer)}> {children} </Link> - ) : ( - <div className={className}>{children}</div> ); } @@ -45,7 +40,7 @@ function CardLayout({ title, description, }: { - href?: string; + href: string; icon: ReactNode; title: string; description?: string; @@ -55,17 +50,29 @@ function CardLayout({ <h2 className={clsx('text--truncate', styles.cardTitle)} title={title}> {icon} {title} </h2> - <div - className={clsx('text--truncate', styles.cardDescription)} - title={description}> - {description} - </div> + {description && ( + <p + className={clsx('text--truncate', styles.cardDescription)} + title={description}> + {description} + </p> + )} </CardContainer> ); } -function CardCategory({item}: {item: PropSidebarItemCategory}): JSX.Element { +function CardCategory({ + item, +}: { + item: PropSidebarItemCategory; +}): JSX.Element | null { const href = findFirstCategoryLink(item); + + // Unexpected: categories that don't have a link have been filtered upfront + if (!href) { + return null; + } + return ( <CardLayout href={href} diff --git a/packages/docusaurus-theme-classic/src/theme/DocCard/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocCard/styles.module.css index bd098eb5fe9e..63c3d9856b70 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCard/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocCard/styles.module.css @@ -6,38 +6,29 @@ */ .cardContainer { - height: 8rem; - color: var(--ifm-color-emphasis-800); --ifm-link-color: var(--ifm-color-emphasis-800); - --ifm-link-hover-color: var(--ifm-color-emphasis-800); + --ifm-link-hover-color: var(--ifm-color-emphasis-700); --ifm-link-hover-decoration: none; - /* box-shadow: var(--ifm-global-shadow-lw); */ box-shadow: 0 1.5px 3px 0 rgb(0 0 0 / 15%); border: 1px solid var(--ifm-color-emphasis-200); - transition: box-shadow var(--ifm-transition-fast) ease, - background-color var(--ifm-transition-fast) ease; + transition: all var(--ifm-transition-fast) ease; + transition-property: border, box-shadow; } -.cardContainer.cardContainerLink:hover { - /* box-shadow: var(--ifm-global-shadow-md); */ - box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%); +.cardContainer:hover { + border-color: var(--ifm-color-primary); + box-shadow: 0 3px 6px 0 rgb(0 0 0 / 20%); } -[data-theme='dark'] .cardContainer.cardContainerLink:hover { - --ifm-card-background-color: #2d2d2d; /* original, non-hovered color is #242526 */ -} - -.cardContainer:not(.cardContainerLink) { - cursor: not-allowed; +.cardContainer *:last-child { + margin-bottom: 0; } .cardTitle { font-size: 1.2rem; - min-height: 1.2rem; } .cardDescription { font-size: 0.8rem; - min-height: 0.8rem; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx index fec4a34eb948..052e88292523 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx @@ -9,6 +9,17 @@ import React from 'react'; import DocCard from '@theme/DocCard'; import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; +import {findFirstCategoryLink} from '@docusaurus/theme-common'; + +// Filter categories that don't have a link. +function filterItems(items: PropSidebarItem[]): PropSidebarItem[] { + return items.filter((item) => { + if (item.type === 'category') { + return !!findFirstCategoryLink(item); + } + return true; + }); +} export default function DocCardList({ items, @@ -17,9 +28,9 @@ export default function DocCardList({ }): JSX.Element { return ( <div className="row"> - {items.map((item, index) => ( - <article key={index} className="col col--6"> - <DocCard item={item} /> + {filterItems(items).map((item, index) => ( + <article key={index} className="col col--6 margin-bottom--lg"> + <DocCard key={index} item={item} /> </article> ))} </div> From c2ac22ec15a7737beeb978720966c20e7e713bf3 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Fri, 25 Mar 2022 14:56:00 +0300 Subject: [PATCH 067/405] refactor(theme-classic): cleanup of code blocks (#6987) --- .../src/theme/CodeBlock/CopyButton/index.tsx | 1 - .../docusaurus-theme-classic/src/theme/CodeBlock/index.tsx | 4 +--- .../src/theme/CodeBlock/styles.module.css | 4 +--- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx index dbc48c99d2f9..cedc4834d14a 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx @@ -42,7 +42,6 @@ export default function CopyButton({code}: Props): JSX.Element { description: 'The ARIA label for copy code blocks button', }) } - // @todo: check it again later title={translate({ id: 'theme.CodeBlock.copy', message: 'Copy', diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index 943d3f84676e..40ab6581fddb 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -111,9 +111,7 @@ export default function CodeBlock({ {codeBlockTitle} </div> )} - <div - className={clsx(styles.codeBlockContent, language)} - style={style}> + <div className={styles.codeBlockContent} style={style}> <pre /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */ tabIndex={0} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index fcdcca6b1c09..02e1e686768f 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -7,7 +7,6 @@ .codeBlockContainer { margin-bottom: var(--ifm-leading); - border-radius: var(--ifm-global-radius); box-shadow: var(--ifm-global-shadow-lw); } @@ -15,6 +14,7 @@ position: relative; /* rtl:ignore */ direction: ltr; + border-radius: var(--ifm-global-radius); } .codeBlockTitle { @@ -29,7 +29,6 @@ .codeBlock { margin: 0; padding: 0; - border-radius: var(--ifm-global-radius); background-color: inherit; } @@ -40,7 +39,6 @@ .codeBlockStandalone { padding: 0; - border-radius: var(--ifm-global-radius); } .codeBlockLines { From d879cdca96cea4aead25d5029cb75def0a9649d1 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Fri, 25 Mar 2022 15:02:24 +0300 Subject: [PATCH 068/405] refactor: improve a11y of dropdown menu (#6971) Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> --- .../src/theme/NavbarItem/DropdownNavbarItem.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx index 6403cc8f00bb..0c5fc67c3d01 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx @@ -85,6 +85,9 @@ function DropdownNavbarItemDesktop({ 'dropdown--show': showDropdown, })}> <NavbarNavLink + aria-haspopup="true" + aria-expanded={showDropdown} + role="button" href={props.to ? undefined : '#'} className={clsx('navbar__link', className)} {...props} @@ -107,7 +110,13 @@ function DropdownNavbarItemDesktop({ setShowDropdown(false); const nextNavbarItem = dropdownRef.current!.nextElementSibling; if (nextNavbarItem) { - (nextNavbarItem as HTMLElement).focus(); + const targetItem = + nextNavbarItem instanceof HTMLAnchorElement + ? nextNavbarItem + : // Next item is another dropdown; focus on the inner + // anchor element instead so there's outline + nextNavbarItem.querySelector('a'); + (targetItem as HTMLElement).focus(); } } }} From f1bcdbff63aaeb3f1bcbee83b8c3cd85892c5f95 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 21:50:37 +0800 Subject: [PATCH 069/405] fix(validation): improve error messages for a few schemas (#6997) * fix(validation): improve error messages for a few schemas * kick CI * fix test --- .../src/__tests__/options.test.ts | 16 ++-- .../validationSchemas.test.ts.snap | 76 ++++++++++++++----- .../src/validationSchemas.ts | 5 ++ .../configValidation.test.ts.snap | 20 ----- .../server/__tests__/configValidation.test.ts | 33 +++++++- .../docusaurus/src/server/configValidation.ts | 24 +++++- 6 files changed, 122 insertions(+), 52 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 89bec2179df3..8f21906faa5e 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -150,9 +150,11 @@ describe('normalizeDocsPluginOptions', () => { testValidate({ remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]], }), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"remarkPlugins[0]\\" does not match any of the allowed types"`, - ); + ).toThrowErrorMatchingInlineSnapshot(` + "\\"remarkPlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or + - A simple module, like \`require(\\"remark-math\\")\`" + `); }); it('rejects invalid rehype plugin options', () => { @@ -166,9 +168,11 @@ describe('normalizeDocsPluginOptions', () => { ], ], }), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"rehypePlugins[0]\\" does not match any of the allowed types"`, - ); + ).toThrowErrorMatchingInlineSnapshot(` + "\\"rehypePlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or + - A simple module, like \`require(\\"remark-math\\")\`" + `); }); it('rejects bad path inputs', () => { diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index 56a45cbbc2aa..dc6695380d21 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -28,15 +28,35 @@ exports[`validation schemas pluginIdSchema: for value=null 1`] = `"\\"value\\" m exports[`validation schemas pluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; exports[`validation schemas rehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; @@ -44,15 +64,35 @@ exports[`validation schemas rehypePluginsSchema: for value=false 1`] = `"\\"valu exports[`validation schemas rehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; - -exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; + +exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; exports[`validation schemas remarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index bf2bf6826fa1..f49b962a853b 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -23,6 +23,11 @@ const MarkdownPluginsSchema = Joi.array() Joi.function(), Joi.object(), ) + .messages({ + 'array.includes': `{#label} does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), \\{ strict: false \\}]\`, or +- A simple module, like \`require("remark-math")\``, + }) .default([]); export const RemarkPluginsSchema = MarkdownPluginsSchema; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap index aad69e1e286d..0c24cbaf8b8a 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -161,23 +161,3 @@ exports[`normalizeConfig throws error for unknown field 1`] = ` If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. See https://docusaurus.io/docs/docusaurus.config.js/#customfields" `; - -exports[`normalizeConfig throws error if css doesn't have href 1`] = ` -"\\"stylesheets[1]\\" does not match any of the allowed types -" -`; - -exports[`normalizeConfig throws error if presets is not array 1`] = ` -"\\"presets\\" must be an array -" -`; - -exports[`normalizeConfig throws error if scripts doesn't have src 1`] = ` -"\\"scripts[1]\\" does not match any of the allowed types -" -`; - -exports[`normalizeConfig throws error if themes is not array 1`] = ` -"\\"themes\\" must be an array -" -`; diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 90233c353792..b6d606b41701 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -224,7 +224,10 @@ describe('normalizeConfig', () => { normalizeConfig({ themes: {}, }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"themes\\" must be an array + " + `); }); it('throws error if presets is not array', () => { @@ -232,7 +235,23 @@ describe('normalizeConfig', () => { normalizeConfig({ presets: {}, }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"presets\\" must be an array + " + `); + }); + + it('throws error if presets looks invalid', () => { + expect(() => { + normalizeConfig({ + presets: [() => {}], + }); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"presets[0]\\" does not look like a valid preset config. A preset config entry should be one of: + - A tuple of [presetName, options], like \`[\\"classic\\", { blog: false }]\`, or + - A simple string, like \`\\"classic\\"\` + " + `); }); it("throws error if scripts doesn't have src", () => { @@ -240,7 +259,10 @@ describe('normalizeConfig', () => { normalizeConfig({ scripts: ['https://some.com', {}], }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"scripts[1]\\" is invalid. A script must be a plain string (the src), or an object with at least a \\"src\\" property. + " + `); }); it("throws error if css doesn't have href", () => { @@ -248,7 +270,10 @@ describe('normalizeConfig', () => { normalizeConfig({ stylesheets: ['https://somescript.com', {type: 'text/css'}], }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"stylesheets[1]\\" is invalid. A stylesheet must be a plain string (the href), or an object with at least a \\"href\\" property. + " + `); }); it('throws error for required fields', () => { diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index d4dfb2f4fdac..4ad81037565b 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -113,10 +113,18 @@ const PluginSchema = createPluginSchema(false); const ThemeSchema = createPluginSchema(true); -const PresetSchema = Joi.alternatives().try( - Joi.string(), - Joi.array().items(Joi.string().required(), Joi.object().required()).length(2), -); +const PresetSchema = Joi.alternatives() + .try( + Joi.string(), + Joi.array() + .items(Joi.string().required(), Joi.object().required()) + .length(2), + ) + .messages({ + 'alternatives.types': `{#label} does not look like a valid preset config. A preset config entry should be one of: +- A tuple of [presetName, options], like \`["classic", \\{ blog: false \\}]\`, or +- A simple string, like \`"classic"\``, + }); const LocaleConfigSchema = Joi.object({ label: Joi.string(), @@ -190,6 +198,10 @@ export const ConfigSchema = Joi.object({ // See https://github.com/facebook/docusaurus/issues/3378 .unknown(), ) + .messages({ + 'array.includes': + '{#label} is invalid. A script must be a plain string (the src), or an object with at least a "src" property.', + }) .default(DEFAULT_CONFIG.scripts), ssrTemplate: Joi.string(), stylesheets: Joi.array() @@ -200,6 +212,10 @@ export const ConfigSchema = Joi.object({ type: Joi.string(), }).unknown(), ) + .messages({ + 'array.includes': + '{#label} is invalid. A stylesheet must be a plain string (the href), or an object with at least a "href" property.', + }) .default(DEFAULT_CONFIG.stylesheets), clientModules: Joi.array() .items(Joi.string()) From b5ceead3b2a668beca4fd49253fa02e32295307d Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 25 Mar 2022 22:23:11 +0800 Subject: [PATCH 070/405] feat(content-docs): autogenerate category with linked doc metadata as fallback (#6859) --- .../__snapshots__/index.test.ts.snap | 14 +++++ .../__snapshots__/generator.test.ts.snap | 2 +- .../src/sidebars/__tests__/generator.test.ts | 3 +- .../src/sidebars/generator.ts | 61 +++++++++++++------ .../src/sidebars/processor.ts | 1 + .../src/sidebars/types.ts | 1 + .../docs/api/plugins/plugin-content-docs.md | 1 + .../docs/guides/docs/sidebar/autogenerated.md | 2 +- 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 3c40354723ff..44346d589b45 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -1407,6 +1407,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 0, "source": "@site/docs/3-API/01_Core APIs/0 --- Client API.md", "sourceDirName": "3-API/01_Core APIs", + "title": "Client API", "unversionedId": "API/Core APIs/Client API", }, { @@ -1415,6 +1416,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 1, "source": "@site/docs/3-API/01_Core APIs/1 --- Server API.md", "sourceDirName": "3-API/01_Core APIs", + "title": "Server API", "unversionedId": "API/Core APIs/Server API", }, { @@ -1423,6 +1425,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 0, "source": "@site/docs/3-API/02_Extension APIs/0. Plugin API.md", "sourceDirName": "3-API/02_Extension APIs", + "title": "Plugin API", "unversionedId": "API/Extension APIs/Plugin API", }, { @@ -1431,6 +1434,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 1, "source": "@site/docs/3-API/02_Extension APIs/1. Theme API.md", "sourceDirName": "3-API/02_Extension APIs", + "title": "Theme API", "unversionedId": "API/Extension APIs/Theme API", }, { @@ -1439,6 +1443,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 3, "source": "@site/docs/3-API/03_api-end.md", "sourceDirName": "3-API", + "title": "API End", "unversionedId": "API/api-end", }, { @@ -1447,6 +1452,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 0, "source": "@site/docs/3-API/00_api-overview.md", "sourceDirName": "3-API", + "title": "API Overview", "unversionedId": "API/api-overview", }, { @@ -1458,6 +1464,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 1, "source": "@site/docs/Guides/z-guide1.md", "sourceDirName": "Guides", + "title": "Guide 1", "unversionedId": "Guides/guide1", }, { @@ -1468,6 +1475,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 2, "source": "@site/docs/Guides/02-guide2.md", "sourceDirName": "Guides", + "title": "Guide 2", "unversionedId": "Guides/guide2", }, { @@ -1479,6 +1487,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 2.5, "source": "@site/docs/Guides/0-guide2.5.md", "sourceDirName": "Guides", + "title": "Guide 2.5", "unversionedId": "Guides/guide2.5", }, { @@ -1490,6 +1499,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 3, "source": "@site/docs/Guides/guide3.md", "sourceDirName": "Guides", + "title": "Guide 3", "unversionedId": "Guides/guide3", }, { @@ -1500,6 +1510,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": undefined, "source": "@site/docs/Guides/a-guide4.md", "sourceDirName": "Guides", + "title": "Guide 4", "unversionedId": "Guides/guide4", }, { @@ -1510,6 +1521,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": undefined, "source": "@site/docs/Guides/b-guide5.md", "sourceDirName": "Guides", + "title": "Guide 5", "unversionedId": "Guides/guide5", }, { @@ -1518,6 +1530,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 0, "source": "@site/docs/0-getting-started.md", "sourceDirName": ".", + "title": "Getting Started", "unversionedId": "getting-started", }, { @@ -1526,6 +1539,7 @@ exports[`site with custom sidebar items generator sidebarItemsGenerator is calle "sidebarPosition": 1, "source": "@site/docs/1-installation.md", "sourceDirName": ".", + "title": "Installation", "unversionedId": "installation", }, ], diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap index 3ab94d601021..e042c366581d 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/generator.test.ts.snap @@ -116,7 +116,7 @@ exports[`DefaultSidebarItemsGenerator generates subfolder sidebar 1`] = ` "type": "doc", }, ], - "label": "subsubsubfolder3 (_category_.json label)", + "label": "Subsubsubfolder category label", "link": { "id": "doc1", "type": "doc", diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts index 501774ef600e..66281f746b68 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/generator.test.ts @@ -234,7 +234,7 @@ describe('DefaultSidebarItemsGenerator', () => { }, 'subfolder/subsubfolder/subsubsubfolder3': { position: 1, - label: 'subsubsubfolder3 (_category_.json label)', + // This item's label is defined from the index doc instead link: { type: 'doc', id: 'doc1', // This is a "fully-qualified" ID that can't be found locally @@ -246,6 +246,7 @@ describe('DefaultSidebarItemsGenerator', () => { id: 'doc1', source: 'doc1.md', sourceDirName: 'subfolder/subsubfolder', + title: 'Subsubsubfolder category label', sidebarPosition: undefined, frontMatter: {}, }, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts index 5e266bc00564..928731fc4fc5 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts @@ -158,9 +158,6 @@ Available doc IDs: ): WithPosition<NormalizedSidebarItemCategory> { const categoryMetadata = categoriesMetadata[posixPath(path.join(autogenDir, fullPath))]; - const className = categoryMetadata?.className; - const customProps = categoryMetadata?.customProps; - const {filename, numberPrefix} = numberPrefixParser(folderName); const allItems = Object.entries(dir).map(([key, content]) => dirToItem(content, key, `${fullPath}/${key}`), ); @@ -184,41 +181,65 @@ Available doc IDs: }); } - function getCategoryLinkedDocId(): string | undefined { - const link = categoryMetadata?.link; - if (link !== undefined) { - if (link && link.type === 'doc') { - return findDocByLocalId(link.id)?.id || getDoc(link.id).id; + // In addition to the ID, this function also retrieves metadata of the + // linked doc that could be used as fallback values for category metadata + function getCategoryLinkedDocMetadata(): + | { + id: string; + position?: number; + label?: string; + customProps?: {[key: string]: unknown}; + className?: string; } + | undefined { + const link = categoryMetadata?.link; + if (link !== undefined && link?.type !== 'doc') { // If a link is explicitly specified, we won't apply conventions return undefined; } - // Apply default convention to pick index.md, README.md or - // <categoryName>.md as the category doc - return findConventionalCategoryDocLink()?.id; + const id = link + ? findDocByLocalId(link.id)?.id ?? getDoc(link.id).id + : findConventionalCategoryDocLink()?.id; + if (!id) { + return undefined; + } + const doc = getDoc(id); + return { + id, + position: doc.sidebarPosition, + label: doc.frontMatter.sidebar_label ?? doc.title, + customProps: doc.frontMatter.sidebar_custom_props, + className: doc.frontMatter.sidebar_class_name, + }; } - - const categoryLinkedDocId = getCategoryLinkedDocId(); - + const categoryLinkedDoc = getCategoryLinkedDocMetadata(); const link: SidebarItemCategoryLinkConfig | null | undefined = - categoryLinkedDocId + categoryLinkedDoc ? { type: 'doc', - id: categoryLinkedDocId, // We "remap" a potentially "local id" to a "qualified id" + id: categoryLinkedDoc.id, // We "remap" a potentially "local id" to a "qualified id" } : categoryMetadata?.link; - // If a doc is linked, remove it from the category subItems const items = allItems.filter( - (item) => !(item.type === 'doc' && item.id === categoryLinkedDocId), + (item) => !(item.type === 'doc' && item.id === categoryLinkedDoc?.id), ); + const className = + categoryMetadata?.className ?? categoryLinkedDoc?.className; + const customProps = + categoryMetadata?.customProps ?? categoryLinkedDoc?.customProps; + const {filename, numberPrefix} = numberPrefixParser(folderName); + return { type: 'category', - label: categoryMetadata?.label ?? filename, + label: categoryMetadata?.label ?? categoryLinkedDoc?.label ?? filename, collapsible: categoryMetadata?.collapsible, collapsed: categoryMetadata?.collapsed, - position: categoryMetadata?.position ?? numberPrefix, + position: + categoryMetadata?.position ?? + categoryLinkedDoc?.position ?? + numberPrefix, source: folderName, ...(customProps !== undefined && {customProps}), ...(className !== undefined && {className}), diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts index 7e5fa5b6a557..a4f55b6bf5d0 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts @@ -31,6 +31,7 @@ function toSidebarItemsGeneratorDoc( return _.pick(doc, [ 'id', 'unversionedId', + 'title', 'frontMatter', 'source', 'sourceDirName', diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index 8ad3c310b7a6..50a1e6185c2c 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -231,6 +231,7 @@ export type SidebarItemsGeneratorDoc = Pick< DocMetadataBase, | 'id' | 'unversionedId' + | 'title' | 'frontMatter' | 'source' | 'sourceDirName' diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index 2c97cd4ab78e..cf69f8f8a220 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -89,6 +89,7 @@ type SidebarGenerator = (generatorArgs: { version: {contentPath: string; versionName: string}; // the current version docs: Array<{ id: string; + title: string; frontMatter: DocFrontMatter & Record<string, unknown>; source: string; sourceDirName: string; diff --git a/website/docs/guides/docs/sidebar/autogenerated.md b/website/docs/guides/docs/sidebar/autogenerated.md index 0b74e1f61faa..239888b99f30 100644 --- a/website/docs/guides/docs/sidebar/autogenerated.md +++ b/website/docs/guides/docs/sidebar/autogenerated.md @@ -323,7 +323,7 @@ sidebar_class_name: green This is the easy tutorial! ``` -**For categories**: add a `_category_.json` or `_category_.yml` file in the respective folder. You can specify any category metadata and also the `position` metadata. +**For categories**: add a `_category_.json` or `_category_.yml` file in the respective folder. You can specify any category metadata and also the `position` metadata. `label`, `className`, `position`, and `customProps` will default to the respective values of the category's linked doc, if there is one. <Tabs> <TabItem value="JSON"> From 73deaa8bf69e138965433a30d18c0ddc4ecef85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Fri, 25 Mar 2022 16:16:38 +0100 Subject: [PATCH 071/405] chore: prepare v2.0.0-beta.18 release (#7001) --- CHANGELOG.md | 219 ++++++++++++++++++ admin/new.docusaurus.io/package.json | 2 +- lerna.json | 2 +- packages/create-docusaurus/package.json | 4 +- .../templates/classic-typescript/package.json | 8 +- .../templates/classic/package.json | 6 +- .../templates/facebook/package.json | 6 +- .../docusaurus-cssnano-preset/package.json | 2 +- packages/docusaurus-logger/package.json | 2 +- packages/docusaurus-mdx-loader/package.json | 8 +- packages/docusaurus-migrate/package.json | 6 +- .../package.json | 4 +- .../package.json | 14 +- .../package.json | 16 +- .../package.json | 16 +- .../package.json | 12 +- packages/docusaurus-plugin-debug/package.json | 8 +- .../package.json | 8 +- .../package.json | 8 +- .../package.json | 14 +- packages/docusaurus-plugin-pwa/package.json | 14 +- .../docusaurus-plugin-sitemap/package.json | 12 +- .../docusaurus-preset-classic/package.json | 24 +- .../package.json | 2 +- .../docusaurus-theme-classic/package.json | 24 +- packages/docusaurus-theme-common/package.json | 14 +- .../package.json | 12 +- .../package.json | 18 +- .../package.json | 6 +- packages/docusaurus-types/package.json | 2 +- packages/docusaurus-utils-common/package.json | 4 +- .../docusaurus-utils-validation/package.json | 8 +- packages/docusaurus-utils/package.json | 6 +- packages/docusaurus/package.json | 18 +- packages/lqip-loader/package.json | 4 +- packages/stylelint-copyright/package.json | 2 +- website/package.json | 26 +-- .../advanced/architecture.md | 0 .../advanced/client.md | 44 ++++ .../advanced/index.md | 0 .../advanced/plugins.md | 0 .../advanced/routing.md | 0 .../advanced/ssg.md | 0 .../api/docusaurus.config.js.md | 16 +- .../api/plugin-methods/README.md | 0 .../api/plugin-methods/_category_.yml | 0 .../plugin-methods/extend-infrastructure.md | 8 +- .../api/plugin-methods/i18n-lifecycles.md | 0 .../api/plugin-methods/lifecycle-apis.md | 23 +- .../api/plugin-methods/static-methods.md | 0 .../api/plugins/_category_.yml | 0 .../api/plugins/overview.md | 0 .../api/plugins/plugin-client-redirects.md | 0 .../api/plugins/plugin-content-blog.md | 20 +- .../api/plugins/plugin-content-docs.md | 1 + .../api/plugins/plugin-content-pages.md | 0 .../api/plugins/plugin-debug.md | 0 .../api/plugins/plugin-google-analytics.md | 0 .../api/plugins/plugin-google-gtag.md | 0 .../api/plugins/plugin-ideal-image.md | 0 .../api/plugins/plugin-pwa.md | 0 .../api/plugins/plugin-sitemap.md | 0 .../api/themes/_category_.yml | 0 .../api/themes/overview.md | 0 .../api/themes/theme-classic.md | 0 .../api/themes/theme-configuration.md | 21 +- .../api/themes/theme-live-codeblock.md | 0 .../api/themes/theme-search-algolia.md | 0 .../docusaurus-asset-example-banner.png | Bin .../assets/docusaurus-asset-example.docx | Bin .../assets/docusaurus-asset-example.xyz | Bin .../blog.mdx | 11 +- .../browser-support.md | 0 .../cli.md | 10 + .../configuration.md | 0 .../deployment.mdx | 12 +- .../docusaurus-core.md | 0 .../guides/creating-pages.md | 6 +- .../guides/docs/docs-create-doc.mdx | 0 .../guides/docs/docs-introduction.md | 20 +- .../guides/docs/docs-markdown-features.mdx | 0 .../guides/docs/docs-multi-instance.mdx | 0 .../guides/docs/sidebar/autogenerated.md | 7 +- .../guides/docs/sidebar/index.md | 0 .../guides/docs/sidebar/items.md | 0 .../guides/docs/sidebar/multiple-sidebars.md | 0 .../guides/docs/versioning.md | 0 .../_markdown-partial-example.mdx | 0 .../markdown-features-admonitions.mdx | 4 +- .../markdown-features-assets.mdx | 20 +- .../markdown-features-code-blocks.mdx | 148 ++++++------ .../markdown-features-head-metadata.mdx | 16 +- .../markdown-features-headings.mdx | 0 .../markdown-features-inline-toc.mdx | 19 +- .../markdown-features-intro.mdx | 0 .../markdown-features-math-equations.mdx | 9 +- .../markdown-features-plugins.mdx | 0 .../markdown-features-react.mdx | 4 +- .../markdown-features-react.module.css | 0 .../markdown-features-tabs-styles.module.css | 0 .../markdown-features-tabs.mdx | 2 +- .../guides/whats-next.md | 4 +- .../i18n/i18n-crowdin.mdx | 0 .../i18n/i18n-git.md | 0 .../i18n/i18n-introduction.md | 0 .../i18n/i18n-tutorial.md | 0 .../installation.md | 24 +- .../introduction.md | 0 .../migration/migration-automated.md | 0 .../migration/migration-manual.md | 0 .../migration/migration-overview.md | 0 .../migration/migration-translated-sites.md | 0 .../migration/migration-versioned-sites.md | 0 .../playground.mdx | 0 .../search.md | 0 .../seo.md | 37 +-- .../static-assets.md | 0 .../styling-layout.md | 12 +- .../swizzling.md | 0 .../typescript-support.md | 2 +- .../using-plugins.md | 0 ...on => version-2.0.0-beta.18-sidebars.json} | 0 website/versions.json | 4 +- website/versionsArchived.json | 1 + 124 files changed, 690 insertions(+), 376 deletions(-) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/architecture.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/client.md (73%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/index.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/plugins.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/routing.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/advanced/ssg.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/docusaurus.config.js.md (96%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/README.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/_category_.yml (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/extend-infrastructure.md (96%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/i18n-lifecycles.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/lifecycle-apis.md (94%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugin-methods/static-methods.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/_category_.yml (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/overview.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-client-redirects.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-content-blog.md (90%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-content-docs.md (99%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-content-pages.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-debug.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-google-analytics.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-google-gtag.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-ideal-image.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-pwa.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/plugins/plugin-sitemap.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/_category_.yml (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/overview.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/theme-classic.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/theme-configuration.md (96%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/theme-live-codeblock.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/api/themes/theme-search-algolia.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/assets/docusaurus-asset-example-banner.png (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/assets/docusaurus-asset-example.docx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/assets/docusaurus-asset-example.xyz (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/blog.mdx (97%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/browser-support.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/cli.md (96%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/configuration.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/deployment.mdx (97%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/docusaurus-core.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/creating-pages.md (98%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/docs-create-doc.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/docs-introduction.md (85%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/docs-markdown-features.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/docs-multi-instance.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/sidebar/autogenerated.md (97%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/sidebar/index.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/sidebar/items.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/sidebar/multiple-sidebars.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/docs/versioning.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/_markdown-partial-example.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-admonitions.mdx (99%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-assets.mdx (92%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-code-blocks.mdx (87%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-head-metadata.mdx (63%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-headings.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-inline-toc.mdx (81%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-intro.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-math-equations.mdx (95%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-plugins.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-react.mdx (98%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-react.module.css (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-tabs-styles.module.css (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/markdown-features/markdown-features-tabs.mdx (98%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/guides/whats-next.md (89%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/i18n/i18n-crowdin.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/i18n/i18n-git.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/i18n/i18n-introduction.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/i18n/i18n-tutorial.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/installation.md (90%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/introduction.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/migration/migration-automated.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/migration/migration-manual.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/migration/migration-overview.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/migration/migration-translated-sites.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/migration/migration-versioned-sites.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/playground.mdx (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/search.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/seo.md (96%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/static-assets.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/styling-layout.md (91%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/swizzling.md (100%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/typescript-support.md (99%) rename website/versioned_docs/{version-2.0.0-beta.16 => version-2.0.0-beta.18}/using-plugins.md (100%) rename website/versioned_sidebars/{version-2.0.0-beta.16-sidebars.json => version-2.0.0-beta.18-sidebars.json} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9992b28ec895..f30ba836d46b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,224 @@ # Docusaurus 2 Changelog +## 2.0.0-beta.18 (2022-03-25) + +#### :rocket: New Feature + +- `docusaurus-mdx-loader`, `docusaurus-theme-classic` + - [#6990](https://github.com/facebook/docusaurus/pull/6990) feat: lazy-load external images + ability to customize image display ([@slorber](https://github.com/slorber)) +- `docusaurus-module-type-aliases`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus` + - [#6933](https://github.com/facebook/docusaurus/pull/6933) feat(core,theme): useRouteContext + HtmlClassNameProvider ([@slorber](https://github.com/slorber)) +- `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus` + - [#6921](https://github.com/facebook/docusaurus/pull/6921) feat(core): allow plugin lifecycles to return relative paths ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-classic` + - [#6697](https://github.com/facebook/docusaurus/pull/6697) feat: add SEO microdata for doc breadcrumbs ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6842](https://github.com/facebook/docusaurus/pull/6842) feat(theme-classic): MDXContent wrapper component ([@slorber](https://github.com/slorber)) +- `docusaurus-plugin-content-docs` + - [#6780](https://github.com/facebook/docusaurus/pull/6780) feat(content-docs): allow custom props through _category_.json ([@taejs](https://github.com/taejs)) + +#### :boom: Breaking Change + +- `docusaurus-plugin-content-docs` + - [#6859](https://github.com/facebook/docusaurus/pull/6859) feat(content-docs): autogenerate category with linked doc metadata as fallback ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-classic` + - [#6989](https://github.com/facebook/docusaurus/pull/6989) refactor: extract MDX components ([@slorber](https://github.com/slorber)) +- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus` + - [#6925](https://github.com/facebook/docusaurus/pull/6925) refactor(theme-{classic,common}): refactor site/page/search metadata + apply className on html element ([@slorber](https://github.com/slorber)) +- `docusaurus-theme-classic`, `docusaurus-theme-common` + - [#6895](https://github.com/facebook/docusaurus/pull/6895) refactor(theme-{classic,common}): split navbar into smaller components + cleanup + swizzle config ([@slorber](https://github.com/slorber)) + - [#6930](https://github.com/facebook/docusaurus/pull/6930) refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook ([@lex111](https://github.com/lex111)) + +#### :bug: Bug Fix + +- `docusaurus` + - [#6993](https://github.com/facebook/docusaurus/pull/6993) fix(core): prevent useBaseUrl returning /base/base when on /base ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6936](https://github.com/facebook/docusaurus/pull/6936) fix: remove semicolon from HTML output ([@lex111](https://github.com/lex111)) + - [#6849](https://github.com/facebook/docusaurus/pull/6849) fix(cli): write-heading-id should not generate colliding slugs when not overwriting ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-classic` + - [#6983](https://github.com/facebook/docusaurus/pull/6983) fix(search): bump Infima, fix search issue due to broken CSS selector ([@slorber](https://github.com/slorber)) +- `docusaurus-utils-validation` + - [#6977](https://github.com/facebook/docusaurus/pull/6977) fix(validation): allow non-object params to remark/rehype plugins ([@aloisklink](https://github.com/aloisklink)) +- `docusaurus-plugin-content-docs`, `docusaurus-utils` + - [#6973](https://github.com/facebook/docusaurus/pull/6973) fix(content-docs): suppress git error on multiple occurrences ([@felipecrs](https://github.com/felipecrs)) +- `docusaurus-plugin-content-blog` + - [#6947](https://github.com/facebook/docusaurus/pull/6947) fix(content-blog): only create archive route if there are blog posts ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6918](https://github.com/facebook/docusaurus/pull/6918) fix(content-blog): remove double leading slash in blog-only paginated view ([@heowc](https://github.com/heowc)) +- `docusaurus-theme-search-algolia` + - [#6888](https://github.com/facebook/docusaurus/pull/6888) fix(theme-algolia): declare content-docs as dependency ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-translations` + - [#6847](https://github.com/facebook/docusaurus/pull/6847) fix: minor Chinese translation fixes ([@rccttwd](https://github.com/rccttwd)) + +#### :nail_care: Polish + +- `docusaurus-plugin-content-docs` + - [#6859](https://github.com/facebook/docusaurus/pull/6859) feat(content-docs): autogenerate category with linked doc metadata as fallback ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6887](https://github.com/facebook/docusaurus/pull/6887) fix(content-docs): give context about sidebar loading failure ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-content-docs`, `docusaurus-utils-validation`, `docusaurus` + - [#6997](https://github.com/facebook/docusaurus/pull/6997) fix(validation): improve error messages for a few schemas ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-classic` + - [#6971](https://github.com/facebook/docusaurus/pull/6971) refactor: improve a11y of dropdown menu ([@lex111](https://github.com/lex111)) + - [#6987](https://github.com/facebook/docusaurus/pull/6987) refactor(theme-classic): cleanup of code blocks ([@lex111](https://github.com/lex111)) + - [#6950](https://github.com/facebook/docusaurus/pull/6950) refactor(theme-classic): clean up CSS of doc cards ([@lex111](https://github.com/lex111)) + - [#6994](https://github.com/facebook/docusaurus/pull/6994) refactor: better external link icon positioning ([@lex111](https://github.com/lex111)) + - [#6989](https://github.com/facebook/docusaurus/pull/6989) refactor: extract MDX components ([@slorber](https://github.com/slorber)) + - [#6985](https://github.com/facebook/docusaurus/pull/6985) refactor(theme-classic): remove span wrappers from layout links ([@lex111](https://github.com/lex111)) + - [#6986](https://github.com/facebook/docusaurus/pull/6986) fix(theme-classic): minor code copy button improvements ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6964](https://github.com/facebook/docusaurus/pull/6964) refactor: replace text-based copy code button with icons ([@lex111](https://github.com/lex111)) + - [#6932](https://github.com/facebook/docusaurus/pull/6932) refactor(theme-classic): little breadcrumbs improvements ([@lex111](https://github.com/lex111)) + - [#6914](https://github.com/facebook/docusaurus/pull/6914) feat(theme-classic): set aria-expanded on expandable sidebar categories ([@pkowaluk](https://github.com/pkowaluk)) + - [#6844](https://github.com/facebook/docusaurus/pull/6844) refactor(theme-classic): split sidebar into smaller parts ([@slorber](https://github.com/slorber)) + - [#6846](https://github.com/facebook/docusaurus/pull/6846) refactor(theme-classic): consistently add span wrapper for layout links ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus` + - [#6980](https://github.com/facebook/docusaurus/pull/6980) feat(utils): JSDoc for all APIs ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-common` + - [#6974](https://github.com/facebook/docusaurus/pull/6974) feat(theme-common): JSDoc for all APIs ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus` + - [#6784](https://github.com/facebook/docusaurus/pull/6784) feat(core): allow configureWebpack to return undefined ([@yorkie](https://github.com/yorkie)) + - [#6941](https://github.com/facebook/docusaurus/pull/6941) refactor(core): improve error message when a page has no default-export ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6878](https://github.com/facebook/docusaurus/pull/6878) fix(core): ensure stable webpack theme aliases sorting ([@jrvidal](https://github.com/jrvidal)) + - [#6854](https://github.com/facebook/docusaurus/pull/6854) fix(core): fix swizzle legend typo ([@DigiPie](https://github.com/DigiPie)) + - [#6850](https://github.com/facebook/docusaurus/pull/6850) fix(core): make plugin lifecycles consistently bound to the plugin instance ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-utils` + - [#6937](https://github.com/facebook/docusaurus/pull/6937) fix(content-docs): warn when files are not tracked ([@felipecrs](https://github.com/felipecrs)) +- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus` + - [#6925](https://github.com/facebook/docusaurus/pull/6925) refactor(theme-{classic,common}): refactor site/page/search metadata + apply className on html element ([@slorber](https://github.com/slorber)) +- `docusaurus-theme-classic`, `docusaurus-theme-common` + - [#6895](https://github.com/facebook/docusaurus/pull/6895) refactor(theme-{classic,common}): split navbar into smaller components + cleanup + swizzle config ([@slorber](https://github.com/slorber)) + - [#6930](https://github.com/facebook/docusaurus/pull/6930) refactor(theme-{classic,common}): refactor ColorModeToggle + useColorMode() hook ([@lex111](https://github.com/lex111)) + - [#6894](https://github.com/facebook/docusaurus/pull/6894) refactor(theme-classic): split theme footer into smaller components + swizzle config ([@slorber](https://github.com/slorber)) +- `docusaurus-types`, `docusaurus` + - [#6929](https://github.com/facebook/docusaurus/pull/6929) refactor(core): minor routes type improvement ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-client-redirects`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap` + - [#6928](https://github.com/facebook/docusaurus/pull/6928) chore(pwa, sitemap, client-redirects, ideal-image): JSDoc for types ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-content-blog`, `docusaurus-theme-classic`, `docusaurus-utils` + - [#6922](https://github.com/facebook/docusaurus/pull/6922) refactor(content-blog): clean up type definitions; in-code documentation ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-translations` + - [#6781](https://github.com/facebook/docusaurus/pull/6781) feat(theme-translations): complete Russian translations ([@dragomano](https://github.com/dragomano)) + - [#6877](https://github.com/facebook/docusaurus/pull/6877) chore(theme-translations): complete Vietnamese translations ([@datlechin](https://github.com/datlechin)) +- `docusaurus-plugin-content-blog` + - [#6909](https://github.com/facebook/docusaurus/pull/6909) refactor(content-blog): improve error message of authors map validation ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus` + - [#6860](https://github.com/facebook/docusaurus/pull/6860) fix(create): load entry file after node version checking ([@taejs](https://github.com/taejs)) + +#### :memo: Documentation + +- Other + - [#6988](https://github.com/facebook/docusaurus/pull/6988) docs: fix example admonition syntax ([@kaycebasques](https://github.com/kaycebasques)) + - [#6978](https://github.com/facebook/docusaurus/pull/6978) docs: npm run tsc -> npx tsc ([@jadonn](https://github.com/jadonn)) + - [#6952](https://github.com/facebook/docusaurus/pull/6952) docs: add K3ai to showcase ([@alefesta](https://github.com/alefesta)) + - [#6948](https://github.com/facebook/docusaurus/pull/6948) docs: add pdfme docs to showcase ([@hand-dot](https://github.com/hand-dot)) + - [#6943](https://github.com/facebook/docusaurus/pull/6943) docs: add SeaORM docs to showcase ([@billy1624](https://github.com/billy1624)) + - [#6926](https://github.com/facebook/docusaurus/pull/6926) docs: clarify the usage of slug ([@kaycebasques](https://github.com/kaycebasques)) + - [#6911](https://github.com/facebook/docusaurus/pull/6911) docs: add Reactive Button site to showcase ([@arifszn](https://github.com/arifszn)) + - [#6904](https://github.com/facebook/docusaurus/pull/6904) docs: update image for digital support services ([@PatelN123](https://github.com/PatelN123)) + - [#6892](https://github.com/facebook/docusaurus/pull/6892) docs: add EduLinks site to showcase ([@odarpi](https://github.com/odarpi)) + - [#6889](https://github.com/facebook/docusaurus/pull/6889) docs: editorial fixes ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6883](https://github.com/facebook/docusaurus/pull/6883) docs(cli): add info about development on github codespaces ([@vedantmgoyal2009](https://github.com/vedantmgoyal2009)) + - [#6856](https://github.com/facebook/docusaurus/pull/6856) docs: add Reddit Image Fetcher site to showcase ([@arifszn](https://github.com/arifszn)) + - [#6875](https://github.com/facebook/docusaurus/pull/6875) docs: update TRPG Engine showcase ([@moonrailgun](https://github.com/moonrailgun)) + - [#6871](https://github.com/facebook/docusaurus/pull/6871) docs: mark clutch and gulp as open-source ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6862](https://github.com/facebook/docusaurus/pull/6862) docs: update showcase data ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6837](https://github.com/facebook/docusaurus/pull/6837) docs: add PcapPlusPlus to showcase ([@seladb](https://github.com/seladb)) + - [#6832](https://github.com/facebook/docusaurus/pull/6832) docs: add Spicetify site to showcase ([@afonsojramos](https://github.com/afonsojramos)) + - [#6830](https://github.com/facebook/docusaurus/pull/6830) docs: simplify imported code blocks syntax ([@nathan-contino-mongo](https://github.com/nathan-contino-mongo)) +- `docusaurus-types` + - [#6881](https://github.com/facebook/docusaurus/pull/6881) docs: mention configureWebpack devServer return value ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus` + - [#6833](https://github.com/facebook/docusaurus/pull/6833) docs: make tutorial code block directly copyable ([@samgutentag](https://github.com/samgutentag)) + +#### :house: Internal + +- `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6995](https://github.com/facebook/docusaurus/pull/6995) refactor: ensure all types are using index signature instead of Record ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-plugin-pwa`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6991](https://github.com/facebook/docusaurus/pull/6991) chore: upgrade dependencies ([@Josh-Cena](https://github.com/Josh-Cena)) +- `lqip-loader` + - [#6992](https://github.com/facebook/docusaurus/pull/6992) refactor(lqip-loader): remove unused palette option ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus` + - [#6975](https://github.com/facebook/docusaurus/pull/6975) chore: update static-site-generator-webpack-plugin ([@slorber](https://github.com/slorber)) +- `stylelint-copyright` + - [#6967](https://github.com/facebook/docusaurus/pull/6967) chore: publish stylelint-copyright again ([@slorber](https://github.com/slorber)) +- `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-theme-classic`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus` + - [#6961](https://github.com/facebook/docusaurus/pull/6961) refactor: unify how validateOptions is handled ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-types` + - [#6957](https://github.com/facebook/docusaurus/pull/6957) chore(types): remove querystring from dependencies ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-common`, `docusaurus` + - [#6956](https://github.com/facebook/docusaurus/pull/6956) test: improve test coverage; reorder theme-common files ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6955](https://github.com/facebook/docusaurus/pull/6955) refactor(core): move browserContext and docusaurusContext out of client exports ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6944](https://github.com/facebook/docusaurus/pull/6944) chore: migrate Jest and website to SWC ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-utils` + - [#6951](https://github.com/facebook/docusaurus/pull/6951) test: fix Windows test for gitUtils ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright` + - [#6931](https://github.com/facebook/docusaurus/pull/6931) chore: tighten ESLint config ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects` + - [#6924](https://github.com/facebook/docusaurus/pull/6924) refactor(client-redirects): migrate validation to validateOptions lifecycle ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6916](https://github.com/facebook/docusaurus/pull/6916) chore: upgrade dependencies ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus`, `docusaurus-plugin-content-docs`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `stylelint-copyright` + - [#6912](https://github.com/facebook/docusaurus/pull/6912) test: improve test coverage; multiple internal refactors ([@Josh-Cena](https://github.com/Josh-Cena)) +- Other + - [#6910](https://github.com/facebook/docusaurus/pull/6910) refactor: convert Jest infrastructure to TS ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6838](https://github.com/facebook/docusaurus/pull/6838) fix(website): changelog plugin leads to CI bugs on release ([@slorber](https://github.com/slorber)) +- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-utils`, `docusaurus` + - [#6908](https://github.com/facebook/docusaurus/pull/6908) chore: do not print prototype in jest snapshot ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-migrate`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus` + - [#6906](https://github.com/facebook/docusaurus/pull/6906) refactor: install eslint-plugin-regexp ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-mdx-loader`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils`, `docusaurus` + - [#6905](https://github.com/facebook/docusaurus/pull/6905) test: improve test coverage; properly test core client APIs ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-sitemap`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus` + - [#6903](https://github.com/facebook/docusaurus/pull/6903) chore: spell-check test files ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-migrate`, `docusaurus-module-type-aliases`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus-utils-common`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6902](https://github.com/facebook/docusaurus/pull/6902) test(theme-common): improve test coverage ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-cssnano-preset`, `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-sitemap`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-utils-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader`, `stylelint-copyright` + - [#6900](https://github.com/facebook/docusaurus/pull/6900) test: enable a few jest eslint rules ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-translations`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6898](https://github.com/facebook/docusaurus/pull/6898) refactor: import jest as global; unify import style of some modules ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-theme-classic`, `docusaurus-theme-common` + - [#6891](https://github.com/facebook/docusaurus/pull/6891) refactor(theme-classic): avoid using clsx class dict with CSS modules ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus` + - [#6880](https://github.com/facebook/docusaurus/pull/6880) refactor: prefer fs.outputFile to ensureDir + writeFile ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-pwa`, `docusaurus-types`, `docusaurus` + - [#6866](https://github.com/facebook/docusaurus/pull/6866) refactor: improve types ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-mdx-loader`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-pwa`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-types`, `docusaurus`, `lqip-loader` + - [#6864](https://github.com/facebook/docusaurus/pull/6864) refactor: remove unnecessary default values normalized during validation ([@Josh-Cena](https://github.com/Josh-Cena)) +- `create-docusaurus`, `docusaurus-migrate`, `docusaurus` + - [#6861](https://github.com/facebook/docusaurus/pull/6861) refactor: make JS executables included in the tsconfig for editor hints ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-types`, `docusaurus` + - [#6857](https://github.com/facebook/docusaurus/pull/6857) test: improve test coverage ([@Josh-Cena](https://github.com/Josh-Cena)) +- `docusaurus-logger`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-search-algolia`, `docusaurus-utils-common`, `docusaurus-utils`, `docusaurus`, `lqip-loader` + - [#6852](https://github.com/facebook/docusaurus/pull/6852) refactor: enable a few TS flags ([@Josh-Cena](https://github.com/Josh-Cena)) + +#### Committers: 28 + +- Afonso Jorge Ramos ([@afonsojramos](https://github.com/afonsojramos)) +- Alessandro Festa ([@alefesta](https://github.com/alefesta)) +- Alexey Pyltsyn ([@lex111](https://github.com/lex111)) +- Alois Klink ([@aloisklink](https://github.com/aloisklink)) +- Ariful Alam ([@arifszn](https://github.com/arifszn)) +- Begula ([@vedantmgoyal2009](https://github.com/vedantmgoyal2009)) +- Billy Chan ([@billy1624](https://github.com/billy1624)) +- Bugo ([@dragomano](https://github.com/dragomano)) +- Evan ([@DigiPie](https://github.com/DigiPie)) +- Felipe Santos ([@felipecrs](https://github.com/felipecrs)) +- Jadon N ([@jadonn](https://github.com/jadonn)) +- Joshua Chen ([@Josh-Cena](https://github.com/Josh-Cena)) +- Kayce Basques ([@kaycebasques](https://github.com/kaycebasques)) +- Kyohei Fukuda ([@hand-dot](https://github.com/hand-dot)) +- Nayan Patel ([@PatelN123](https://github.com/PatelN123)) +- Ngô Quốc Đạt ([@datlechin](https://github.com/datlechin)) +- Odarpi ([@odarpi](https://github.com/odarpi)) +- Pawel Kowaluk ([@pkowaluk](https://github.com/pkowaluk)) +- Roberto Vidal ([@jrvidal](https://github.com/jrvidal)) +- Sam Gutentag ([@samgutentag](https://github.com/samgutentag)) +- Sébastien Lorber ([@slorber](https://github.com/slorber)) +- Tsz W. TAM ([@rccttwd](https://github.com/rccttwd)) +- WonChul Heo ([@heowc](https://github.com/heowc)) +- Yorkie Liu ([@yorkie](https://github.com/yorkie)) +- [@seladb](https://github.com/seladb) +- moonrailgun ([@moonrailgun](https://github.com/moonrailgun)) +- nate contino ([@nathan-contino-mongo](https://github.com/nathan-contino-mongo)) +- tae ([@taejs](https://github.com/taejs)) + ## 2.0.0-beta.17 (2022-03-03) #### :rocket: New Feature diff --git a/admin/new.docusaurus.io/package.json b/admin/new.docusaurus.io/package.json index 16c6bd0abef5..b756cdbeea9e 100644 --- a/admin/new.docusaurus.io/package.json +++ b/admin/new.docusaurus.io/package.json @@ -1,6 +1,6 @@ { "name": "new.docusaurus.io", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "private": true, "scripts": { "start": "netlify dev" diff --git a/lerna.json b/lerna.json index cb868eb2e866..a6c855450b0b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "npmClient": "yarn", "useWorkspaces": true, "changelog": { diff --git a/packages/create-docusaurus/package.json b/packages/create-docusaurus/package.json index 418329635a2f..e9d943f4b5c3 100755 --- a/packages/create-docusaurus/package.json +++ b/packages/create-docusaurus/package.json @@ -1,6 +1,6 @@ { "name": "create-docusaurus", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Create Docusaurus apps easily.", "type": "module", "repository": { @@ -22,7 +22,7 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.17", + "@docusaurus/logger": "2.0.0-beta.18", "commander": "^5.1.0", "fs-extra": "^10.0.1", "lodash": "^4.17.21", diff --git a/packages/create-docusaurus/templates/classic-typescript/package.json b/packages/create-docusaurus/templates/classic-typescript/package.json index acfd86d994c4..519ecaed3b66 100644 --- a/packages/create-docusaurus/templates/classic-typescript/package.json +++ b/packages/create-docusaurus/templates/classic-typescript/package.json @@ -1,6 +1,6 @@ { "name": "docusaurus-2-classic-typescript-template", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -15,8 +15,8 @@ "typecheck": "tsc" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "prism-react-renderer": "^1.3.1", @@ -24,7 +24,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", "@tsconfig/docusaurus": "^1.0.5", "typescript": "^4.6.3" }, diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index b2e3ecb8df4c..56e16d39efaa 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -1,6 +1,6 @@ { "name": "docusaurus-2-classic-template", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -14,8 +14,8 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "prism-react-renderer": "^1.3.1", diff --git a/packages/create-docusaurus/templates/facebook/package.json b/packages/create-docusaurus/templates/facebook/package.json index 2c547bd44f61..38bd9866b0af 100644 --- a/packages/create-docusaurus/templates/facebook/package.json +++ b/packages/create-docusaurus/templates/facebook/package.json @@ -1,6 +1,6 @@ { "name": "docusaurus-2-facebook-template", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -18,8 +18,8 @@ "format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\"" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "react": "^17.0.2", diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index b42011147953..43d2f19522ff 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/cssnano-preset", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Advanced cssnano preset for maximum optimization.", "main": "index.js", "license": "MIT", diff --git a/packages/docusaurus-logger/package.json b/packages/docusaurus-logger/package.json index c43d320fcab9..238e44277965 100644 --- a/packages/docusaurus-logger/package.json +++ b/packages/docusaurus-logger/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/logger", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "An encapsulated logger for semantically formatting console messages.", "main": "./lib/index.js", "repository": { diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 0472d7bfefb8..1215aed4270e 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/mdx-loader", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus Loader for MDX", "main": "lib/index.js", "types": "src/mdx-loader.d.ts", @@ -20,8 +20,8 @@ "dependencies": { "@babel/parser": "^7.17.8", "@babel/traverse": "^7.17.3", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -36,7 +36,7 @@ "webpack": "^5.70.0" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/types": "2.0.0-beta.18", "@types/escape-html": "^1.0.1", "@types/mdast": "^3.0.10", "@types/stringify-object": "^3.3.1", diff --git a/packages/docusaurus-migrate/package.json b/packages/docusaurus-migrate/package.json index 4ae500341ba1..01457dd55b72 100644 --- a/packages/docusaurus-migrate/package.json +++ b/packages/docusaurus-migrate/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/migrate", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "A CLI tool to migrate from older versions of Docusaurus.", "license": "MIT", "engines": { @@ -23,8 +23,8 @@ }, "dependencies": { "@babel/preset-env": "^7.16.11", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", "@mapbox/hast-util-to-jsx": "^2.0.0", "color": "^4.2.1", "commander": "^5.1.0", diff --git a/packages/docusaurus-module-type-aliases/package.json b/packages/docusaurus-module-type-aliases/package.json index 44cb25e3a571..f15a3a6c7685 100644 --- a/packages/docusaurus-module-type-aliases/package.json +++ b/packages/docusaurus-module-type-aliases/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/module-type-aliases", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus module type aliases.", "types": "./src/index.d.ts", "publishConfig": { @@ -12,7 +12,7 @@ "directory": "packages/docusaurus-module-type-aliases" }, "dependencies": { - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/types": "2.0.0-beta.18", "@types/react": "*", "@types/react-router-config": "*", "@types/react-router-dom": "*", diff --git a/packages/docusaurus-plugin-client-redirects/package.json b/packages/docusaurus-plugin-client-redirects/package.json index 20b2aedbcf38..3bee353ebe93 100644 --- a/packages/docusaurus-plugin-client-redirects/package.json +++ b/packages/docusaurus-plugin-client-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-client-redirects", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Client redirects plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-client-redirects.d.ts", @@ -18,18 +18,18 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "eta": "^1.12.3", "fs-extra": "^10.0.1", "lodash": "^4.17.21", "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json index 88af116f4d2f..4dffa1a94040 100644 --- a/packages/docusaurus-plugin-content-blog/package.json +++ b/packages/docusaurus-plugin-content-blog/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-blog", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Blog plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-content-blog.d.ts", @@ -18,12 +18,12 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/mdx-loader": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/mdx-loader": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "cheerio": "^1.0.0-rc.10", "feed": "^4.2.2", "fs-extra": "^10.0.1", @@ -35,7 +35,7 @@ "webpack": "^5.70.0" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/types": "2.0.0-beta.18", "escape-string-regexp": "^4.0.0" }, "peerDependencies": { diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index 522135a1d0a3..c080891df07f 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-docs", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docs plugin for Docusaurus.", "main": "lib/index.js", "exports": { @@ -23,11 +23,11 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/mdx-loader": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/mdx-loader": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "combine-promises": "^1.1.0", "fs-extra": "^10.0.1", "import-fresh": "^3.3.0", @@ -39,8 +39,8 @@ "webpack": "^5.70.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@docusaurus/types": "2.0.0-beta.18", "@types/js-yaml": "^4.0.5", "@types/picomatch": "^2.3.0", "commander": "^5.1.0", diff --git a/packages/docusaurus-plugin-content-pages/package.json b/packages/docusaurus-plugin-content-pages/package.json index 29a27364c5be..8cc6de8765f0 100644 --- a/packages/docusaurus-plugin-content-pages/package.json +++ b/packages/docusaurus-plugin-content-pages/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-pages", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Pages plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-content-pages.d.ts", @@ -18,17 +18,17 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/mdx-loader": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/mdx-loader": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "fs-extra": "^10.0.1", "remark-admonitions": "^1.2.1", "tslib": "^2.3.1", "webpack": "^5.70.0" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-plugin-debug/package.json b/packages/docusaurus-plugin-debug/package.json index bdcad0c78251..3a99d1b859a3 100644 --- a/packages/docusaurus-plugin-debug/package.json +++ b/packages/docusaurus-plugin-debug/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-debug", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Debug plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-debug.d.ts", @@ -18,14 +18,14 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", "fs-extra": "^10.0.1", "react-json-view": "^1.21.3", "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-plugin-google-analytics/package.json b/packages/docusaurus-plugin-google-analytics/package.json index 22799299275c..7dfbc3578232 100644 --- a/packages/docusaurus-plugin-google-analytics/package.json +++ b/packages/docusaurus-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-google-analytics", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Global analytics (analytics.js) plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-google-analytics.d.ts", @@ -18,12 +18,12 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-plugin-google-gtag/package.json b/packages/docusaurus-plugin-google-gtag/package.json index 72d03781ed89..925a196a9e9e 100644 --- a/packages/docusaurus-plugin-google-gtag/package.json +++ b/packages/docusaurus-plugin-google-gtag/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-google-gtag", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Global Site Tag (gtag.js) plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-google-gtag.d.ts", @@ -18,12 +18,12 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-plugin-ideal-image/package.json b/packages/docusaurus-plugin-ideal-image/package.json index 8a00967829e3..18044e5c43ad 100644 --- a/packages/docusaurus-plugin-ideal-image/package.json +++ b/packages/docusaurus-plugin-ideal-image/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-ideal-image", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).", "main": "lib/index.js", "types": "src/plugin-ideal-image.d.ts", @@ -21,11 +21,11 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/lqip-loader": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/lqip-loader": "2.0.0-beta.18", "@docusaurus/responsive-loader": "^1.7.0", - "@docusaurus/theme-translations": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "@endiliey/react-ideal-image": "^0.0.11", "react-waypoint": "^10.1.0", "sharp": "^0.30.3", @@ -33,8 +33,8 @@ "webpack": "^5.70.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@docusaurus/types": "2.0.0-beta.18", "fs-extra": "^10.0.1" }, "peerDependencies": { diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json index 0c29557a51bb..3150d85f7df8 100644 --- a/packages/docusaurus-plugin-pwa/package.json +++ b/packages/docusaurus-plugin-pwa/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-pwa", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus Plugin to add PWA support.", "main": "lib/index.js", "types": "src/plugin-pwa.d.ts", @@ -22,11 +22,11 @@ "dependencies": { "@babel/core": "^7.17.8", "@babel/preset-env": "^7.16.11", - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-translations": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "babel-loader": "^8.2.4", "clsx": "^1.1.1", "core-js": "^3.21.1", @@ -39,7 +39,7 @@ "workbox-window": "^6.5.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", "fs-extra": "^10.0.1" }, "peerDependencies": { diff --git a/packages/docusaurus-plugin-sitemap/package.json b/packages/docusaurus-plugin-sitemap/package.json index fd186fa89048..9eb611ed0126 100644 --- a/packages/docusaurus-plugin-sitemap/package.json +++ b/packages/docusaurus-plugin-sitemap/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-sitemap", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Simple sitemap generation plugin for Docusaurus.", "main": "lib/index.js", "types": "src/plugin-sitemap.d.ts", @@ -18,16 +18,16 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "fs-extra": "^10.0.1", "sitemap": "^7.1.1", "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-preset-classic/package.json b/packages/docusaurus-preset-classic/package.json index 59187fb486d3..850c52f9e030 100644 --- a/packages/docusaurus-preset-classic/package.json +++ b/packages/docusaurus-preset-classic/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/preset-classic", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Classic preset for Docusaurus.", "main": "lib/index.js", "types": "src/preset-classic.d.ts", @@ -18,17 +18,17 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/plugin-content-blog": "2.0.0-beta.17", - "@docusaurus/plugin-content-docs": "2.0.0-beta.17", - "@docusaurus/plugin-content-pages": "2.0.0-beta.17", - "@docusaurus/plugin-debug": "2.0.0-beta.17", - "@docusaurus/plugin-google-analytics": "2.0.0-beta.17", - "@docusaurus/plugin-google-gtag": "2.0.0-beta.17", - "@docusaurus/plugin-sitemap": "2.0.0-beta.17", - "@docusaurus/theme-classic": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-search-algolia": "2.0.0-beta.17" + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/plugin-content-blog": "2.0.0-beta.18", + "@docusaurus/plugin-content-docs": "2.0.0-beta.18", + "@docusaurus/plugin-content-pages": "2.0.0-beta.18", + "@docusaurus/plugin-debug": "2.0.0-beta.18", + "@docusaurus/plugin-google-analytics": "2.0.0-beta.18", + "@docusaurus/plugin-google-gtag": "2.0.0-beta.18", + "@docusaurus/plugin-sitemap": "2.0.0-beta.18", + "@docusaurus/theme-classic": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-search-algolia": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-remark-plugin-npm2yarn/package.json b/packages/docusaurus-remark-plugin-npm2yarn/package.json index f183f95cafd6..3c0468b12340 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/package.json +++ b/packages/docusaurus-remark-plugin-npm2yarn/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/remark-plugin-npm2yarn", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Remark plugin for converting npm commands to Yarn commands as tabs.", "main": "lib/index.js", "publishConfig": { diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index dfbe3ddf767f..6820614d1571 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-classic", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Classic theme for Docusaurus", "main": "lib/index.js", "types": "src/theme-classic.d.ts", @@ -21,15 +21,15 @@ "format:lib-next": "prettier --config ../../.prettierrc --write \"lib-next/**/*.{js,ts,jsx,tsc}\"" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/plugin-content-blog": "2.0.0-beta.17", - "@docusaurus/plugin-content-docs": "2.0.0-beta.17", - "@docusaurus/plugin-content-pages": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-translations": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/plugin-content-blog": "2.0.0-beta.18", + "@docusaurus/plugin-content-docs": "2.0.0-beta.18", + "@docusaurus/plugin-content-pages": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", "copy-text-to-clipboard": "^3.0.1", @@ -42,8 +42,8 @@ "rtlcss": "^3.5.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@docusaurus/types": "2.0.0-beta.18", "@types/mdx-js__react": "^1.5.5", "@types/prismjs": "^1.26.0", "@types/rtlcss": "^3.1.2", diff --git a/packages/docusaurus-theme-common/package.json b/packages/docusaurus-theme-common/package.json index ab293316f44c..9c77f8eb95b9 100644 --- a/packages/docusaurus-theme-common/package.json +++ b/packages/docusaurus-theme-common/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-common", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Common code for Docusaurus themes.", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -18,10 +18,10 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@docusaurus/plugin-content-blog": "2.0.0-beta.17", - "@docusaurus/plugin-content-docs": "2.0.0-beta.17", - "@docusaurus/plugin-content-pages": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@docusaurus/plugin-content-blog": "2.0.0-beta.18", + "@docusaurus/plugin-content-docs": "2.0.0-beta.18", + "@docusaurus/plugin-content-pages": "2.0.0-beta.18", "clsx": "^1.1.1", "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^1.3.1", @@ -29,8 +29,8 @@ "utility-types": "^3.10.0" }, "devDependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/types": "2.0.0-beta.18", "fs-extra": "^10.0.1", "lodash": "^4.17.21" }, diff --git a/packages/docusaurus-theme-live-codeblock/package.json b/packages/docusaurus-theme-live-codeblock/package.json index da1802a21bfa..ffdcbb6ca6b0 100644 --- a/packages/docusaurus-theme-live-codeblock/package.json +++ b/packages/docusaurus-theme-live-codeblock/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-live-codeblock", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus live code block component.", "main": "lib/index.js", "types": "src/theme-live-codeblock.d.ts", @@ -21,10 +21,10 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-translations": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "@philpl/buble": "^0.19.7", "clsx": "^1.1.1", "fs-extra": "^10.0.1", @@ -32,7 +32,7 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/types": "2.0.0-beta.18", "@types/buble": "^0.20.1" }, "peerDependencies": { diff --git a/packages/docusaurus-theme-search-algolia/package.json b/packages/docusaurus-theme-search-algolia/package.json index 6f47d1110da8..e2cd35f6bdf6 100644 --- a/packages/docusaurus-theme-search-algolia/package.json +++ b/packages/docusaurus-theme-search-algolia/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-search-algolia", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Algolia search component for Docusaurus.", "main": "lib/index.js", "exports": { @@ -26,13 +26,13 @@ }, "dependencies": { "@docsearch/react": "^3.0.0", - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/plugin-content-docs": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-translations": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/plugin-content-docs": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "algoliasearch": "^4.13.0", "algoliasearch-helper": "^3.7.4", "clsx": "^1.1.1", @@ -43,7 +43,7 @@ "utility-types": "^3.10.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17" + "@docusaurus/module-type-aliases": "2.0.0-beta.18" }, "peerDependencies": { "react": "^16.8.4 || ^17.0.0", diff --git a/packages/docusaurus-theme-translations/package.json b/packages/docusaurus-theme-translations/package.json index b690f7d48513..64b10648c7a5 100644 --- a/packages/docusaurus-theme-translations/package.json +++ b/packages/docusaurus-theme-translations/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-translations", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Docusaurus theme translations.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -23,8 +23,8 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", "lodash": "^4.17.21" }, "engines": { diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index 59eec31416ef..245d45cedd10 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/types", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Common types for Docusaurus packages.", "types": "./src/index.d.ts", "publishConfig": { diff --git a/packages/docusaurus-utils-common/package.json b/packages/docusaurus-utils-common/package.json index a2728c53dec3..ee7156d5b08b 100644 --- a/packages/docusaurus-utils-common/package.json +++ b/packages/docusaurus-utils-common/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/utils-common", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Common (Node/Browser) utility functions for Docusaurus packages.", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -21,7 +21,7 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17" + "@docusaurus/types": "2.0.0-beta.18" }, "engines": { "node": ">=14" diff --git a/packages/docusaurus-utils-validation/package.json b/packages/docusaurus-utils-validation/package.json index 1cd8f64b0561..ea845a2df40d 100644 --- a/packages/docusaurus-utils-validation/package.json +++ b/packages/docusaurus-utils-validation/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/utils-validation", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Node validation utility functions for Docusaurus packages.", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -18,10 +18,10 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "js-yaml": "^4.1.0", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", "joi": "^17.6.0", + "js-yaml": "^4.1.0", "tslib": "^2.3.1" }, "engines": { diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index df9eb8ef298d..51435bb08ab7 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/utils", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Node utility functions for Docusaurus packages.", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -18,7 +18,7 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.17", + "@docusaurus/logger": "2.0.0-beta.18", "@svgr/webpack": "^6.2.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.1", @@ -38,7 +38,7 @@ "node": ">=14" }, "devDependencies": { - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/types": "2.0.0-beta.18", "@types/dedent": "^0.7.0", "@types/github-slugger": "^1.3.0", "@types/micromatch": "^4.0.2", diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 0164015184df..e4776f9e4895 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -1,7 +1,7 @@ { "name": "@docusaurus/core", "description": "Easy to Maintain Open Source Documentation Websites", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "license": "MIT", "publishConfig": { "access": "public" @@ -41,13 +41,13 @@ "@babel/runtime": "^7.17.8", "@babel/runtime-corejs3": "^7.17.8", "@babel/traverse": "^7.17.3", - "@docusaurus/cssnano-preset": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/mdx-loader": "2.0.0-beta.17", + "@docusaurus/cssnano-preset": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/mdx-loader": "2.0.0-beta.18", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", - "@docusaurus/utils-validation": "2.0.0-beta.17", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", "@slorber/static-site-generator-webpack-plugin": "^4.0.4", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.4", @@ -106,8 +106,8 @@ "webpackbar": "^5.0.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@docusaurus/types": "2.0.0-beta.17", + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@docusaurus/types": "2.0.0-beta.18", "@types/detect-port": "^1.3.2", "@types/nprogress": "^0.2.0", "@types/react-dom": "^17.0.14", diff --git a/packages/lqip-loader/package.json b/packages/lqip-loader/package.json index 66ccece761dd..7c524b8bf7ba 100644 --- a/packages/lqip-loader/package.json +++ b/packages/lqip-loader/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/lqip-loader", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Low Quality Image Placeholders (LQIP) loader for webpack.", "main": "lib/index.js", "publishConfig": { @@ -17,7 +17,7 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.17", + "@docusaurus/logger": "2.0.0-beta.18", "file-loader": "^6.2.0", "lodash": "^4.17.21", "sharp": "^0.30.3", diff --git a/packages/stylelint-copyright/package.json b/packages/stylelint-copyright/package.json index be46ef9595d4..f5a24cd77cda 100644 --- a/packages/stylelint-copyright/package.json +++ b/packages/stylelint-copyright/package.json @@ -1,6 +1,6 @@ { "name": "stylelint-copyright", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "Stylelint plugin to check CSS files for a copyright header.", "main": "index.js", "license": "MIT", diff --git a/website/package.json b/website/package.json index 2323ae995ee4..2ee13f7bb689 100644 --- a/website/package.json +++ b/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -36,18 +36,18 @@ "dependencies": { "@crowdin/cli": "^3.7.8", "@crowdin/crowdin-api-client": "^1.15.0", - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/logger": "2.0.0-beta.17", - "@docusaurus/plugin-client-redirects": "2.0.0-beta.17", - "@docusaurus/plugin-ideal-image": "2.0.0-beta.17", - "@docusaurus/plugin-pwa": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", - "@docusaurus/remark-plugin-npm2yarn": "2.0.0-beta.17", - "@docusaurus/theme-classic": "2.0.0-beta.17", - "@docusaurus/theme-common": "2.0.0-beta.17", - "@docusaurus/theme-live-codeblock": "2.0.0-beta.17", - "@docusaurus/utils": "2.0.0-beta.17", - "@docusaurus/utils-common": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/logger": "2.0.0-beta.18", + "@docusaurus/plugin-client-redirects": "2.0.0-beta.18", + "@docusaurus/plugin-ideal-image": "2.0.0-beta.18", + "@docusaurus/plugin-pwa": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", + "@docusaurus/remark-plugin-npm2yarn": "2.0.0-beta.18", + "@docusaurus/theme-classic": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-live-codeblock": "2.0.0-beta.18", + "@docusaurus/utils": "2.0.0-beta.18", + "@docusaurus/utils-common": "2.0.0-beta.18", "@popperjs/core": "^2.11.4", "@swc/core": "^1.2.160", "clsx": "^1.1.1", diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/architecture.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/architecture.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/architecture.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/architecture.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/client.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/client.md similarity index 73% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/client.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/client.md index 4148f270318d..ef4c4d220c60 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/advanced/client.md +++ b/website/versioned_docs/version-2.0.0-beta.18/advanced/client.md @@ -1,3 +1,7 @@ +--- +description: How the Docusaurus client is structured +--- + # Client architecture ## Theme aliases {#theme-aliases} @@ -75,3 +79,43 @@ The components in this "stack" are pushed in the order of `preset plugins > pres `@theme-original/*` always points to the topmost non-swizzled component. That's why you can import `@theme-original/CodeBlock` in the swizzled component—it points to the next one in the "component stack", a theme-provided one. Plugin authors should not try to use this because your component could be the topmost component and cause a self-import. `@theme-init/*` always points to the bottommost component—usually, this comes from the theme or plugin that first provides this component. Individual plugins / themes trying to enhance code block can safely use `@theme-init/CodeBlock` to get its basic version. Site creators should generally not use this because you likely want to enhance the _topmost_ instead of the _bottommost_ component. It's also possible that the `@theme-init/CodeBlock` alias does not exist at all—Docusaurus only creates it when it points to a different one from `@theme-original/CodeBlock`, i.e. when it's provided by more than one theme. We don't waste aliases! + +## Client modules {#client-modules} + +Client modules are part of your site's bundle, just like theme components. However, they are usually side-effect-ful. Client modules are anything that can be `import`ed by Webpack—CSS, JS, etc. JS scripts usually work on the global context, like registering event listeners, creating global variables... + +These modules are imported globally before React even renders the initial UI. + +```js title="App.tsx" +// How it works under the hood +import '@generated/client-modules'; +``` + +Plugins and sites can both declare client modules, through [`getClientModules`](../api/plugin-methods/lifecycle-apis.md#getClientModules) and [`siteConfig.clientModules`](../api/docusaurus.config.js.md#clientModules), respectively. + +Client modules are called during server-side rendering as well, so remember to check the [execution environment](./ssg.md#escape-hatches) before accessing client-side globals. + +```js title="mySiteGlobalJs.js" +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +if (ExecutionEnvironment.canUseDOM) { + // As soon as the site loads in the browser, register a global event listener + window.addEventListener('keydown', (e) => { + if (e.code === 'Period') { + location.assign(location.href.replace('.com', '.dev')); + } + }); +} +``` + +CSS stylesheets imported as client modules are [global](../styling-layout.md#global-styles). + +```css title="mySiteGlobalCss.css" +/* This stylesheet is global. */ +.globalSelector { + color: red; +} +``` + +<!-- TODO client module lifecycles --> +<!-- https://github.com/facebook/docusaurus/issues/3399 --> diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/index.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/index.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/index.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/index.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/plugins.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/plugins.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/routing.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/routing.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/routing.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/routing.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/advanced/ssg.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/ssg.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/advanced/ssg.md rename to website/versioned_docs/version-2.0.0-beta.18/advanced/ssg.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/docusaurus.config.js.md b/website/versioned_docs/version-2.0.0-beta.18/api/docusaurus.config.js.md similarity index 96% rename from website/versioned_docs/version-2.0.0-beta.16/api/docusaurus.config.js.md rename to website/versioned_docs/version-2.0.0-beta.18/api/docusaurus.config.js.md index ab50dc53956c..5a52885277b7 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/docusaurus.config.js.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/docusaurus.config.js.md @@ -284,18 +284,6 @@ module.exports = { defaultMode: 'light', disableSwitch: false, respectPrefersColorScheme: true, - switchConfig: { - darkIcon: '🌙', - lightIcon: '\u2600', - // React inline style object - // see https://reactjs.org/docs/dom-elements.html#style - darkIconStyle: { - marginLeft: '2px', - }, - lightIconStyle: { - marginLeft: '1px', - }, - }, }, navbar: { title: 'Site Title', @@ -450,7 +438,7 @@ module.exports = { ### `clientModules` {#clientmodules} -An array of client modules to load globally on your site: +An array of [client modules](../advanced/client.md#client-modules) to load globally on your site: Example: @@ -463,8 +451,6 @@ module.exports = { }; ``` -See also: [`getClientModules()`](./plugin-methods/lifecycle-apis.md#getClientModules). - ### `ssrTemplate` {#ssrtemplate} An HTML template written in [Eta's syntax](https://eta.js.org/docs/syntax#syntax-overview) that will be used to render your application. This can be used to set custom attributes on the `body` tags, additional `meta` tags, customize the `viewport`, etc. Please note that Docusaurus will rely on the template to be correctly structured in order to function properly, once you do customize it, you will have to make sure that your template is compliant with the requirements from `upstream`. diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/README.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/README.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/README.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/README.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/_category_.yml b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/_category_.yml similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/_category_.yml rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/_category_.yml diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/extend-infrastructure.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/extend-infrastructure.md similarity index 96% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/extend-infrastructure.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/extend-infrastructure.md index f4a5bc89db3a..1885129b7007 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/extend-infrastructure.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/extend-infrastructure.md @@ -61,7 +61,7 @@ module.exports = function (context, options) { ## `getThemePath()` {#getThemePath} -Returns the path to the directory where the theme components can be found. When your users call `swizzle`, `getThemePath` is called and its returned path is used to find your theme components. +Returns the path to the directory where the theme components can be found. When your users call `swizzle`, `getThemePath` is called and its returned path is used to find your theme components. Relative paths are resolved against the folder containing the entry point. For example, your `getThemePath` can be: @@ -73,7 +73,7 @@ module.exports = function (context, options) { name: 'my-theme', // highlight-start getThemePath() { - return path.resolve(__dirname, './theme'); + return './theme'; }, // highlight-end }; @@ -103,11 +103,11 @@ module.exports = function (context, options) { // highlight-start getThemePath() { // Where compiled JavaScript output lives - return path.join(__dirname, '../lib/theme'); + return '../lib/theme'; }, getTypeScriptThemePath() { // Where TypeScript source code lives - return path.resolve(__dirname, '../src/theme'); + return '../src/theme'; }, // highlight-end }; diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/i18n-lifecycles.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/i18n-lifecycles.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/i18n-lifecycles.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/i18n-lifecycles.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/lifecycle-apis.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/lifecycle-apis.md similarity index 94% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/lifecycle-apis.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/lifecycle-apis.md index b25455eed31f..3d30cb3ea5ba 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/lifecycle-apis.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/lifecycle-apis.md @@ -233,6 +233,27 @@ module.exports = function (context, options) { Read the [webpack-merge strategy doc](https://github.com/survivejs/webpack-merge#merging-with-strategies) for more details. +### Configuring dev server {#configuring-dev-server} + +The dev server can be configured through returning a `devServer` field. + +```js title="docusaurus-plugin/src/index.js" +module.exports = function (context, options) { + return { + name: 'custom-docusaurus-plugin', + configureWebpack(config, isServer, utils) { + return { + // highlight-start + devServer: { + open: '/docs', // Opens localhost:3000/docs instead of localhost:3000/ + }, + // highlight-end + }; + }, + }; +}; +``` + ## `configurePostCss(options)` {#configurePostCss} Modifies [`postcssOptions` of `postcss-loader`](https://webpack.js.org/loaders/postcss-loader/#postcssoptions) during the generation of the client bundle. @@ -378,7 +399,7 @@ module.exports = function (context, options) { ## `getClientModules()` {#getClientModules} -Returns an array of paths to the modules that are to be imported into the client bundle. These modules are imported globally before React even renders the initial UI. +Returns an array of paths to the [client modules](../../advanced/client.md#client-modules) that are to be imported into the client bundle. As an example, to make your theme load a `customCss` or `customJs` file path from `options` passed in by the user: diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/static-methods.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/static-methods.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugin-methods/static-methods.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugin-methods/static-methods.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/_category_.yml b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/_category_.yml similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/_category_.yml rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/_category_.yml diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/overview.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/overview.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/overview.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/overview.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-client-redirects.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-client-redirects.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-client-redirects.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-client-redirects.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-blog.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-blog.md similarity index 90% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-blog.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-blog.md index 7eda77338a4c..dbd658b6812e 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-blog.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-blog.md @@ -37,32 +37,32 @@ Accepted fields: | Name | Type | Default | Description | | --- | --- | --- | --- | -| `path` | `string` | `'blog'` | Path to the blog content directory on the filesystem, relative to site dir. | -| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | +| `path` | `string` | `'blog'` | Path to the blog content directory on the file system, relative to site dir. | +| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativePostPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | | `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. | | `blogTitle` | `string` | `'Blog'` | Blog page title for better SEO. | | `blogDescription` | `string` | `'Blog'` | Blog page meta description for better SEO. | -| `blogSidebarCount` | <code>number \| 'ALL'</code> | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable | +| `blogSidebarCount` | <code>number \| 'ALL'</code> | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable. | | `blogSidebarTitle` | `string` | `'Recent posts'` | Title of the blog sidebar. | | `routeBasePath` | `string` | `'blog'` | URL route for the blog section of your site. **DO NOT** include a trailing slash. Use `/` to put the blog at root path. | -| `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. | -| `archiveBasePath` | <code>string \| null</code> | `'/archive'` | URL route for the archive blog section of your site. It is prepended to the `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. | -| `include` | `string[]` | `['**/*.{md,mdx}']` | Matching files will be included and processed. | -| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. | +| `tagsBasePath` | `string` | `'tags'` | URL route for the tags section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. | +| `archiveBasePath` | <code>string \| null</code> | `'archive'` | URL route for the archive section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. | +| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. | +| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. | | `postsPerPage` | <code>number \| 'ALL'</code> | `10` | Number of posts to show per page in the listing page. Use `'ALL'` to display all posts on one listing page. | | `blogListComponent` | `string` | `'@theme/BlogListPage'` | Root component of the blog listing page. | | `blogPostComponent` | `string` | `'@theme/BlogPostPage'` | Root component of each blog post page. | -| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page | +| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page. | | `blogTagsPostsComponent` | `string` | `'@theme/BlogTagsPostsPage'` | Root component of the "posts containing tag" page. | | `blogArchiveComponent` | `string` | `'@theme/BlogArchivePage'` | Root component of the blog archive page. | | `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. | | `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. | | `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. | | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | -| `truncateMarker` | `string` | `/<!--\s*(truncate)\s*-->/` | Truncate marker, can be a regex or string. | +| `truncateMarker` | `RegExp` | `/<!--\s*(truncate)\s*-->/` | Truncate marker marking where the summary ends. | | `showReadingTime` | `boolean` | `true` | Show estimated reading time for the blog post. | | `readingTime` | `ReadingTimeFunctionOption` | The default reading time | A callback to customize the reading time number displayed. | -| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory specified with `path`. Can also be a `json` file. | +| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory. | | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions.type` | <code>FeedType \| FeedType[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-docs.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-docs.md similarity index 99% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-docs.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-docs.md index 2c97cd4ab78e..cf69f8f8a220 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-docs.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-docs.md @@ -89,6 +89,7 @@ type SidebarGenerator = (generatorArgs: { version: {contentPath: string; versionName: string}; // the current version docs: Array<{ id: string; + title: string; frontMatter: DocFrontMatter & Record<string, unknown>; source: string; sourceDirName: string; diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-pages.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-pages.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-content-pages.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-content-pages.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-debug.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-debug.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-debug.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-debug.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-google-analytics.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-google-analytics.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-google-analytics.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-google-analytics.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-google-gtag.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-google-gtag.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-google-gtag.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-google-gtag.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-ideal-image.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-ideal-image.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-ideal-image.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-ideal-image.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-pwa.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-pwa.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-pwa.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-pwa.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-sitemap.md b/website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-sitemap.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/plugins/plugin-sitemap.md rename to website/versioned_docs/version-2.0.0-beta.18/api/plugins/plugin-sitemap.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/_category_.yml b/website/versioned_docs/version-2.0.0-beta.18/api/themes/_category_.yml similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/_category_.yml rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/_category_.yml diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/overview.md b/website/versioned_docs/version-2.0.0-beta.18/api/themes/overview.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/overview.md rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/overview.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-classic.md b/website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-classic.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-classic.md rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-classic.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-configuration.md b/website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-configuration.md similarity index 96% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-configuration.md rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-configuration.md index e79cf89614cf..d954079d52bb 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-configuration.md +++ b/website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-configuration.md @@ -28,11 +28,6 @@ Accepted fields: | `defaultMode` | <code>'light' \| 'dark'</code> | `'light'` | The color mode when user first visits the site. | | `disableSwitch` | `boolean` | `false` | Hides the switch in the navbar. Useful if you want to support a single color mode. | | `respectPrefersColorScheme` | `boolean` | `false` | Whether to use the `prefers-color-scheme` media-query, using user system preferences, instead of the hardcoded `defaultMode`. | -| `switchConfig` | _See below_ | _See below_ | Dark/light switch icon options. | -| `switchConfig.darkIcon` | `string` | `'🌜'` | Icon for the switch while in dark mode. | -| `switchConfig.darkIconStyle` | JSX style object (see [documentation](https://reactjs.org/docs/dom-elements.html#style)) | `{}` | CSS to apply to dark icon. | -| `switchConfig.lightIcon` | `string` | `'🌞'` | Icon for the switch while in light mode. | -| `switchConfig.lightIconStyle` | JSX style object | `{}` | CSS to apply to light icon. | </APITable> @@ -46,18 +41,6 @@ module.exports = { defaultMode: 'light', disableSwitch: false, respectPrefersColorScheme: false, - switchConfig: { - darkIcon: '🌙', - darkIconStyle: { - marginLeft: '2px', - }, - // Unicode icons such as '\u2600' will work - // Unicode with 5 chars require brackets: '\u{1F602}' - lightIcon: '\u{1F602}', - lightIconStyle: { - marginLeft: '1px', - }, - }, }, // highlight-end }, @@ -918,9 +901,9 @@ import {useColorMode} from '@docusaurus/theme-common'; const Example = () => { // highlight-next-line - const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode(); + const {colorMode, setColorMode} = useColorMode(); - return <h1>Dark mode is now {isDarkTheme ? 'on' : 'off'}</h1>; + return <h1>Dark mode is now {colorMode === 'dark' ? 'on' : 'off'}</h1>; }; ``` diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-live-codeblock.md b/website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-live-codeblock.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-live-codeblock.md rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-live-codeblock.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-search-algolia.md b/website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-search-algolia.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/api/themes/theme-search-algolia.md rename to website/versioned_docs/version-2.0.0-beta.18/api/themes/theme-search-algolia.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example-banner.png b/website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example-banner.png similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example-banner.png rename to website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example-banner.png diff --git a/website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example.docx b/website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example.docx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example.docx rename to website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example.docx diff --git a/website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example.xyz b/website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example.xyz similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/assets/docusaurus-asset-example.xyz rename to website/versioned_docs/version-2.0.0-beta.18/assets/docusaurus-asset-example.xyz diff --git a/website/versioned_docs/version-2.0.0-beta.16/blog.mdx b/website/versioned_docs/version-2.0.0-beta.18/blog.mdx similarity index 97% rename from website/versioned_docs/version-2.0.0-beta.16/blog.mdx rename to website/versioned_docs/version-2.0.0-beta.18/blog.mdx index bdee3fcb351f..3e0173879a5f 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/blog.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/blog.mdx @@ -185,7 +185,7 @@ date: 2021-09-13T18:00 ## Blog post authors {#blog-post-authors} -Use the `authors` front matter field to declare blog post authors. +Use the `authors` front matter field to declare blog post authors. An author should have at least a `name` or an `image_url`. Docusaurus uses information like `url`, `email`, and `title`, but any other information is allowed. ### Inline authors {#inline-authors} @@ -202,6 +202,7 @@ authors: title: Co-creator of Docusaurus 1 url: https://github.com/JoelMarcey image_url: https://github.com/JoelMarcey.png + email: jimarcey@gmail.com --- ``` @@ -215,6 +216,7 @@ authors: title: Co-creator of Docusaurus 1 url: https://github.com/JoelMarcey image_url: https://github.com/JoelMarcey.png + email: jimarcey@gmail.com - name: Sébastien Lorber title: Docusaurus maintainer url: https://sebastienlorber.com @@ -259,6 +261,7 @@ jmarcey: title: Co-creator of Docusaurus 1 url: https://github.com/JoelMarcey image_url: https://github.com/JoelMarcey.png + email: jimarcey@gmail.com slorber: name: Sébastien Lorber @@ -353,6 +356,12 @@ website/i18n/[locale]/docusaurus-plugin-content-blog/authors.yml An author, either declared through front matter or through the authors map, needs to have a name or an avatar, or both. If all authors of a post don't have names, Docusaurus will display their avatars compactly. See [this test post](/tests/blog/2022/01/20/image-only-authors) for the effect. +:::caution Feed generation + +[RSS feeds](#feed) require the author's email to be set for the author to appear in the feed. + +::: + ## Reading time {#reading-time} Docusaurus generates a reading time estimation for each blog post based on word count. We provide an option to customize this. diff --git a/website/versioned_docs/version-2.0.0-beta.16/browser-support.md b/website/versioned_docs/version-2.0.0-beta.18/browser-support.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/browser-support.md rename to website/versioned_docs/version-2.0.0-beta.18/browser-support.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/cli.md b/website/versioned_docs/version-2.0.0-beta.18/cli.md similarity index 96% rename from website/versioned_docs/version-2.0.0-beta.16/cli.md rename to website/versioned_docs/version-2.0.0-beta.18/cli.md index f300d26abef7..530c55c7a49f 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/cli.md +++ b/website/versioned_docs/version-2.0.0-beta.18/cli.md @@ -50,6 +50,16 @@ Please note that some functionality (for example, anchor links) will not work in ::: +:::info Development over network + +When forwarding port 3000 from a remote server or VM (e.g. GitHub Codespaces), you can run the dev server on `0.0.0.0` to make it listen on the local IP. + +```bash npm2yarn +npm run start -- --host 0.0.0.0 +``` + +::: + #### Enabling HTTPS {#enabling-https} There are multiple ways to obtain a certificate. We will use [mkcert](https://github.com/FiloSottile/mkcert) as an example. diff --git a/website/versioned_docs/version-2.0.0-beta.16/configuration.md b/website/versioned_docs/version-2.0.0-beta.18/configuration.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/configuration.md rename to website/versioned_docs/version-2.0.0-beta.18/configuration.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/deployment.mdx b/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx similarity index 97% rename from website/versioned_docs/version-2.0.0-beta.16/deployment.mdx rename to website/versioned_docs/version-2.0.0-beta.18/deployment.mdx index 5abf43320e68..d2016ed0d58f 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/deployment.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx @@ -213,7 +213,7 @@ Refer to [slorber/trailing-slash-guide](https://github.com/slorber/trailing-slas Deploying your Docusaurus project to [Vercel](https://vercel.com/) will provide you with [various benefits](https://vercel.com/) in the areas of performance and ease of use. -To deploy your Docusaurus project with a [Vercel for Git Integration](https://vercel.com/docs/git-integrations), make sure it has been pushed to a Git repository. +To deploy your Docusaurus project with a [Vercel for Git Integration](https://vercel.com/docs/concepts/git), make sure it has been pushed to a Git repository. Import the project into Vercel using the [Import Flow](https://vercel.com/import/git). During the import, you will find all relevant options preconfigured for you; however, you can choose to change any of these options, a list of which can be found [here](https://vercel.com/docs/build-step#build-&-development-settings). @@ -339,12 +339,12 @@ Alternatively, you can use SSH (`USE_SSH=true`) to log in. [GitHub Actions](https://help.github.com/en/actions) allow you to automate, customize, and execute your software development workflows right in your repository. -The workflow examples below assume your website source resides in the `main` branch of your repository (the _source branch_ is `main`), under a folder called `website/`, and your [publishing source](https://help.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site) is configured for the `gh-pages` branch (the _deployment branch_ is `gh-pages`). +The workflow examples below assume your website source resides in the `main` branch of your repository (the _source branch_ is `main`), and your [publishing source](https://help.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site) is configured for the `gh-pages` branch (the _deployment branch_ is `gh-pages`). Our goal is that: -1. When a new pull request is made to `main` and updates `website/`, there's an action that ensures the site builds successfully, without actually deploying. This job will be called `test-deploy`. -2. When a pull request is merged to the `main` branch or someone pushes to the `main` branch directly and `website/` is updated, it will be built and deployed to the `gh-pages` branch. After that, the new build output will be served on the GitHub Pages site. This job will be called `deploy`. +1. When a new pull request is made to `main`, there's an action that ensures the site builds successfully, without actually deploying. This job will be called `test-deploy`. +2. When a pull request is merged to the `main` branch or someone pushes to the `main` branch directly, it will be built and deployed to the `gh-pages` branch. After that, the new build output will be served on the GitHub Pages site. This job will be called `deploy`. Here are two approaches to deploying your docs with GitHub Actions. Based on the location of your deployment branch (`gh-pages`), choose the relevant tab below: @@ -369,7 +369,7 @@ Add these two workflow files: These files assume you are using yarn. If you use npm, change `cache: yarn`, `yarn install --frozen-lockfile`, `yarn build` to `cache: npm`, `npm ci`, `npm run build` accordingly. -If your Docusaurus project is not at the root of the repo, you would need to change the paths as well. +If your Docusaurus project is not at the root of your repo, you may need to configure a [default working directory](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-set-the-default-shell-and-working-directory), and adjust the paths accordingly. ::: @@ -499,7 +499,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x cache: yarn - uses: webfactory/ssh-agent@v0.5.0 with: diff --git a/website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md b/website/versioned_docs/version-2.0.0-beta.18/docusaurus-core.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/docusaurus-core.md rename to website/versioned_docs/version-2.0.0-beta.18/docusaurus-core.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/creating-pages.md b/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md similarity index 98% rename from website/versioned_docs/version-2.0.0-beta.16/guides/creating-pages.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md index bf4c277d4a15..160b4dbf1dec 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/creating-pages.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md @@ -35,9 +35,9 @@ Create a file `/src/pages/helloReact.js`: import React from 'react'; import Layout from '@theme/Layout'; -function Hello() { +export default function Hello() { return ( - <Layout title="Hello"> + <Layout title="Hello" description="Hello React Page"> <div style={{ display: 'flex', @@ -53,8 +53,6 @@ function Hello() { </Layout> ); } - -export default Hello; ``` Once you save the file, the development server will automatically reload the changes. Now open `http://localhost:3000/helloReact` and you will see the new page you just created. diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-create-doc.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-create-doc.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-create-doc.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-create-doc.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-introduction.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-introduction.md similarity index 85% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-introduction.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-introduction.md index 426186a72bbd..02e9d76b45cd 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-introduction.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-introduction.md @@ -37,17 +37,31 @@ id: part1 Lorem ipsum ``` -If you want more control over the last part of the document URL, it is possible to add a `slug` (defaults to the `id`). +### Customizing doc URLs {#customizing-doc-urls} + +By default, a document's URL location is its file path relative to the `docs` folder. Use the `slug` front matter to change a document's URL. + +For example, suppose your site structure looks like this: + +```bash +website # Root directory of your site +└── docs + └── guide + └── hello.md +``` + +By default `hello.md` will be available at `/docs/guide/hello`. You can change its URL location to `/docs/bonjour`: ```md --- -id: part1 -slug: part1.html +slug: /bonjour --- Lorem ipsum ``` +`slug` will be appended to the doc plugin's `routeBasePath`, which is `/docs` by default. See [Docs-only mode](#docs-only-mode) for how to remove the `/docs` part from the URL. + :::note It is possible to use: diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-markdown-features.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-markdown-features.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-markdown-features.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-markdown-features.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-multi-instance.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-multi-instance.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/docs-multi-instance.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/docs-multi-instance.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/autogenerated.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/autogenerated.md similarity index 97% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/autogenerated.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/autogenerated.md index 807de81571de..239888b99f30 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/autogenerated.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/autogenerated.md @@ -323,7 +323,7 @@ sidebar_class_name: green This is the easy tutorial! ``` -**For categories**: add a `_category_.json` or `_category_.yml` file in the respective folder. You can specify any category metadata and also the `position` metadata. +**For categories**: add a `_category_.json` or `_category_.yml` file in the respective folder. You can specify any category metadata and also the `position` metadata. `label`, `className`, `position`, and `customProps` will default to the respective values of the category's linked doc, if there is one. <Tabs> <TabItem value="JSON"> @@ -338,6 +338,9 @@ This is the easy tutorial! "link": { "type": "generated-index", "title": "Tutorial overview" + }, + "customProps": { + "description": "This description can be used in the swizzled DocCard" } } ``` @@ -354,6 +357,8 @@ className: red link: type: generated-index title: Tutorial overview +customProps: + description: This description can be used in the swizzled DocCard ``` </TabItem> diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/index.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/index.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/index.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/index.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/items.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/items.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/items.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/items.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/multiple-sidebars.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/multiple-sidebars.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/sidebar/multiple-sidebars.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/sidebar/multiple-sidebars.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/docs/versioning.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/docs/versioning.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/_markdown-partial-example.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/_markdown-partial-example.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/_markdown-partial-example.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/_markdown-partial-example.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-admonitions.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-admonitions.mdx similarity index 99% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-admonitions.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-admonitions.mdx index 365641ab2504..3302ee532661 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-admonitions.mdx @@ -87,14 +87,14 @@ If you use [Prettier](https://prettier.io) to format your Markdown files, Pretti <!-- prettier-ignore --> ```md <!-- Prettier doesn't change this --> -::: note +:::note Hello world ::: <!-- Prettier changes this --> -::: note +:::note Hello world ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-assets.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-assets.mdx similarity index 92% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-assets.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-assets.mdx index 32194db3291e..321ddb5d9ad2 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-assets.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-assets.mdx @@ -6,6 +6,8 @@ slug: /markdown-features/assets --- import BrowserWindow from '@site/src/components/BrowserWindow'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; Sometimes you want to link to assets (e.g. docx files, images...) directly from Markdown files, and it is convenient to co-locate the asset next to the Markdown file using it. @@ -24,12 +26,18 @@ Let's imagine the following file structure: You can display images in three different ways: Markdown syntax, CJS require, or ES imports syntax. +<Tabs> +<TabItem value="Markdown syntax"> + Display images using simple Markdown syntax: ```md ![Example banner](./assets/docusaurus-asset-example-banner.png) ``` +</TabItem> +<TabItem value="CommonJS require"> + Display images using inline CommonJS `require` in JSX image tag: ```jsx @@ -39,6 +47,9 @@ Display images using inline CommonJS `require` in JSX image tag: /> ``` +</TabItem> +<TabItem value="Import statement"> + Display images using ES `import` syntax and JSX image tag: ```jsx @@ -47,7 +58,10 @@ import myImageUrl from './assets/docusaurus-asset-example-banner.png'; <img src={myImageUrl} alt="Example banner" />; ``` -This results in displaying the image: +</TabItem> +</Tabs> + +All of the above result in displaying the image: <BrowserWindow> @@ -63,7 +77,7 @@ If you are using [@docusaurus/plugin-ideal-image](../../api/plugins/plugin-ideal ## Files {#files} -In the same way, you can link to existing assets by requiring them and using the returned url in videos, links, etc. +In the same way, you can link to existing assets by `require`'ing them and using the returned URL in `video`s, `a` anchor links, etc. ```md # My Markdown page @@ -89,7 +103,7 @@ or :::info markdown links are always file paths -If you use the Markdown image or link syntax, all asset paths will be resolved as file paths by Docusaurus and automatically converted to `require()` calls. You don't need to use `require()` in Markdown unless you use the JSX syntax. +If you use the Markdown image or link syntax, all asset paths will be resolved as file paths by Docusaurus and automatically converted to `require()` calls. You don't need to use `require()` in Markdown unless you use the JSX syntax, which you do have to handle yourself. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-code-blocks.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx similarity index 87% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-code-blocks.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx index 7934b6ebaafb..085d944ca429 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx @@ -14,11 +14,13 @@ Code blocks within documentation are super-powered 💪. You can add a title to the code block by adding a `title` key after the language (leave a space between them). - ```jsx title="/src/components/HelloCodeTitle.js" - function HelloCodeTitle(props) { - return <h1>Hello, {props.name}</h1>; - } - ``` +````md +```jsx title="/src/components/HelloCodeTitle.js" +function HelloCodeTitle(props) { + return <h1>Hello, {props.name}</h1>; +} +``` +```` <BrowserWindow> @@ -34,9 +36,11 @@ function HelloCodeTitle(props) { Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for the specifications of MDX. - ```js - console.log('Every repo must come with a mascot.'); - ``` +````md +```js +console.log('Every repo must come with a mascot.'); +``` +```` Use the matching language meta string for your code block, and Docusaurus will pick up syntax highlighting automatically, powered by [Prism React Renderer](https://github.com/FormidableLabs/prism-react-renderer). @@ -127,26 +131,28 @@ You can refer to [Prism's official language definitions](https://github.com/Pris You can use comments with `highlight-next-line`, `highlight-start`, and `highlight-end` to select which lines are highlighted. - ```js - function HighlightSomeText(highlight) { - if (highlight) { - // highlight-next-line - return 'This text is highlighted!'; - } +````md +```js +function HighlightSomeText(highlight) { + if (highlight) { + // highlight-next-line + return 'This text is highlighted!'; + } - return 'Nothing highlighted'; - } + return 'Nothing highlighted'; +} - function HighlightMoreText(highlight) { - // highlight-start - if (highlight) { - return 'This range is highlighted!'; - } - // highlight-end +function HighlightMoreText(highlight) { + // highlight-start + if (highlight) { + return 'This range is highlighted!'; + } + // highlight-end - return 'Nothing highlighted'; - } - ``` + return 'Nothing highlighted'; +} +``` +```` ````mdx-code-block <BrowserWindow> @@ -177,14 +183,14 @@ function HighlightMoreText(highlight) { Supported commenting syntax: -| Language | Syntax | +| Style | Syntax | | ---------- | ------------------------ | -| JavaScript | `/* ... */` and `// ...` | -| JSX | `{/* ... */}` | -| Python | `# ...` | -| HTML | `<!-- ... -->` | +| C-style | `/* ... */` and `// ...` | +| JSX-style | `{/* ... */}` | +| Bash-style | `# ...` | +| HTML-style | `<!-- ... -->` | -If there's a syntax that is not currently supported, we are open to adding them! Pull requests welcome. +We will do our best to infer which set of comment styles to use based on the language, and default to allowing _all_ comment styles. If there's a comment style that is not currently supported, we are open to adding them! Pull requests welcome. To accomplish this, Docusaurus adds the `docusaurus-highlight-code-line` class to the highlighted lines. You will need to define your own styling for this CSS, possibly in your `src/css/custom.css` with a custom background color which is dependent on your selected syntax highlighting theme. The color given below works for the default highlighting theme (Palenight), so if you are using another theme, you will have to tweak the color accordingly. @@ -207,19 +213,21 @@ To accomplish this, Docusaurus adds the `docusaurus-highlight-code-line` class t You can also specify highlighted line ranges within the language meta string (leave a space after the language). To highlight multiple lines, separate the line numbers by commas or use the range syntax to select a chunk of lines. This feature uses the `parse-number-range` library and you can find [more syntax](https://www.npmjs.com/package/parse-numeric-range) on their project details. - ```jsx {1,4-6,11} - import React from 'react'; +````md +```jsx {1,4-6,11} +import React from 'react'; - function MyComponent(props) { - if (props.isBar) { - return <div>Bar</div>; - } +function MyComponent(props) { + if (props.isBar) { + return <div>Bar</div>; + } - return <div>Foo</div>; - } + return <div>Foo</div>; +} - export default MyComponent; - ``` +export default MyComponent; +``` +```` <BrowserWindow> @@ -265,9 +273,7 @@ In the future, we may extend the magic comment system and let you define custom (Powered by [React Live](https://github.com/FormidableLabs/react-live)) -You can create an interactive coding editor with the `@docusaurus/theme-live-codeblock` plugin. - -First, add the plugin to your package. +You can create an interactive coding editor with the `@docusaurus/theme-live-codeblock` plugin. First, add the plugin to your package. ```bash npm2yarn npm install --save @docusaurus/theme-live-codeblock @@ -285,28 +291,30 @@ module.exports = { To use the plugin, create a code block with `live` attached to the language meta string. - ```jsx live - function Clock(props) { - const [date, setDate] = useState(new Date()); - useEffect(() => { - var timerID = setInterval(() => tick(), 1000); - - return function cleanup() { - clearInterval(timerID); - }; - }); - - function tick() { - setDate(new Date()); - } - - return ( - <div> - <h2>It is {date.toLocaleTimeString()}.</h2> - </div> - ); - } - ``` +````md +```jsx live +function Clock(props) { + const [date, setDate] = useState(new Date()); + useEffect(() => { + var timerID = setInterval(() => tick(), 1000); + + return function cleanup() { + clearInterval(timerID); + }; + }); + + function tick() { + setDate(new Date()); + } + + return ( + <div> + <h2>It is {date.toLocaleTimeString()}.</h2> + </div> + ); +} +``` +```` The code block will be rendered as an interactive editor. Changes to the code will reflect on the result panel live. @@ -445,9 +453,9 @@ Syntax highlighting only works on plain strings. Docusaurus will not attempt to With MDX, you can easily create interactive components within your documentation, for example, to display code in multiple programming languages and switch between them using a tabs component. -Instead of implementing a dedicated component for multi-language support code blocks, we've implemented a generic Tabs component in the classic theme so that you can use it for other non-code scenarios as well. +Instead of implementing a dedicated component for multi-language support code blocks, we've implemented a general-purpose [`<Tabs>`](./markdown-features-tabs.mdx) component in the classic theme so that you can use it for other non-code scenarios as well. -The following example is how you can have multi-language code tabs in your docs. Note that the empty lines above and below each language block are **intentional**. This is a current limitation of MDX: you have to leave empty lines around Markdown syntax for the MDX parser to know that it's Markdown syntax and not JSX. +The following example is how you can have multi-language code tabs in your docs. Note that the empty lines above and below each language block are **intentional**. This is a [current limitation of MDX](./markdown-features-react.mdx#markdown-and-jsx-interoperability): you have to leave empty lines around Markdown syntax for the MDX parser to know that it's Markdown syntax and not JSX. ````jsx import Tabs from '@theme/Tabs'; @@ -467,7 +475,7 @@ function helloWorld() { ```py def hello_world(): - print 'Hello, world!' + print("Hello, world!") ``` </TabItem> @@ -503,7 +511,7 @@ function helloWorld() { ```py def hello_world(): - print 'Hello, world!' + print("Hello, world!") ``` </TabItem> diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-head-metadata.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-head-metadata.mdx similarity index 63% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-head-metadata.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-head-metadata.mdx index fa987eb1fedf..1a2c04095c1c 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-head-metadata.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-head-metadata.mdx @@ -7,9 +7,7 @@ slug: /markdown-features/head-metadata # Head Metadata -Docusaurus automatically sets useful page metadata in `<html>`, `<head>` and `<body>` for you. - -It is possible to add extra metadata (or override existing ones) by using the `<head>` tag in Markdown files: +Docusaurus automatically sets useful page metadata in `<html>`, `<head>` and `<body>` for you. It is possible to add extra metadata (or override existing ones) with the `<head>` tag in Markdown files: ```md title="markdown-features-head-metadata.mdx" --- @@ -46,22 +44,18 @@ My text :::tip -This `<head>` declaration has been added to the current Markdown doc, as a demo. - -Open your browser DevTools and check how this page's metadata has been affected. +This `<head>` declaration has been added to the current Markdown doc as a demo. Open your browser DevTools and check how this page's metadata has been affected. ::: -:::tip +:::tip You don't need this for regular SEO -**You don't always need this for typical SEO needs.** Content plugins (e.g. docs and blog) provide front matter options like `description`, `keywords`, and `image`, which will be automatically applied to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `<head>` tag. +Content plugins (e.g. docs and blog) provide front matter options like `description`, `keywords`, and `image`, which will be automatically applied to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `<head>` tag. ::: :::note -This feature is built on top of the Docusaurus [`<Head>`](./../../docusaurus-core.md#head) component. - -Refer to [react-helmet](https://github.com/nfl/react-helmet) for exhaustive documentation. +This feature is built on top of the Docusaurus [`<Head>`](./../../docusaurus-core.md#head) component. Refer to [react-helmet](https://github.com/nfl/react-helmet) for exhaustive documentation. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-headings.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-headings.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-headings.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-headings.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-inline-toc.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-inline-toc.mdx similarity index 81% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-inline-toc.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-inline-toc.mdx index 4a48251ac4d0..8369a133184d 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-inline-toc.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-inline-toc.mdx @@ -7,15 +7,11 @@ slug: /markdown-features/inline-toc import BrowserWindow from '@site/src/components/BrowserWindow'; -Each Markdown document displays a tab of content on the top-right corner. - -But it is also possible to display an inline table of contents directly inside a markdown document, thanks to MDX. +Each Markdown document displays a table of contents on the top-right corner. But it is also possible to display an inline table of contents directly inside a markdown document, thanks to MDX. ## Full table of contents {#full-table-of-contents} -The `toc` variable is available in any MDX document and contains all the headings of an MDX document. - -By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel`. +The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. ```jsx import TOCInline from '@theme/TOCInline'; @@ -27,9 +23,7 @@ import TOCInline from '@theme/TOCInline'; import TOCInline from '@theme/TOCInline'; <BrowserWindow> - <TOCInline toc={toc} /> - </BrowserWindow> ``` @@ -53,12 +47,19 @@ import TOCInline from '@theme/TOCInline'; <TOCInline // Only show h2 and h4 headings toc={toc.filter((node) => node.level === 2 || node.level === 4)} + minHeadingLevel={2} + // Show h4 headings in addition to the default h2 and h3 headings + maxHeadingLevel={4} />; ``` ```mdx-code-block <BrowserWindow> -<TOCInline toc={toc.filter((node) => node.level === 2 || node.level === 4)} /> +<TOCInline + toc={toc.filter((node) => node.level === 2 || node.level === 4)} + minHeadingLevel={2} + maxHeadingLevel={4} +/> </BrowserWindow> ``` diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-intro.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-intro.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-intro.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-intro.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-math-equations.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-math-equations.mdx similarity index 95% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-math-equations.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-math-equations.mdx index d785f3d027c0..e3281d6fd6ad 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-math-equations.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-math-equations.mdx @@ -17,9 +17,10 @@ Please read [KaTeX](https://katex.org) documentation for more details. Write inline math equations by wrapping LaTeX equations between `$`: -```mdx -Let $f\colon[a,b] \to \R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be $F(x)= -\int_{a}^{x} f(t)\,dt$. Then $$F$$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$. +```latex +Let $f\colon[a,b]\to\R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be +$F(x)=\int_{a}^{x} f(t)\,dt$. Then $F$ is continuous, and at all $x$ such that +$f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$. ``` <BrowserWindow> @@ -33,7 +34,7 @@ Let $f\colon[a,b] \to \R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be $F(x For equation block or display mode, use line breaks and `$$`: -```mdx +```latex $$ I = \int_0^{2\pi} \sin(x)\,dx $$ diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-plugins.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-plugins.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-react.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-react.mdx similarity index 98% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-react.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-react.mdx index be6f0018fa05..08530fd72efc 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-react.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-react.mdx @@ -352,7 +352,7 @@ Now you can import code snippets from another file as it is: import CodeBlock from '@theme/CodeBlock'; import MyComponentSource from '!!raw-loader!./myComponent'; -<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock> +<CodeBlock language="jsx">{MyComponentSource}</CodeBlock> ``` <!-- prettier-ignore-end --> @@ -362,7 +362,7 @@ import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponen <BrowserWindow> -<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock> +<CodeBlock language="jsx">{MyComponentSource}</CodeBlock> </BrowserWindow> diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-react.module.css b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-react.module.css similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-react.module.css rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-react.module.css diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-tabs-styles.module.css b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs-styles.module.css similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-tabs-styles.module.css rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs-styles.module.css diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx similarity index 98% rename from website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-tabs.mdx rename to website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx index 55ce040ead00..062a9abe54f7 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx @@ -12,7 +12,7 @@ import TabItem from '@theme/TabItem'; import styles from './markdown-features-tabs-styles.module.css'; ``` -Docusaurus provides `<Tabs>` components that you can use thanks to [MDX](./markdown-features-react.mdx): +Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx): <!-- prettier-ignore-start --> ```jsx diff --git a/website/versioned_docs/version-2.0.0-beta.16/guides/whats-next.md b/website/versioned_docs/version-2.0.0-beta.18/guides/whats-next.md similarity index 89% rename from website/versioned_docs/version-2.0.0-beta.16/guides/whats-next.md rename to website/versioned_docs/version-2.0.0-beta.18/guides/whats-next.md index 17c322a59b8e..7782f58eeb29 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/guides/whats-next.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/whats-next.md @@ -6,8 +6,8 @@ Congratulations! You have understood most core features of Docusaurus now. You h - [Used the docs plugin](./docs/docs-introduction.md) to create documentation pages. This includes [configuring the sidebar](./docs/sidebar/index.md), and even [versioning](./docs/versioning.md) - [Used the blog plugin](../blog.mdx) to create a fully featured blog - Tried your hands on [a range of Markdown features](./markdown-features/markdown-features-intro.mdx), which are useful for all content plugins -- [Used stylesheets](../styling-layout.md) to customize your site's appearance -- [Put images and other assets](../static-assets.md) in your pages +- [Used stylesheets](../styling-layout.md) or [swizzling](../swizzling.md) to customize your site's appearance +- [Included images and other assets](../static-assets.md) in your pages - [Added search](../search.md) to your site - Understood how [browser support](../browser-support.md) and [SEO](../seo.md) are done through standard Docusaurus APIs - Learned about how [individual plugins](../using-plugins.md) are installed and configured diff --git a/website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-crowdin.mdx rename to website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-git.md b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-git.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-git.md rename to website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-git.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-introduction.md b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-introduction.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-introduction.md rename to website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-introduction.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-tutorial.md b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/i18n/i18n-tutorial.md rename to website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/installation.md b/website/versioned_docs/version-2.0.0-beta.18/installation.md similarity index 90% rename from website/versioned_docs/version-2.0.0-beta.16/installation.md rename to website/versioned_docs/version-2.0.0-beta.18/installation.md index 0a79f9b3f7cb..ceee8a5df6c8 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/installation.md +++ b/website/versioned_docs/version-2.0.0-beta.18/installation.md @@ -41,7 +41,7 @@ If you do not specify `name` or `template`, it will prompt you for them. We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus. -The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory. If it's a git repository, you can also specify a cloning strategy. Run `npx create-docusaurus@latest --help` for more information. +The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory. If it's a git repository, you can also specify a cloning strategy. You can also use the template's TypeScript variant by passing the `--typescript` flag. @@ -66,24 +66,24 @@ You can also initialize a new project using your preferred project manager: ````mdx-code-block <Tabs> -<TabItem value="npm v6+"> +<TabItem value="npm"> ```bash -npm init docusaurus website classic +npm init docusaurus ``` </TabItem> <TabItem value="yarn"> ```bash -yarn create docusaurus website classic +yarn create docusaurus ``` </TabItem> <TabItem value="pnpm"> ```bash -pnpm create docusaurus website classic +pnpm create docusaurus ``` </TabItem> @@ -99,11 +99,7 @@ Docusaurus makes best efforts to select a package manager to install dependencie npx create-docusaurus@latest my-website classic --package-manager yarn ``` -If you want to skip installing dependencies, use the `--skip-install` option. - -```bash -npx create-docusaurus@latest my-website classic --skip-install -``` +Run `npx create-docusaurus@latest --help` for more information about all available flags. ## Project structure {#project-structure} @@ -137,10 +133,10 @@ my-website ### Project structure rundown {#project-structure-rundown} -- `/blog/` - Contains the blog Markdown files. You can delete the directory if you do not want/need a blog. More details can be found in the [blog guide](blog.mdx) -- `/docs/` - Contains the Markdown files for the docs. Customize the order of the docs sidebar in `sidebars.js`. More details can be found in the [docs guide](./guides/docs/docs-markdown-features.mdx) -- `/src/` - Non-documentation files like pages or custom React components. You don't have to strictly put your non-documentation files in here but putting them under a centralized directory makes it easier to specify in case you need to do some sort of linting/processing - - `/src/pages` - Any files within this directory will be converted into a website page. More details can be found in the [pages guide](guides/creating-pages.md) +- `/blog/` - Contains the blog Markdown files. You can delete the directory if you've disabled the blog plugin, or you can change its name after setting the `path` option. More details can be found in the [blog guide](blog.mdx) +- `/docs/` - Contains the Markdown files for the docs. Customize the order of the docs sidebar in `sidebars.js`. You can delete the directory if you've disabled the docs plugin, or you can change its name after setting the `path` option. More details can be found in the [docs guide](./guides/docs/docs-markdown-features.mdx) +- `/src/` - Non-documentation files like pages or custom React components. You don't have to strictly put your non-documentation files here, but putting them under a centralized directory makes it easier to specify in case you need to do some sort of linting/processing + - `/src/pages` - Any JSX/TSX/MDX file within this directory will be converted into a website page. More details can be found in the [pages guide](guides/creating-pages.md) - `/static/` - Static directory. Any contents inside here will be copied into the root of the final `build` directory - `/docusaurus.config.js` - A config file containing the site configuration. This is the equivalent of `siteConfig.js` in Docusaurus v1 - `/package.json` - A Docusaurus website is a React app. You can install and use any npm packages you like in them diff --git a/website/versioned_docs/version-2.0.0-beta.16/introduction.md b/website/versioned_docs/version-2.0.0-beta.18/introduction.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/introduction.md rename to website/versioned_docs/version-2.0.0-beta.18/introduction.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-automated.md b/website/versioned_docs/version-2.0.0-beta.18/migration/migration-automated.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/migration/migration-automated.md rename to website/versioned_docs/version-2.0.0-beta.18/migration/migration-automated.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md b/website/versioned_docs/version-2.0.0-beta.18/migration/migration-manual.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/migration/migration-manual.md rename to website/versioned_docs/version-2.0.0-beta.18/migration/migration-manual.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-overview.md b/website/versioned_docs/version-2.0.0-beta.18/migration/migration-overview.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/migration/migration-overview.md rename to website/versioned_docs/version-2.0.0-beta.18/migration/migration-overview.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-translated-sites.md b/website/versioned_docs/version-2.0.0-beta.18/migration/migration-translated-sites.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/migration/migration-translated-sites.md rename to website/versioned_docs/version-2.0.0-beta.18/migration/migration-translated-sites.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/migration/migration-versioned-sites.md b/website/versioned_docs/version-2.0.0-beta.18/migration/migration-versioned-sites.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/migration/migration-versioned-sites.md rename to website/versioned_docs/version-2.0.0-beta.18/migration/migration-versioned-sites.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/playground.mdx b/website/versioned_docs/version-2.0.0-beta.18/playground.mdx similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/playground.mdx rename to website/versioned_docs/version-2.0.0-beta.18/playground.mdx diff --git a/website/versioned_docs/version-2.0.0-beta.16/search.md b/website/versioned_docs/version-2.0.0-beta.18/search.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/search.md rename to website/versioned_docs/version-2.0.0-beta.18/search.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/seo.md b/website/versioned_docs/version-2.0.0-beta.18/seo.md similarity index 96% rename from website/versioned_docs/version-2.0.0-beta.16/seo.md rename to website/versioned_docs/version-2.0.0-beta.18/seo.md index 111560af2801..3c61f7fae51b 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/seo.md +++ b/website/versioned_docs/version-2.0.0-beta.18/seo.md @@ -42,8 +42,30 @@ Similar to [global metadata](#global-metadata), Docusaurus also allows for the a Some content... ``` +Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter: + +```md +--- +title: Title for search engines; can be different from the actual heading +description: A short description of this page +image: a thumbnail image to be shown in social media cards +keywords: [keywords, describing, the main topics] +--- +``` + +When creating your React page, adding these fields in `Layout` would also improve SEO. + +:::tip + +Prefer to use front matter for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `<head>` tag. + +::: + +For JSX pages, you can use the Docusaurus [`<Head>`](docusaurus-core.md#head) component. + ```jsx title="my-react-page.jsx" import React from 'react'; +import Layout from '@theme/Layout'; import Head from '@docusaurus/Head'; export default function page() { @@ -58,22 +80,9 @@ export default function page() { } ``` -Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter: - -```md ---- -title: Title for search engines; can be different from the actual heading -description: A short description of this page -image: a thumbnail image to be shown in social media cards -keywords: [keywords, describing, the main topics] ---- -``` - -When creating your React page, adding these fields in `Layout` would also improve SEO. - :::tip -Prefer to use front matter for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `<head>` tag. +For convenience, the default theme `<Layout>` component accept `title` and `description` as props. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/static-assets.md b/website/versioned_docs/version-2.0.0-beta.18/static-assets.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/static-assets.md rename to website/versioned_docs/version-2.0.0-beta.18/static-assets.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/styling-layout.md b/website/versioned_docs/version-2.0.0-beta.18/styling-layout.md similarity index 91% rename from website/versioned_docs/version-2.0.0-beta.16/styling-layout.md rename to website/versioned_docs/version-2.0.0-beta.18/styling-layout.md index e2f877d4b362..b6cba21b2e5d 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/styling-layout.md +++ b/website/versioned_docs/version-2.0.0-beta.18/styling-layout.md @@ -20,7 +20,7 @@ There are a few approaches/frameworks which will work, depending on your prefere This is the most traditional way of styling that most developers (including non-front-end developers) would be familiar with. It works fine for small websites that do not have much customization. -If you're using `@docusaurus/preset-classic`, you can create your own CSS files (e.g. `/src/css/custom.css`) and import them globally by passing them as an option into the preset. +If you're using `@docusaurus/preset-classic`, you can create your own CSS files (e.g. `/src/css/custom.css`) and import them globally by passing them as an option of the classic theme. ```js title="docusaurus.config.js" module.exports = { @@ -114,7 +114,7 @@ Alternatively, use the following tool to generate the different shades for your ### Dark Mode {#dark-mode} -In light mode, the `<html>` element has a `data-theme="light"` attribute; and in dark mode, it's `data-theme="dark"`. Therefore, you can scope your CSS to dark-mode-only by targeting `html` with a specific attribute. +In light mode, the `<html>` element has a `data-theme="light"` attribute; in dark mode, it's `data-theme="dark"`. Therefore, you can scope your CSS to dark-mode-only by targeting `html` with a specific attribute. ```css /* Overriding root Infima variables */ @@ -129,14 +129,14 @@ In light mode, the `<html>` element has a `data-theme="light"` attribute; and in ### Mobile View {#mobile-view} -Docusaurus uses `966px` as the cutoff between mobile screen width and desktop. If you want your layout to be different in the mobile view, you can use media queries. +Docusaurus uses `996px` as the cutoff between mobile screen width and desktop. If you want your layout to be different in the mobile view, you can use media queries. ```css .banner { padding: 4rem; } /** In mobile view, reduce the padding */ -@media screen and (max-width: 966px) { +@media screen and (max-width: 996px) { .heroBanner { padding: 2rem; } @@ -145,7 +145,7 @@ Docusaurus uses `966px` as the cutoff between mobile screen width and desktop. I ## CSS modules {#css-modules} -To style your components using [CSS Modules](https://github.com/css-modules/css-modules), name your stylesheet files with the `.module.css` suffix (e.g. `welcome.module.css`). webpack will load such CSS files as CSS modules and you have to reference the class names from the imported CSS module (as opposed to using plain strings). This is similar to the convention used in [Create React App](https://facebook.github.io/create-react-app/docs/adding-a-css-modules-stylesheet). +To style your components using [CSS Modules](https://github.com/css-modules/css-modules), name your stylesheet files with the `.module.css` suffix (e.g. `welcome.module.css`). Webpack will load such CSS files as CSS modules and you have to reference the class names as properties of the imported CSS module (as opposed to using plain strings). This is similar to the convention used in [Create React App](https://facebook.github.io/create-react-app/docs/adding-a-css-modules-stylesheet). ```css title="styles.module.css" .main { @@ -180,7 +180,7 @@ The class names will be processed by webpack into a globally unique class name d :::caution -This section is a work in progress. [Welcoming PRs](https://github.com/facebook/docusaurus/issues/1640). +CSS-in-JS support is a work in progress, so libs like MUI may have display quirks. [Welcoming PRs](https://github.com/facebook/docusaurus/issues/1640). ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/swizzling.md b/website/versioned_docs/version-2.0.0-beta.18/swizzling.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/swizzling.md rename to website/versioned_docs/version-2.0.0-beta.18/swizzling.md diff --git a/website/versioned_docs/version-2.0.0-beta.16/typescript-support.md b/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md similarity index 99% rename from website/versioned_docs/version-2.0.0-beta.16/typescript-support.md rename to website/versioned_docs/version-2.0.0-beta.18/typescript-support.md index 3f9e09716855..13f6ad57158e 100644 --- a/website/versioned_docs/version-2.0.0-beta.16/typescript-support.md +++ b/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md @@ -115,7 +115,7 @@ By default, the Docusaurus TypeScript config does not type-check JavaScript file The `// @ts-check` comment ensures the config file is properly type-checked when running: ```bash npm2yarn -npm run tsc +npx tsc ``` ::: diff --git a/website/versioned_docs/version-2.0.0-beta.16/using-plugins.md b/website/versioned_docs/version-2.0.0-beta.18/using-plugins.md similarity index 100% rename from website/versioned_docs/version-2.0.0-beta.16/using-plugins.md rename to website/versioned_docs/version-2.0.0-beta.18/using-plugins.md diff --git a/website/versioned_sidebars/version-2.0.0-beta.16-sidebars.json b/website/versioned_sidebars/version-2.0.0-beta.18-sidebars.json similarity index 100% rename from website/versioned_sidebars/version-2.0.0-beta.16-sidebars.json rename to website/versioned_sidebars/version-2.0.0-beta.18-sidebars.json diff --git a/website/versions.json b/website/versions.json index c93a85922de0..17b19bf8eb64 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,4 @@ [ - "2.0.0-beta.17", - "2.0.0-beta.16" + "2.0.0-beta.18", + "2.0.0-beta.17" ] diff --git a/website/versionsArchived.json b/website/versionsArchived.json index 561012c93e6b..c1fdc2893621 100644 --- a/website/versionsArchived.json +++ b/website/versionsArchived.json @@ -1,4 +1,5 @@ { + "2.0.0-beta.16": "https://623daf53d815110008446e27--docusaurus-2.netlify.app/docs/2.0.0-beta.16", "2.0.0-beta.15": "https://6220d0362c028b000827f851--docusaurus-2.netlify.app/docs/2.0.0-beta.15", "2.0.0-beta.14": "https://6218ceed1b19a70008d9c348--docusaurus-2.netlify.app/docs/2.0.0-beta.14", "2.0.0-beta.13": "https://61f16eafc42e860008d41557--docusaurus-2.netlify.app/docs/2.0.0-beta.13", From e97f2529d623e41577764859908c8d9e81874f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Fri, 25 Mar 2022 16:45:55 +0100 Subject: [PATCH 072/405] chore: regen examples for 2.0 beta.18 (#7002) --- .../docs/tutorial-basics/create-a-document.md | 6 +- examples/classic-typescript/package.json | 16 +- examples/classic-typescript/yarn.lock | 1207 ++++++++-------- .../docs/tutorial-basics/create-a-document.md | 6 +- examples/classic/package.json | 10 +- examples/classic/yarn.lock | 1191 ++++++++------- .../docs/tutorial-basics/create-a-document.md | 6 +- examples/facebook/package.json | 24 +- examples/facebook/yarn.lock | 1273 ++++++++--------- 9 files changed, 1803 insertions(+), 1936 deletions(-) diff --git a/examples/classic-typescript/docs/tutorial-basics/create-a-document.md b/examples/classic-typescript/docs/tutorial-basics/create-a-document.md index feaced79d0a3..a9bb9a4140b1 100644 --- a/examples/classic-typescript/docs/tutorial-basics/create-a-document.md +++ b/examples/classic-typescript/docs/tutorial-basics/create-a-document.md @@ -41,14 +41,14 @@ This is my **first Docusaurus document**! It is also possible to create your sidebar explicitly in `sidebars.js`: -```diff title="sidebars.js" +```js title="sidebars.js" module.exports = { tutorialSidebar: [ { type: 'category', label: 'Tutorial', -- items: [...], -+ items: ['hello'], + // highlight-next-line + items: ['hello'], }, ], }; diff --git a/examples/classic-typescript/package.json b/examples/classic-typescript/package.json index d29bf77dca08..acd799430570 100644 --- a/examples/classic-typescript/package.json +++ b/examples/classic-typescript/package.json @@ -16,18 +16,18 @@ "dev": "docusaurus start" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "prism-react-renderer": "^1.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "prism-react-renderer": "^1.3.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.0.0-beta.17", - "@tsconfig/docusaurus": "^1.0.4", - "typescript": "^4.6.2" + "@docusaurus/module-type-aliases": "2.0.0-beta.18", + "@tsconfig/docusaurus": "^1.0.5", + "typescript": "^4.6.3" }, "browserslist": { "production": [ diff --git a/examples/classic-typescript/yarn.lock b/examples/classic-typescript/yarn.lock index 8881b73f98c4..1fd0c7e58a8a 100644 --- a/examples/classic-typescript/yarn.lock +++ b/examples/classic-typescript/yarn.lock @@ -21,114 +21,114 @@ resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz#e157f9ad624ab8fd940ff28bd2094cdf199cdd79" integrity sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug== -"@algolia/cache-browser-local-storage@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.2.tgz#62935ddb81b50d539111b2146fa340495ec1cd53" - integrity sha512-z8LjFsQc0B6h6LEE3pkUGM4ErVktn6bkFbhnYbTccjmFVQ+wXFJd/D63e0WtaC+hwRB1xq8uKhkz9oojEKEsGA== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/cache-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.2.tgz#8512f311524f4d0aae8611e9879214a5e2a577ae" - integrity sha512-r//r7MF0Na0HxD2BHnjWsDKuI72Z5UEf/Rb/8MC08XKBsjCwBihGxWxycjRcNGjNEIxJBsvRMIEOipcd9qD54g== - -"@algolia/cache-in-memory@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.2.tgz#cacd13c02a7826bfad1c391d012ce00bc5db3859" - integrity sha512-opWpbBUloP1fcTG3wBDnAfcoyNXW5GFDgGtLXrSANdfnelPKkr3O8j01ZTkRlPIuBDR0izGZG8MVWMDlTf71Bw== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/client-account@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.2.tgz#adc4833b78576d1558ba45b7d44be22747debdc9" - integrity sha512-HZqEyeVVjzOlfoSUyc+7+ueEJmRgqSuC+hqQOGECYa5JVno4d8eRVuDAMOb87I2LOdg/WoFMcAtaaRq2gpfV/w== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-analytics@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.2.tgz#741115db1af7db9526acdd702890480480dc09ce" - integrity sha512-7ktimzesu+vk3l+eG9w/nQh6/9AoIieCKmoiRIguKh6okGsaSBrcTHvUwIQEIiliqPuAFBk2M8eXYFqOZzwCZw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.2.tgz#88ffd3ddececdc5f343a4a9cb1f6c4058fe780c1" - integrity sha512-+dTicT1lklwOpeoiDspUoRSQYHhrr2IzllrX89/WuTPEBm2eww1xurqrSTQYC0MuVeX1s9/i4k34Q0ZnspypWg== - dependencies: - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-personalization@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.2.tgz#5aa1d2a4bbc64559a98bb6d029dda59dbc86e490" - integrity sha512-JBW3vYFGIm5sAAy3cLUdmUCpmSAdreo5S1fERg7xgF6KyxGrwyy5BViTNWrOKG+av2yusk1wKydOYJ1Fbpbaxw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-search@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.2.tgz#940dd07ae4fa7aa86e382ecaf0a82445010b1b4c" - integrity sha512-JIqi14TgfEqAooNbSPBC1ZCk3Pnviqlaz9KofAqWBxSRTpPUFnU/XQCU5ihR0PC68SFVDnU/Y9cak/XotXPUeg== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" +"@algolia/cache-browser-local-storage@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.13.0.tgz#f8aa4fe31104b19d616ea392f9ed5c2ea847d964" + integrity sha512-nj1vHRZauTqP/bluwkRIgEADEimqojJgoTRCel5f6q8WCa9Y8QeI4bpDQP28FoeKnDRYa3J5CauDlN466jqRhg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/cache-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.13.0.tgz#27b83fd3939d08d72261b36a07eeafc4cb4d2113" + integrity sha512-f9mdZjskCui/dA/fA/5a+6hZ7xnHaaZI5tM/Rw9X8rRB39SUlF/+o3P47onZ33n/AwkpSbi5QOyhs16wHd55kA== + +"@algolia/cache-in-memory@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.13.0.tgz#10801a74550cbabb64b59ff08c56bce9c278ff2d" + integrity sha512-hHdc+ahPiMM92CQMljmObE75laYzNFYLrNOu0Q3/eyvubZZRtY2SUsEEgyUEyzXruNdzrkcDxFYa7YpWBJYHAg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/client-account@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.13.0.tgz#f8646dd40d1e9e3353e10abbd5d6c293ea92a8e2" + integrity sha512-FzFqFt9b0g/LKszBDoEsW+dVBuUe1K3scp2Yf7q6pgHWM1WqyqUlARwVpLxqyc+LoyJkTxQftOKjyFUqddnPKA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-analytics@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.13.0.tgz#a00bd02df45d71becb9dd4c5c993d805f2e1786d" + integrity sha512-klmnoq2FIiiMHImkzOm+cGxqRLLu9CMHqFhbgSy9wtXZrqb8BBUIUE2VyBe7azzv1wKcxZV2RUyNOMpFqmnRZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.13.0.tgz#8bc373d164dbdcce38b4586912bbe162492bcb86" + integrity sha512-GoXfTp0kVcbgfSXOjfrxx+slSipMqGO9WnNWgeMmru5Ra09MDjrcdunsiiuzF0wua6INbIpBQFTC2Mi5lUNqGA== + dependencies: + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-personalization@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.13.0.tgz#10fb7af356422551f11a67222b39c52306f1512c" + integrity sha512-KneLz2WaehJmNfdr5yt2HQETpLaCYagRdWwIwkTqRVFCv4DxRQ2ChPVW9jeTj4YfAAhfzE6F8hn7wkQ/Jfj6ZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-search@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.13.0.tgz#2d8ff8e755c4a37ec89968f3f9b358eed005c7f0" + integrity sha512-blgCKYbZh1NgJWzeGf+caKE32mo3j54NprOf0LZVCubQb3Kx37tk1Hc8SDs9bCAE8hUvf3cazMPIg7wscSxspA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.2.tgz#cdc9a685d7cf356a4d9e5915f741f1ee1a6baade" - integrity sha512-iOiJAymLjq137G7+8EQuUEkrgta0cZGMg6scp8s4hJ+X6k+6By4nyptdkCWYwKLsW/Xy927QcIhGlkWV78vQIQ== +"@algolia/logger-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.13.0.tgz#be2606e71aae618a1ff1ea9a1b5f5a74284b35a8" + integrity sha512-8yqXk7rMtmQJ9wZiHOt/6d4/JDEg5VCk83gJ39I+X/pwUPzIsbKy9QiK4uJ3aJELKyoIiDT1hpYVt+5ia+94IA== -"@algolia/logger-console@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.2.tgz#d7348e41378fbab5413cb5f97d8ae2ff378cfdb8" - integrity sha512-veuQZyTSqHoHJtr9mLMnYeal9Mee6hCie4eqY+645VbeOrgT9p/kCMbKg5GLJGoLPlXGu7C0XpHyUj5k7/NQyw== +"@algolia/logger-console@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.13.0.tgz#f28028a760e3d9191e28a10b12925e48f6c9afde" + integrity sha512-YepRg7w2/87L0vSXRfMND6VJ5d6699sFJBRWzZPOlek2p5fLxxK7O0VncYuc/IbVHEgeApvgXx0WgCEa38GVuQ== dependencies: - "@algolia/logger-common" "4.12.2" + "@algolia/logger-common" "4.13.0" -"@algolia/requester-browser-xhr@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.2.tgz#abfcb1901602ccdf51879b10d914208b776aa418" - integrity sha512-FpFdHNd81tS3zj6Glqd+lt+RV0ljPExKtx+QB+gani6HWZ9YlSCM+Zl82T4ibxN+hmkrMeAyT+TMzS0jiGhGyQ== +"@algolia/requester-browser-xhr@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.13.0.tgz#e2483f4e8d7f09e27cd0daf6c77711d15c5a919f" + integrity sha512-Dj+bnoWR5MotrnjblzGKZ2kCdQi2cK/VzPURPnE616NU/il7Ypy6U6DLGZ/ZYz+tnwPa0yypNf21uqt84fOgrg== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/requester-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.2.tgz#6d6181fb961205695bf535e108d2e5be8f8c9047" - integrity sha512-4szj/lvDQf/u8EyyRBBRZD1ZkKDyLBbckLj7meQDlnbfwnW1UpLwpB2l3XJ9wDmDSftGxUCeTl5oMFe4z9OEvQ== +"@algolia/requester-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.13.0.tgz#47fb3464cfb26b55ba43676d13f295d812830596" + integrity sha512-BRTDj53ecK+gn7ugukDWOOcBRul59C4NblCHqj4Zm5msd5UnHFjd/sGX+RLOEoFMhetILAnmg6wMrRrQVac9vw== -"@algolia/requester-node-http@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.2.tgz#f91e749ee6854c944cc741f13c539dff23363f67" - integrity sha512-UXfJNZt2KMwjBjiOa3cJ/PyoXWZa/F1vy6rdyG4xQeZDcLbqKP3O2b+bOJcGPmFbmdwBhtAyMVLt+hvAvAVfOw== +"@algolia/requester-node-http@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.13.0.tgz#7d981bbd31492f51dd11820a665f9d8906793c37" + integrity sha512-9b+3O4QFU4azLhGMrZAr/uZPydvzOR4aEZfSL8ZrpLZ7fbbqTO0S/5EVko+QIgglRAtVwxvf8UJ1wzTD2jvKxQ== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/transporter@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.2.tgz#60189b626b170f3386deb1d7a0a1e70ed8156864" - integrity sha512-PUq79if4CukXsm27ymTQ3eD3juSvMcyJmt6mxCkSFE0zQRL4ert61HBlNH6S9y/quUVe3g7oggfHq3d5pdpqZA== +"@algolia/transporter@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.13.0.tgz#f6379e5329efa2127da68c914d1141f5f21dbd07" + integrity sha512-8tSQYE+ykQENAdeZdofvtkOr5uJ9VcQSWgRhQ9h01AehtBIPAczk/b2CLrMsw5yQZziLs5cZ3pJ3478yI+urhA== dependencies: - "@algolia/cache-common" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/requester-common" "4.12.2" + "@algolia/cache-common" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/requester-common" "4.13.0" "@ampproject/remapping@^2.1.0": version "2.1.2" @@ -144,10 +144,10 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" - integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== "@babel/core@7.12.9": version "7.12.9" @@ -171,18 +171,18 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.15.5", "@babel/core@^7.17.5": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== +"@babel/core@^7.15.5", "@babel/core@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -192,10 +192,10 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== +"@babel/generator@^7.12.5", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== dependencies: "@babel/types" "^7.17.0" jsesc "^2.5.1" @@ -216,12 +216,12 @@ "@babel/helper-explode-assignable-expression" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.4" + "@babel/compat-data" "^7.17.7" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" @@ -299,11 +299,11 @@ "@babel/types" "^7.16.7" "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": version "7.16.7" @@ -312,14 +312,14 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" - integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" @@ -363,12 +363,12 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -404,13 +404,13 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" + "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" "@babel/highlight@^7.16.7": @@ -422,10 +422,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -751,9 +751,9 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz#c445f75819641788a27a0a3a759d9df911df6abc" - integrity sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -820,22 +820,22 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" - integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== dependencies: "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" @@ -1122,18 +1122,18 @@ "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-typescript" "^7.16.7" -"@babel/runtime-corejs3@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" - integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== +"@babel/runtime-corejs3@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" + integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== dependencies: core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.8.4": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" @@ -1146,7 +1146,7 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3": +"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": version "7.17.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== @@ -1185,32 +1185,32 @@ "@docsearch/css" "3.0.0" algoliasearch "^4.0.0" -"@docusaurus/core@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.17.tgz#f631aae04405de42a428a31928998242cd1d7b77" - integrity sha512-iNdW7CsmHNOgc4PxD9BFxa+MD8+i7ln7erOBkF3FSMMPnsKUeVqsR3rr31aLmLZRlTXMITSPLxlXwtBZa3KPCw== +"@docusaurus/core@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.18.tgz#44c6eefe29257462df630640a35f0c86bd80639a" + integrity sha512-puV7l+0/BPSi07Xmr8tVktfs1BzhC8P5pm6Bs2CfvysCJ4nefNCD1CosPc1PGBWy901KqeeEJ1aoGwj9tU3AUA== dependencies: - "@babel/core" "^7.17.5" - "@babel/generator" "^7.17.3" + "@babel/core" "^7.17.8" + "@babel/generator" "^7.17.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-transform-runtime" "^7.17.0" "@babel/preset-env" "^7.16.11" "@babel/preset-react" "^7.16.7" "@babel/preset-typescript" "^7.16.7" - "@babel/runtime" "^7.17.2" - "@babel/runtime-corejs3" "^7.17.2" + "@babel/runtime" "^7.17.8" + "@babel/runtime-corejs3" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/cssnano-preset" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" + "@docusaurus/cssnano-preset" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - "@slorber/static-site-generator-webpack-plugin" "^4.0.1" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + "@slorber/static-site-generator-webpack-plugin" "^4.0.4" "@svgr/webpack" "^6.2.1" - autoprefixer "^10.4.2" - babel-loader "^8.2.3" + autoprefixer "^10.4.4" + babel-loader "^8.2.4" babel-plugin-dynamic-import-node "2.3.0" boxen "^6.2.1" chokidar "^3.5.3" @@ -1220,9 +1220,9 @@ commander "^5.1.0" copy-webpack-plugin "^10.2.4" core-js "^3.21.1" - css-loader "^6.6.0" + css-loader "^6.7.1" css-minimizer-webpack-plugin "^3.4.1" - cssnano "^5.0.17" + cssnano "^5.1.5" del "^6.0.0" detect-port "^1.3.0" escape-html "^1.0.3" @@ -1236,9 +1236,9 @@ is-root "^2.1.0" leven "^3.1.0" lodash "^4.17.21" - mini-css-extract-plugin "^2.5.3" + mini-css-extract-plugin "^2.6.0" nprogress "^0.2.0" - postcss "^8.4.7" + postcss "^8.4.12" postcss-loader "^6.2.1" prompts "^2.4.2" react-dev-utils "^12.0.0" @@ -1250,7 +1250,7 @@ react-router-dom "^5.2.0" remark-admonitions "^1.2.1" rtl-detect "^1.0.4" - semver "^7.3.4" + semver "^7.3.5" serve-handler "^6.1.3" shelljs "^0.8.5" terser-webpack-plugin "^5.3.1" @@ -1258,38 +1258,38 @@ update-notifier "^5.1.0" url-loader "^4.1.1" wait-on "^6.0.1" - webpack "^5.69.1" + webpack "^5.70.0" webpack-bundle-analyzer "^4.5.0" webpack-dev-server "^4.7.4" webpack-merge "^5.8.0" webpackbar "^5.0.2" -"@docusaurus/cssnano-preset@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.17.tgz#f687bc6e5c8cb2139a7830dec757cfcb92dbb681" - integrity sha512-DoBwtLjJ9IY9/lNMHIEdo90L4NDayvU28nLgtjR2Sc6aBIMEB/3a5Ndjehnp+jZAkwcDdNASA86EkZVUyz1O1A== +"@docusaurus/cssnano-preset@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.18.tgz#235ac9064fe8f8da618349ce5305be3ed3a44e29" + integrity sha512-VxhYmpyx16Wv00W9TUfLVv0NgEK/BwP7pOdWoaiELEIAMV7SO1+6iB8gsFUhtfKZ31I4uPVLMKrCyWWakoFeFA== dependencies: - cssnano-preset-advanced "^5.1.12" - postcss "^8.4.7" + cssnano-preset-advanced "^5.3.1" + postcss "^8.4.12" postcss-sort-media-queries "^4.2.1" -"@docusaurus/logger@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.17.tgz#89c5ace3b4efd5274adb0d8919328892c4466d02" - integrity sha512-F9JDl06/VLg+ylsvnq9NpILSUeWtl0j4H2LtlLzX5gufEL4dGiCMlnUzYdHl7FSHSzYJ0A/R7vu0SYofsexC4w== +"@docusaurus/logger@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.18.tgz#12302f312a083eb018caa28505b63f5dd4ab6a91" + integrity sha512-frNe5vhH3mbPmH980Lvzaz45+n1PQl3TkslzWYXQeJOkFX17zUd3e3U7F9kR1+DocmAqHkgAoWuXVcvEoN29fg== dependencies: chalk "^4.1.2" tslib "^2.3.1" -"@docusaurus/mdx-loader@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.17.tgz#838f87f4cbf12701c4d8eb11e4f9698fb7155bf8" - integrity sha512-AhJ3GWRmjQYCyINHE595pff5tn3Rt83oGpdev5UT9uvG9lPYPC8nEmh1LI6c0ogfw7YkNznzxWSW4hyyVbYQ3A== +"@docusaurus/mdx-loader@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.18.tgz#4a9fc0607e0a210a7d7db3108415208dd36e33d3" + integrity sha512-pOmAQM4Y1jhuZTbEhjh4ilQa74Mh6Q0pMZn1xgIuyYDdqvIOrOlM/H0i34YBn3+WYuwsGim4/X0qynJMLDUA4A== dependencies: - "@babel/parser" "^7.17.3" + "@babel/parser" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" "@mdx-js/mdx" "^1.6.22" escape-html "^1.0.3" file-loader "^6.2.0" @@ -1301,30 +1301,30 @@ tslib "^2.3.1" unist-util-visit "^2.0.2" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/module-type-aliases@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.17.tgz#73f6d34be202ac093e78769ff72613d353087cd7" - integrity sha512-Tu+8geC/wyygBudbSwvWIHEvt5RwyA7dEoE1JmPbgQtmqUxOZ9bgnfemwXpJW5mKuDiJASbN4of1DhbLqf4sPg== +"@docusaurus/module-type-aliases@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.18.tgz#001379229c58cbc3ed565e19437cbda86d5e8742" + integrity sha512-e6mples8FZRyT7QyqidGS6BgkROjM+gljJsdOqoctbtBp+SZ5YDjwRHOmoY7eqEfsQNOaFZvT2hK38ui87hCRA== dependencies: - "@docusaurus/types" "2.0.0-beta.17" + "@docusaurus/types" "2.0.0-beta.18" "@types/react" "*" "@types/react-router-config" "*" "@types/react-router-dom" "*" react-helmet-async "*" -"@docusaurus/plugin-content-blog@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.17.tgz#1d1063bfda78a80d517694567b965d5c3a70479f" - integrity sha512-gcX4UR+WKT4bhF8FICBQHy+ESS9iRMeaglSboTZbA/YHGax/3EuZtcPU3dU4E/HFJeZ866wgUdbLKpIpsZOidg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/plugin-content-blog@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.18.tgz#95fe3dfc8bae9bf153c65a3a441234c450cbac0a" + integrity sha512-qzK83DgB+mxklk3PQC2nuTGPQD/8ogw1nXSmaQpyXAyhzcz4CXAZ9Swl/Ee9A/bvPwQGnSHSP3xqIYl8OkFtfw== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" cheerio "^1.0.0-rc.10" feed "^4.2.2" fs-extra "^10.0.1" @@ -1333,18 +1333,18 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" - -"@docusaurus/plugin-content-docs@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.17.tgz#97f13bb458e165224db6867836e8e9637ea15921" - integrity sha512-YYrBpuRfTfE6NtENrpSHTJ7K7PZifn6j6hcuvdC0QKE+WD8pS+O2/Ws30yoyvHwLnAnfhvaderh1v9Kaa0/ANg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + webpack "^5.70.0" + +"@docusaurus/plugin-content-docs@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.18.tgz#fef52d945da2928e0f4f3f9a9384d9ee7f2d4288" + integrity sha512-z4LFGBJuzn4XQiUA7OEA2SZTqlp+IYVjd3NrCk/ZUfNi1tsTJS36ATkk9Y6d0Nsp7K2kRXqaXPsz4adDgeIU+Q== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" combine-promises "^1.1.0" fs-extra "^10.0.1" import-fresh "^3.3.0" @@ -1353,80 +1353,80 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-content-pages@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.17.tgz#d5955d3cc23722518a6032f830cf8c7b7aeb3d5a" - integrity sha512-d5x0mXTMJ44ojRQccmLyshYoamFOep2AnBe69osCDnwWMbD3Or3pnc2KMK9N7mVpQFnNFKbHNCLrX3Rv0uwEHA== +"@docusaurus/plugin-content-pages@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.18.tgz#0fef392be3fea3d85c212caf4eb744ead920c30b" + integrity sha512-CJ2Xeb9hQrMeF4DGywSDVX2TFKsQpc8ZA7czyeBAAbSFsoRyxXPYeSh8aWljqR4F1u/EKGSKy0Shk/D4wumaHw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" remark-admonitions "^1.2.1" tslib "^2.3.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-debug@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.17.tgz#0185dfd5575aa940443d2cb9fab4bed3308ed3a1" - integrity sha512-p26fjYFRSC0esEmKo/kRrLVwXoFnzPCFDumwrImhPyqfVxbj+IKFaiXkayb2qHnyEGE/1KSDIgRF4CHt/pyhiw== +"@docusaurus/plugin-debug@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.18.tgz#d4582532e59b538a23398f7c444b005367efa922" + integrity sha512-inLnLERgG7q0WlVmK6nYGHwVqREz13ivkynmNygEibJZToFRdgnIPW+OwD8QzgC5MpQTJw7+uYjcitpBumy1Gw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" fs-extra "^10.0.1" react-json-view "^1.21.3" tslib "^2.3.1" -"@docusaurus/plugin-google-analytics@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.17.tgz#31ca1ef88f0f7874c6e12c642d64abe694494720" - integrity sha512-jvgYIhggYD1W2jymqQVAAyjPJUV1xMCn70bAzaCMxriureMWzhQ/kQMVQpop0ijTMvifOxaV9yTcL1VRXev++A== +"@docusaurus/plugin-google-analytics@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.18.tgz#a9b1659abb3f588e866aaa742ec4c82fe943eda3" + integrity sha512-s9dRBWDrZ1uu3wFXPCF7yVLo/+5LUFAeoxpXxzory8gn9GYDt8ZDj80h5DUyCLxiy72OG6bXWNOYS/Vc6cOPXQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-google-gtag@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.17.tgz#e6baf8f03cea756ed2259a5356fa689388bc303d" - integrity sha512-1pnWHtIk1Jfeqwvr8PlcPE5SODWT1gW4TI+ptmJbJ296FjjyvL/pG0AcGEJmYLY/OQc3oz0VQ0W2ognw9jmFIw== +"@docusaurus/plugin-google-gtag@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.18.tgz#b51611ac01915523ddcfc9732f7862cf4996a0e1" + integrity sha512-h7vPuLVo/9pHmbFcvb4tCpjg4SxxX4k+nfVDyippR254FM++Z/nA5pRB0WvvIJ3ZTe0ioOb5Wlx2xdzJIBHUNg== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-sitemap@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.17.tgz#e1aa67ff09d9145e8e5522c4541bbcdd6365560c" - integrity sha512-19/PaGCsap6cjUPZPGs87yV9e1hAIyd0CTSeVV6Caega8nmOKk20FTrQGFJjZPeX8jvD9QIXcdg6BJnPxcKkaQ== +"@docusaurus/plugin-sitemap@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.18.tgz#7e8217e95bede5719bd02265dcf7eb2fea76b675" + integrity sha512-Klonht0Ye3FivdBpS80hkVYNOH+8lL/1rbCPEV92rKhwYdwnIejqhdKct4tUTCl8TYwWiyeUFQqobC/5FNVZPQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" sitemap "^7.1.1" tslib "^2.3.1" -"@docusaurus/preset-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.17.tgz#a8fc3447aa6fe0e5f259d894cc8dd64c049c7605" - integrity sha512-7YUxPEgM09aZWr25/hpDEp1gPl+1KsCPV1ZTRW43sbQ9TinPm+9AKR3rHVDa8ea8MdiS7BpqCVyK+H/eiyQrUw== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/plugin-debug" "2.0.0-beta.17" - "@docusaurus/plugin-google-analytics" "2.0.0-beta.17" - "@docusaurus/plugin-google-gtag" "2.0.0-beta.17" - "@docusaurus/plugin-sitemap" "2.0.0-beta.17" - "@docusaurus/theme-classic" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-search-algolia" "2.0.0-beta.17" +"@docusaurus/preset-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.18.tgz#82f6905d34a13e46289ac4d2f1125e47033bd9d8" + integrity sha512-TfDulvFt/vLWr/Yy7O0yXgwHtJhdkZ739bTlFNwEkRMAy8ggi650e52I1I0T79s67llecb4JihgHPW+mwiVkCQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/plugin-debug" "2.0.0-beta.18" + "@docusaurus/plugin-google-analytics" "2.0.0-beta.18" + "@docusaurus/plugin-google-gtag" "2.0.0-beta.18" + "@docusaurus/plugin-sitemap" "2.0.0-beta.18" + "@docusaurus/theme-classic" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-search-algolia" "2.0.0-beta.18" "@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": version "5.5.2" @@ -1436,60 +1436,61 @@ "@types/react" "*" prop-types "^15.6.2" -"@docusaurus/theme-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.17.tgz#1f7a1dd714993819f266ce422d06dd4533d4ab3a" - integrity sha512-xfZ9kpgqo0lP9YO4rJj79wtiQJXU6ARo5wYy10IIwiWN+lg00scJHhkmNV431b05xIUjUr0cKeH9nqZmEsQRKg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/theme-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.18.tgz#a3632e83923ed4372f80999128375cd0b378d3f8" + integrity sha512-WJWofvSGKC4Luidk0lyUwkLnO3DDynBBHwmt4QrV+aAVWWSOHUjA2mPOF6GLGuzkZd3KfL9EvAfsU0aGE1Hh5g== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" "@mdx-js/react" "^1.6.22" clsx "^1.1.1" copy-text-to-clipboard "^3.0.1" - infima "0.2.0-alpha.37" + infima "0.2.0-alpha.38" lodash "^4.17.21" - postcss "^8.4.7" - prism-react-renderer "^1.2.1" + postcss "^8.4.12" + prism-react-renderer "^1.3.1" prismjs "^1.27.0" react-router-dom "^5.2.0" - rtlcss "^3.3.0" + rtlcss "^3.5.0" -"@docusaurus/theme-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.17.tgz#3b71bb8b0973a0cee969a1bb76794c81d597f290" - integrity sha512-LJBDhx+Qexn1JHBqZbE4k+7lBaV1LgpE33enXf43ShB7ebhC91d5HLHhBwgt0pih4+elZU4rG+BG/roAmsNM0g== +"@docusaurus/theme-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.18.tgz#abf74f82c37d2ce813f92447cb020831290059fb" + integrity sha512-3pI2Q6ttScDVTDbuUKAx+TdC8wmwZ2hfWk8cyXxksvC9bBHcyzXhSgcK8LTsszn2aANyZ3e3QY2eNSOikTFyng== dependencies: - "@docusaurus/module-type-aliases" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" + "@docusaurus/module-type-aliases" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" clsx "^1.1.1" parse-numeric-range "^1.3.0" prism-react-renderer "^1.3.1" tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-search-algolia@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.17.tgz#880fb965b71e5aa7f01d456a1a2aa8eb6c244082" - integrity sha512-W12XKM7QC5Jmrec359bJ7aDp5U8DNkCxjVKsMNIs8rDunBoI/N+R35ERJ0N7Bg9ONAWO6o7VkUERQsfGqdvr9w== +"@docusaurus/theme-search-algolia@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.18.tgz#cbdda8982deac4556848e04853b7f32d93886c02" + integrity sha512-2w97KO/gnjI49WVtYQqENpQ8iO1Sem0yaTxw7/qv/ndlmIAQD0syU4yx6GsA7bTQCOGwKOWWzZSetCgUmTnWgA== dependencies: "@docsearch/react" "^3.0.0" - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - algoliasearch "^4.12.1" - algoliasearch-helper "^3.7.0" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + algoliasearch "^4.13.0" + algoliasearch-helper "^3.7.4" clsx "^1.1.1" eta "^1.12.3" fs-extra "^10.0.1" @@ -1497,63 +1498,63 @@ tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-translations@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.17.tgz#a4b84fa63befc11847da471922387aa3eb4e5626" - integrity sha512-oxCX6khjZH3lgdRCL0DH06KkUM/kDr9+lzB35+vY8rpFeQruVgRdi8ekPqG3+Wr0U/N+LMhcYE5BmCb6D0Fv2A== +"@docusaurus/theme-translations@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.18.tgz#292699ce89b013262683faf7f4ee7b75a8745a79" + integrity sha512-1uTEUXlKC9nco1Lx9H5eOwzB+LP4yXJG5wfv1PMLE++kJEdZ40IVorlUi3nJnaa9/lJNq5vFvvUDrmeNWsxy/Q== dependencies: fs-extra "^10.0.1" tslib "^2.3.1" -"@docusaurus/types@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.17.tgz#582e3d961ce4409ed17454669b3f6a7a9f696cdd" - integrity sha512-4o7TXu5sKlQpybfFFtsGUElBXwSpiXKsQyyWaRKj7DRBkvMtkDX6ITZNnZO9+EHfLbP/cfrokB8C/oO7mCQ5BQ== +"@docusaurus/types@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.18.tgz#9446928a6b751eefde390420b39eac32ba26abb2" + integrity sha512-zkuSmPQYP3+z4IjGHlW0nGzSSpY7Sit0Nciu/66zSb5m07TK72t6T1MlpCAn/XijcB9Cq6nenC3kJh66nGsKYg== dependencies: commander "^5.1.0" joi "^17.6.0" - querystring "0.2.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" webpack-merge "^5.8.0" -"@docusaurus/utils-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.17.tgz#cefd950a7722f5f702690b4de27ea19fd65f3364" - integrity sha512-90WCVdj6zYzs7neEIS594qfLO78cUL6EVK1CsRHJgVkkGjcYlCQ1NwkyO7bOb+nIAwdJrPJRc2FBSpuEGxPD3w== +"@docusaurus/utils-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.18.tgz#46cf0bed2a7c532b2b85eab5bb914ff118b2c4e9" + integrity sha512-pK83EcOIiKCLGhrTwukZMo5jqd1sqqqhQwOVyxyvg+x9SY/lsnNzScA96OEfm+qQLBwK1OABA7Xc1wfkgkUxvw== dependencies: tslib "^2.3.1" -"@docusaurus/utils-validation@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.17.tgz#d7dbfc1a29768c37c0d8a6af85eb1bdfef7656df" - integrity sha512-5UjayUP16fDjgd52eSEhL7SlN9x60pIhyS+K7kt7RmpSLy42+4/bSr2pns2VlATmuaoNOO6iIFdB2jgSYJ6SGA== +"@docusaurus/utils-validation@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.18.tgz#0dabf113d2c53ee685a715cd4caae6e219e9e41e" + integrity sha512-3aDrXjJJ8Cw2MAYEk5JMNnr8UHPxmVNbPU/PIHFWmWK09nJvs3IQ8nc9+8I30aIjRdIyc/BIOCxgvAcJ4hsxTA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" joi "^17.6.0" + js-yaml "^4.1.0" tslib "^2.3.1" -"@docusaurus/utils@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.17.tgz#6a696e2ec5e50b2271f2d26d31562e9f3e2bc559" - integrity sha512-yRKGdzSc5v6M/6GyQ4omkrAHCleevwKYiIrufCJgRbOtkhYE574d8mIjjirOuA/emcyLxjh+TLtqAA5TwhIryA== +"@docusaurus/utils@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.18.tgz#c3fe0e9fac30db4510962263993fd0ee2679eebb" + integrity sha512-v2vBmH7xSbPwx3+GB90HgLSQdj+Rh5ELtZWy7M20w907k0ROzDmPQ/8Ke2DK3o5r4pZPGnCrsB3SaYI83AEmAA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@svgr/webpack" "^6.0.0" + "@docusaurus/logger" "2.0.0-beta.18" + "@svgr/webpack" "^6.2.1" file-loader "^6.2.0" fs-extra "^10.0.1" github-slugger "^1.4.0" - globby "^11.0.4" + globby "^11.1.0" gray-matter "^4.0.3" js-yaml "^4.1.0" lodash "^4.17.21" - micromatch "^4.0.4" + micromatch "^4.0.5" resolve-pathname "^3.0.0" shelljs "^0.8.5" tslib "^2.3.1" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" "@hapi/hoek@^9.0.0": version "9.2.1" @@ -1647,9 +1648,9 @@ integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== "@sideway/address@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" - integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== dependencies: "@hapi/hoek" "^9.0.0" @@ -1668,15 +1669,14 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@slorber/static-site-generator-webpack-plugin@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" - integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== +"@slorber/static-site-generator-webpack-plugin@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.4.tgz#2bf4a2545e027830d2aa5eb950437c26a289b0f1" + integrity sha512-FvMavoWEIePps6/JwGCOLYKCRhuwIHhMtmbKpBFgzNkxwpa/569LfTkrbRk1m1I3n+ezJK4on9E1A6cjuZmD9g== dependencies: bluebird "^3.7.1" cheerio "^0.22.0" - eval "^0.1.4" - url "^0.11.0" + eval "^0.1.8" webpack-sources "^1.4.3" "@svgr/babel-plugin-add-jsx-attribute@^6.0.0": @@ -1769,7 +1769,7 @@ deepmerge "^4.2.2" svgo "^2.5.0" -"@svgr/webpack@^6.0.0", "@svgr/webpack@^6.2.1": +"@svgr/webpack@^6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== @@ -1795,10 +1795,10 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@tsconfig/docusaurus@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.4.tgz#fc40f87a672568678d83533dd4031a09d75877ca" - integrity sha512-I6sziQAzLrrqj9r6S26c7aOAjfGVXIE7gWdNONPwnpDcHiMRMQut1s1YCi/APem3dOy23tAb2rvHfNtGCaWuUQ== +"@tsconfig/docusaurus@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.5.tgz#5298c5b0333c6263f06c3149b38ebccc9f169a4e" + integrity sha512-KM/TuJa9fugo67dTGx+ktIqf3fVc077J6jwHu845Hex4EQf7LABlNonP/mohDKT0cmncdtlYVHHF74xR/YpThg== "@types/body-parser@*": version "1.19.2" @@ -1895,9 +1895,9 @@ "@types/node" "*" "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/mdast@^3.0.0": version "3.0.10" @@ -1912,9 +1912,9 @@ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== "@types/node@*", "@types/node@^17.0.5": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/parse-json@^4.0.0": version "4.0.0" @@ -1968,9 +1968,9 @@ "@types/react" "*" "@types/react@*": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2021,9 +2021,9 @@ integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== "@types/ws@^8.2.2": - version "8.5.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.2.tgz#77e0c2e360e9579da930ffcfa53c5975ea3bdd26" - integrity sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw== + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== dependencies: "@types/node" "*" @@ -2224,41 +2224,41 @@ ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" uri-js "^4.2.2" -algoliasearch-helper@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz#c0a0493df84d850360f664ad7a9d4fc78a94fd78" - integrity sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w== +algoliasearch-helper@^3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.4.tgz#3812ea161da52463ec88da52612c9a363c1b181d" + integrity sha512-KmJrsHVm5TmxZ9Oj53XdXuM4CQeu7eVFnB15tpSFt+7is1d1yVCv3hxCLMqYSw/rH42ccv013miQpRr268P8vw== dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.0.0, algoliasearch@^4.12.1: - version "4.12.2" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.2.tgz#d7672a15b8fd1b261d9ae193535b68bcb189cfd2" - integrity sha512-bn1P9+V415zeDQJtXn+1SwuwedEAv9/LJAxt8XwR6ygH/sMwaHSm2hpkz8wIbCBt/tKQ43TL672Kyxzv5PwGgQ== - dependencies: - "@algolia/cache-browser-local-storage" "4.12.2" - "@algolia/cache-common" "4.12.2" - "@algolia/cache-in-memory" "4.12.2" - "@algolia/client-account" "4.12.2" - "@algolia/client-analytics" "4.12.2" - "@algolia/client-common" "4.12.2" - "@algolia/client-personalization" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/logger-console" "4.12.2" - "@algolia/requester-browser-xhr" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/requester-node-http" "4.12.2" - "@algolia/transporter" "4.12.2" +algoliasearch@^4.0.0, algoliasearch@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.13.0.tgz#e36611fda82b1fc548c156ae7929a7f486e4b663" + integrity sha512-oHv4faI1Vl2s+YC0YquwkK/TsaJs79g2JFg5FDm2rKN12VItPTAeQ7hyJMHarOPPYuCnNC5kixbtcqvb21wchw== + dependencies: + "@algolia/cache-browser-local-storage" "4.13.0" + "@algolia/cache-common" "4.13.0" + "@algolia/cache-in-memory" "4.13.0" + "@algolia/client-account" "4.13.0" + "@algolia/client-analytics" "4.13.0" + "@algolia/client-common" "4.13.0" + "@algolia/client-personalization" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/logger-console" "4.13.0" + "@algolia/requester-browser-xhr" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/requester-node-http" "4.13.0" + "@algolia/transporter" "4.13.0" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -2363,14 +2363,14 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.3.7, autoprefixer@^10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" - integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== +autoprefixer@^10.3.7, autoprefixer@^10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: - browserslist "^4.19.1" - caniuse-lite "^1.0.30001297" - fraction.js "^4.1.2" + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" @@ -2382,13 +2382,13 @@ axios@^0.25.0: dependencies: follow-redirects "^1.14.7" -babel-loader@^8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -2549,20 +2549,20 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1: - version "4.19.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.3.tgz#29b7caad327ecf2859485f696f9604214bedd383" - integrity sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== dependencies: - caniuse-lite "^1.0.30001312" - electron-to-chromium "^1.4.71" + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" escalade "^3.1.1" node-releases "^2.0.2" picocolors "^1.0.0" @@ -2641,10 +2641,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001312: - version "1.0.30001312" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== ccount@^1.0.0, ccount@^1.0.3: version "1.1.0" @@ -3056,13 +3056,13 @@ css-declaration-sorter@^6.0.3: dependencies: timsort "^0.3.0" -css-loader@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3" - integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg== +css-loader@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" + integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== dependencies: icss-utils "^5.1.0" - postcss "^8.4.5" + postcss "^8.4.7" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" @@ -3126,37 +3126,37 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.1.12: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.0.tgz#fc87b7c7327b61306e3e707e2f0fda3fa468f713" - integrity sha512-E7jJoKc2GjZsRLm8wQd2wZa+1a6tslA1elimwpcJTnH6dBQBkjQ8tAwNWUeyT72owYcCNGWTnar60bTnrnEWzw== +cssnano-preset-advanced@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.1.tgz#f4fa7006aab67e354289b3efd512c93a272b3874" + integrity sha512-kfCknalY5VX/JKJ3Iri5/5rhZmQIqkbqgXsA6oaTnfA4flY/tt+w0hMxbExr0/fVuJL8w56j211op+pkQoNzoQ== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" postcss-discard-unused "^5.1.0" - postcss-merge-idents "^5.1.0" - postcss-reduce-idents "^5.1.0" + postcss-merge-idents "^5.1.1" + postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.0.tgz#2579d38b9217746f2cf9f938954a91e00418ded6" - integrity sha512-3N5Vcptj2pqVKpHVqH6ezOJvqikR2PdLTbTrsrhF61FbLRQuujAqZ2sKN5rvcMsb7hFjrNnjZT8CGEkxoN/Pwg== +cssnano-preset-default@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" + integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== dependencies: css-declaration-sorter "^6.0.3" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" postcss-colormin "^5.3.0" postcss-convert-values "^5.1.0" - postcss-discard-comments "^5.1.0" + postcss-discard-comments "^5.1.1" postcss-discard-duplicates "^5.1.0" - postcss-discard-empty "^5.1.0" + postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.0" - postcss-merge-rules "^5.1.0" + postcss-merge-longhand "^5.1.3" + postcss-merge-rules "^5.1.1" postcss-minify-font-values "^5.1.0" - postcss-minify-gradients "^5.1.0" - postcss-minify-params "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.2" postcss-minify-selectors "^5.2.0" postcss-normalize-charset "^5.1.0" postcss-normalize-display-values "^5.1.0" @@ -3166,24 +3166,24 @@ cssnano-preset-default@^5.2.0: postcss-normalize-timing-functions "^5.1.0" postcss-normalize-unicode "^5.1.0" postcss-normalize-url "^5.1.0" - postcss-normalize-whitespace "^5.1.0" - postcss-ordered-values "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.1" postcss-reduce-initial "^5.1.0" postcss-reduce-transforms "^5.1.0" postcss-svgo "^5.1.0" - postcss-unique-selectors "^5.1.0" + postcss-unique-selectors "^5.1.1" cssnano-utils@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.17, cssnano@^5.0.6: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.0.tgz#cf977d660a5824d0d5542639ed1d4045afd84cbe" - integrity sha512-wWxave1wMlThGg4ueK98jFKaNqXnQd1nVZpSkQ9XvR+YymlzP1ofWqES1JkHtI250LksP9z5JH+oDcrKDJezAg== +cssnano@^5.0.6, cssnano@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" + integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== dependencies: - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" lilconfig "^2.0.3" yaml "^1.10.2" @@ -3214,9 +3214,9 @@ debug@^3.1.1: ms "^2.1.1" debug@^4.1.0, debug@^4.1.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -3402,9 +3402,9 @@ domhandler@^2.3.0: domelementtype "1" domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" @@ -3468,10 +3468,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.4.71: - version "1.4.75" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz#d1ad9bb46f2f1bf432118c2be21d27ffeae82fdd" - integrity sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q== +electron-to-chromium@^1.4.84: + version "1.4.93" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.93.tgz#2e87ac28721cb31d472ec2bd04f7daf9f2e13de2" + integrity sha512-ywq9Pc5Gwwpv7NG767CtoU8xF3aAUQJjH9//Wy3MBCg4w5JSLbJUq2L8IsCdzPMjvSgxuue9WcVaTOyyxCL0aQ== emoji-regex@^8.0.0: version "8.0.0" @@ -3610,11 +3610,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eval@^0.1.4: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" - integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== +eval@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.8.tgz#2b903473b8cc1d1989b83a1e7923f883eb357f85" + integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== dependencies: + "@types/node" "*" require-like ">= 0.1.1" eventemitter3@^4.0.0: @@ -3866,10 +3867,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.3.tgz#be65b0f20762ef27e1e793860bc2dfb716e99e65" - integrity sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg== +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== fresh@0.5.2: version "0.5.2" @@ -4017,7 +4018,7 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.1, globby@^11.0.4: +globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -4335,14 +4336,14 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" - integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== + version "0.5.6" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" + integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== http-proxy-middleware@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz#5df04f69a89f530c2284cd71eeaa51ba52243289" - integrity sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA== + version "2.0.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz#03af0f4676d172ae775cb5c33f592f40e1a4e07a" + integrity sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" @@ -4416,10 +4417,10 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infima@0.2.0-alpha.37: - version "0.2.0-alpha.37" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.37.tgz#b87ff42d528d6d050098a560f0294fbdd12adb78" - integrity sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q== +infima@0.2.0-alpha.38: + version "0.2.0-alpha.38" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.38.tgz#e41d95c7cd82756549b17df12f613fed4af3d528" + integrity sha512-1WsmqSMI5IqzrUx3goq+miJznHBonbE3aoqZ1AR/i/oHhroxNeSV6Awv5VoVfXBhfTzLSnxkHaRI2qpAMYcCzw== inflight@^1.0.4: version "1.0.6" @@ -4777,19 +4778,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^6.0.1: version "6.1.0" @@ -4835,9 +4827,9 @@ leven@^3.1.0: integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== lilconfig@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== lines-and-columns@^1.1.6: version "1.2.4" @@ -4849,15 +4841,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" @@ -5102,20 +5085,15 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -"mime-db@>= 1.43.0 < 2": +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5133,11 +5111,11 @@ mime-types@2.1.18: mime-db "~1.33.0" mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.51.0" + mime-db "1.52.0" mime@1.6.0: version "1.6.0" @@ -5162,10 +5140,10 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@^2.5.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9" - integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw== +mini-css-extract-plugin@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== dependencies: schema-utils "^4.0.0" @@ -5188,17 +5166,17 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" mrmime@^1.0.0: version "1.0.0" @@ -5271,9 +5249,9 @@ node-fetch@2.6.7: whatwg-url "^5.0.0" node-forge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" - integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" + integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== node-releases@^2.0.2: version "2.0.2" @@ -5598,7 +5576,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -5651,20 +5629,20 @@ postcss-convert-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-discard-comments@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.0.tgz#87be4e0953bf599935837b940c701f8d4eca7d0b" - integrity sha512-L0IKF4jAshRyn03SkEO6ar/Ipz2oLywVbg2THf2EqqdNkBwmVMxuTR/RoAltOw4piiaLt3gCAdrbAqmTBInmhg== +postcss-discard-comments@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" + integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== postcss-discard-duplicates@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.0.tgz#7f51b16cd1b89f8180bbc7cee34d6cbabf2ef810" - integrity sha512-782T/buGgb3HOuHOJAHpdyKzAAKsv/BxWqsutnZ+QsiHEcDkY7v+6WWdturuBiSal6XMOO1p1aJvwXdqLD5vhA== +postcss-discard-empty@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== postcss-discard-overridden@^5.1.0: version "5.1.0" @@ -5687,26 +5665,26 @@ postcss-loader@^6.2.1: klona "^2.0.5" semver "^7.3.5" -postcss-merge-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.0.tgz#948e1183cd659cfb5f99c7389f5fcec83c8f9a00" - integrity sha512-l+awq6+uUiCILsHahWK5KE25495I4oCKlUrIA+EdBvklnVdWlBEsbkzq5+ouPKb8OAe4WwRBgFvaSq7f77FY+w== +postcss-merge-idents@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz#7753817c2e0b75d0853b56f78a89771e15ca04a1" + integrity sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.0.tgz#f716bffbf0bdfbde6ea78c36088e21559f8a0a95" - integrity sha512-Gr46srN2tsLD8fudKYoHO56RG0BLQ2nsBRnSZGY04eNBPwTeWa9KeHrbL3tOLAHyB2aliikycPH2TMJG1U+W6g== +postcss-merge-longhand@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" + integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== dependencies: postcss-value-parser "^4.2.0" stylehacks "^5.1.0" -postcss-merge-rules@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.0.tgz#a2d5117eba09c8686a5471d97bd9afcf30d1b41f" - integrity sha512-NecukEJovQ0mG7h7xV8wbYAkXGTO3MPKnXvuiXzOKcxoOodfTTKYjeo8TMhAswlSkjcPIBlnKbSFcTuVSDaPyQ== +postcss-merge-rules@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" + integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== dependencies: browserslist "^4.16.6" caniuse-api "^3.0.0" @@ -5720,19 +5698,19 @@ postcss-minify-font-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.0.tgz#de0260a67a13b7b321a8adc3150725f2c6612377" - integrity sha512-J/TMLklkONn3LuL8wCwfwU8zKC1hpS6VcxFkNUNjmVt53uKqrrykR3ov11mdUYyqVMEx67slMce0tE14cE4DTg== +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== dependencies: colord "^2.9.1" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.0.tgz#e0b1f4e05cfd396682f612856485907e4064f25e" - integrity sha512-q67dcts4Hct6x8+JmhBgctHkbvUsqGIg2IItenjE63iZXMbhjr7AlVZkNnKtIGt/1Wsv7p/7YzeSII6Q+KPXRg== +postcss-minify-params@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" + integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== dependencies: browserslist "^4.16.6" cssnano-utils "^3.1.0" @@ -5829,25 +5807,25 @@ postcss-normalize-url@^5.1.0: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.0.tgz#aed8b4580c9ad6e8eac034177291187ea16a059c" - integrity sha512-7O1FanKaJkpWFyCghFzIkLhehujV/frGkdofGLwhg5upbLyGsSfiTcZAdSzoPsSUgyPCkBkNMeWR8yVgPdQybg== +postcss-normalize-whitespace@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.0.tgz#04ef429e0991b0292bc918b135cd4c038f7b889f" - integrity sha512-wU4Z4D4uOIH+BUKkYid36gGDJNQtkVJT7Twv8qH6UyfttbbJWyw4/xIPuVEkkCtQLAJ0EdsNSh8dlvqkXb49TA== +postcss-ordered-values@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" + integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.1.0.tgz#386b65cf861a9045663bd349d572027ab138ca4a" - integrity sha512-2xDoPTzv98D/HFDrGTgVEBlcuS47wvua2oc4g2WoZdYPwzPWMWb2TCRruCyN7vbl+HAtVLGvEOMZIZb3wYgv7w== +postcss-reduce-idents@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" + integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" @@ -5889,10 +5867,10 @@ postcss-svgo@^5.1.0: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.0.tgz#70a945da1b0599d00f617222a44ba1d82a676694" - integrity sha512-LmUhgGobtpeVJJHuogzjLRwJlN7VH+BL5c9GKMVJSS/ejoyePZkXvNsYUtk//F6vKOGK86gfRS0xH7fXQSDtvA== +postcss-unique-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" + integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== dependencies: postcss-selector-parser "^6.0.5" @@ -5906,10 +5884,10 @@ postcss-zindex@^5.1.0: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== -postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.5, postcss@^8.4.7: - version "8.4.7" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.7.tgz#f99862069ec4541de386bf57f5660a6c7a0875a8" - integrity sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A== +postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: nanoid "^3.3.1" picocolors "^1.0.0" @@ -5933,7 +5911,7 @@ pretty-time@^1.1.0: resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== -prism-react-renderer@^1.2.1, prism-react-renderer@^1.3.1: +prism-react-renderer@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== @@ -5995,11 +5973,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -6027,16 +6000,6 @@ qs@6.9.7: resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystring@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -6126,7 +6089,7 @@ react-dev-utils@^12.0.0: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.1: +react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -6228,7 +6191,7 @@ react-textarea-autosize@^8.3.2: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react@^17.0.1: +react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -6513,7 +6476,7 @@ rtl-detect@^1.0.4: resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== -rtlcss@^3.3.0: +rtlcss@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== @@ -6531,9 +6494,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== dependencies: tslib "^2.1.0" @@ -7062,9 +7025,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.1: terser "^5.7.2" terser@^5.10.0, terser@^5.7.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" - integrity sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A== + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== dependencies: acorn "^8.5.0" commander "^2.20.0" @@ -7154,9 +7117,9 @@ type-fest@^0.20.2: integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^2.5.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.0.tgz#ce342f58cab9114912f54b493d60ab39c3fc82b6" - integrity sha512-Qe5GRT+n/4GoqCNGGVp5Snapg1Omq3V7irBJB3EaKsp7HWDo5Gv2d/67gfNyV+d5EXD+x/RF5l1h4yJ7qNkcGA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" + integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== type-is@~1.6.18: version "1.6.18" @@ -7173,10 +7136,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +typescript@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== ua-parser-js@^0.7.30: version "0.7.31" @@ -7355,14 +7318,6 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use-composed-ref@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" @@ -7557,7 +7512,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.69.1: +webpack@^5.70.0: version "5.70.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== diff --git a/examples/classic/docs/tutorial-basics/create-a-document.md b/examples/classic/docs/tutorial-basics/create-a-document.md index feaced79d0a3..a9bb9a4140b1 100644 --- a/examples/classic/docs/tutorial-basics/create-a-document.md +++ b/examples/classic/docs/tutorial-basics/create-a-document.md @@ -41,14 +41,14 @@ This is my **first Docusaurus document**! It is also possible to create your sidebar explicitly in `sidebars.js`: -```diff title="sidebars.js" +```js title="sidebars.js" module.exports = { tutorialSidebar: [ { type: 'category', label: 'Tutorial', -- items: [...], -+ items: ['hello'], + // highlight-next-line + items: ['hello'], }, ], }; diff --git a/examples/classic/package.json b/examples/classic/package.json index 2d9fb788d6de..8c69f696a97e 100644 --- a/examples/classic/package.json +++ b/examples/classic/package.json @@ -15,13 +15,13 @@ "dev": "docusaurus start" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "prism-react-renderer": "^1.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "prism-react-renderer": "^1.3.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "browserslist": { "production": [ diff --git a/examples/classic/yarn.lock b/examples/classic/yarn.lock index 0d356623a0ae..c0468a24b5cf 100644 --- a/examples/classic/yarn.lock +++ b/examples/classic/yarn.lock @@ -21,114 +21,114 @@ resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz#e157f9ad624ab8fd940ff28bd2094cdf199cdd79" integrity sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug== -"@algolia/cache-browser-local-storage@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.2.tgz#62935ddb81b50d539111b2146fa340495ec1cd53" - integrity sha512-z8LjFsQc0B6h6LEE3pkUGM4ErVktn6bkFbhnYbTccjmFVQ+wXFJd/D63e0WtaC+hwRB1xq8uKhkz9oojEKEsGA== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/cache-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.2.tgz#8512f311524f4d0aae8611e9879214a5e2a577ae" - integrity sha512-r//r7MF0Na0HxD2BHnjWsDKuI72Z5UEf/Rb/8MC08XKBsjCwBihGxWxycjRcNGjNEIxJBsvRMIEOipcd9qD54g== - -"@algolia/cache-in-memory@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.2.tgz#cacd13c02a7826bfad1c391d012ce00bc5db3859" - integrity sha512-opWpbBUloP1fcTG3wBDnAfcoyNXW5GFDgGtLXrSANdfnelPKkr3O8j01ZTkRlPIuBDR0izGZG8MVWMDlTf71Bw== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/client-account@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.2.tgz#adc4833b78576d1558ba45b7d44be22747debdc9" - integrity sha512-HZqEyeVVjzOlfoSUyc+7+ueEJmRgqSuC+hqQOGECYa5JVno4d8eRVuDAMOb87I2LOdg/WoFMcAtaaRq2gpfV/w== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-analytics@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.2.tgz#741115db1af7db9526acdd702890480480dc09ce" - integrity sha512-7ktimzesu+vk3l+eG9w/nQh6/9AoIieCKmoiRIguKh6okGsaSBrcTHvUwIQEIiliqPuAFBk2M8eXYFqOZzwCZw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.2.tgz#88ffd3ddececdc5f343a4a9cb1f6c4058fe780c1" - integrity sha512-+dTicT1lklwOpeoiDspUoRSQYHhrr2IzllrX89/WuTPEBm2eww1xurqrSTQYC0MuVeX1s9/i4k34Q0ZnspypWg== - dependencies: - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-personalization@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.2.tgz#5aa1d2a4bbc64559a98bb6d029dda59dbc86e490" - integrity sha512-JBW3vYFGIm5sAAy3cLUdmUCpmSAdreo5S1fERg7xgF6KyxGrwyy5BViTNWrOKG+av2yusk1wKydOYJ1Fbpbaxw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-search@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.2.tgz#940dd07ae4fa7aa86e382ecaf0a82445010b1b4c" - integrity sha512-JIqi14TgfEqAooNbSPBC1ZCk3Pnviqlaz9KofAqWBxSRTpPUFnU/XQCU5ihR0PC68SFVDnU/Y9cak/XotXPUeg== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" +"@algolia/cache-browser-local-storage@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.13.0.tgz#f8aa4fe31104b19d616ea392f9ed5c2ea847d964" + integrity sha512-nj1vHRZauTqP/bluwkRIgEADEimqojJgoTRCel5f6q8WCa9Y8QeI4bpDQP28FoeKnDRYa3J5CauDlN466jqRhg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/cache-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.13.0.tgz#27b83fd3939d08d72261b36a07eeafc4cb4d2113" + integrity sha512-f9mdZjskCui/dA/fA/5a+6hZ7xnHaaZI5tM/Rw9X8rRB39SUlF/+o3P47onZ33n/AwkpSbi5QOyhs16wHd55kA== + +"@algolia/cache-in-memory@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.13.0.tgz#10801a74550cbabb64b59ff08c56bce9c278ff2d" + integrity sha512-hHdc+ahPiMM92CQMljmObE75laYzNFYLrNOu0Q3/eyvubZZRtY2SUsEEgyUEyzXruNdzrkcDxFYa7YpWBJYHAg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/client-account@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.13.0.tgz#f8646dd40d1e9e3353e10abbd5d6c293ea92a8e2" + integrity sha512-FzFqFt9b0g/LKszBDoEsW+dVBuUe1K3scp2Yf7q6pgHWM1WqyqUlARwVpLxqyc+LoyJkTxQftOKjyFUqddnPKA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-analytics@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.13.0.tgz#a00bd02df45d71becb9dd4c5c993d805f2e1786d" + integrity sha512-klmnoq2FIiiMHImkzOm+cGxqRLLu9CMHqFhbgSy9wtXZrqb8BBUIUE2VyBe7azzv1wKcxZV2RUyNOMpFqmnRZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.13.0.tgz#8bc373d164dbdcce38b4586912bbe162492bcb86" + integrity sha512-GoXfTp0kVcbgfSXOjfrxx+slSipMqGO9WnNWgeMmru5Ra09MDjrcdunsiiuzF0wua6INbIpBQFTC2Mi5lUNqGA== + dependencies: + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-personalization@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.13.0.tgz#10fb7af356422551f11a67222b39c52306f1512c" + integrity sha512-KneLz2WaehJmNfdr5yt2HQETpLaCYagRdWwIwkTqRVFCv4DxRQ2ChPVW9jeTj4YfAAhfzE6F8hn7wkQ/Jfj6ZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-search@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.13.0.tgz#2d8ff8e755c4a37ec89968f3f9b358eed005c7f0" + integrity sha512-blgCKYbZh1NgJWzeGf+caKE32mo3j54NprOf0LZVCubQb3Kx37tk1Hc8SDs9bCAE8hUvf3cazMPIg7wscSxspA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.2.tgz#cdc9a685d7cf356a4d9e5915f741f1ee1a6baade" - integrity sha512-iOiJAymLjq137G7+8EQuUEkrgta0cZGMg6scp8s4hJ+X6k+6By4nyptdkCWYwKLsW/Xy927QcIhGlkWV78vQIQ== +"@algolia/logger-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.13.0.tgz#be2606e71aae618a1ff1ea9a1b5f5a74284b35a8" + integrity sha512-8yqXk7rMtmQJ9wZiHOt/6d4/JDEg5VCk83gJ39I+X/pwUPzIsbKy9QiK4uJ3aJELKyoIiDT1hpYVt+5ia+94IA== -"@algolia/logger-console@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.2.tgz#d7348e41378fbab5413cb5f97d8ae2ff378cfdb8" - integrity sha512-veuQZyTSqHoHJtr9mLMnYeal9Mee6hCie4eqY+645VbeOrgT9p/kCMbKg5GLJGoLPlXGu7C0XpHyUj5k7/NQyw== +"@algolia/logger-console@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.13.0.tgz#f28028a760e3d9191e28a10b12925e48f6c9afde" + integrity sha512-YepRg7w2/87L0vSXRfMND6VJ5d6699sFJBRWzZPOlek2p5fLxxK7O0VncYuc/IbVHEgeApvgXx0WgCEa38GVuQ== dependencies: - "@algolia/logger-common" "4.12.2" + "@algolia/logger-common" "4.13.0" -"@algolia/requester-browser-xhr@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.2.tgz#abfcb1901602ccdf51879b10d914208b776aa418" - integrity sha512-FpFdHNd81tS3zj6Glqd+lt+RV0ljPExKtx+QB+gani6HWZ9YlSCM+Zl82T4ibxN+hmkrMeAyT+TMzS0jiGhGyQ== +"@algolia/requester-browser-xhr@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.13.0.tgz#e2483f4e8d7f09e27cd0daf6c77711d15c5a919f" + integrity sha512-Dj+bnoWR5MotrnjblzGKZ2kCdQi2cK/VzPURPnE616NU/il7Ypy6U6DLGZ/ZYz+tnwPa0yypNf21uqt84fOgrg== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/requester-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.2.tgz#6d6181fb961205695bf535e108d2e5be8f8c9047" - integrity sha512-4szj/lvDQf/u8EyyRBBRZD1ZkKDyLBbckLj7meQDlnbfwnW1UpLwpB2l3XJ9wDmDSftGxUCeTl5oMFe4z9OEvQ== +"@algolia/requester-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.13.0.tgz#47fb3464cfb26b55ba43676d13f295d812830596" + integrity sha512-BRTDj53ecK+gn7ugukDWOOcBRul59C4NblCHqj4Zm5msd5UnHFjd/sGX+RLOEoFMhetILAnmg6wMrRrQVac9vw== -"@algolia/requester-node-http@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.2.tgz#f91e749ee6854c944cc741f13c539dff23363f67" - integrity sha512-UXfJNZt2KMwjBjiOa3cJ/PyoXWZa/F1vy6rdyG4xQeZDcLbqKP3O2b+bOJcGPmFbmdwBhtAyMVLt+hvAvAVfOw== +"@algolia/requester-node-http@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.13.0.tgz#7d981bbd31492f51dd11820a665f9d8906793c37" + integrity sha512-9b+3O4QFU4azLhGMrZAr/uZPydvzOR4aEZfSL8ZrpLZ7fbbqTO0S/5EVko+QIgglRAtVwxvf8UJ1wzTD2jvKxQ== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/transporter@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.2.tgz#60189b626b170f3386deb1d7a0a1e70ed8156864" - integrity sha512-PUq79if4CukXsm27ymTQ3eD3juSvMcyJmt6mxCkSFE0zQRL4ert61HBlNH6S9y/quUVe3g7oggfHq3d5pdpqZA== +"@algolia/transporter@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.13.0.tgz#f6379e5329efa2127da68c914d1141f5f21dbd07" + integrity sha512-8tSQYE+ykQENAdeZdofvtkOr5uJ9VcQSWgRhQ9h01AehtBIPAczk/b2CLrMsw5yQZziLs5cZ3pJ3478yI+urhA== dependencies: - "@algolia/cache-common" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/requester-common" "4.12.2" + "@algolia/cache-common" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/requester-common" "4.13.0" "@ampproject/remapping@^2.1.0": version "2.1.2" @@ -144,10 +144,10 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" - integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== "@babel/core@7.12.9": version "7.12.9" @@ -171,18 +171,18 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.15.5", "@babel/core@^7.17.5": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== +"@babel/core@^7.15.5", "@babel/core@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -192,10 +192,10 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== +"@babel/generator@^7.12.5", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== dependencies: "@babel/types" "^7.17.0" jsesc "^2.5.1" @@ -216,12 +216,12 @@ "@babel/helper-explode-assignable-expression" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.4" + "@babel/compat-data" "^7.17.7" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" @@ -299,11 +299,11 @@ "@babel/types" "^7.16.7" "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": version "7.16.7" @@ -312,14 +312,14 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" - integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" @@ -363,12 +363,12 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -404,13 +404,13 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" + "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" "@babel/highlight@^7.16.7": @@ -422,10 +422,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -751,9 +751,9 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz#c445f75819641788a27a0a3a759d9df911df6abc" - integrity sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -820,22 +820,22 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" - integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== dependencies: "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" @@ -1122,18 +1122,18 @@ "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-typescript" "^7.16.7" -"@babel/runtime-corejs3@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" - integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== +"@babel/runtime-corejs3@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" + integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== dependencies: core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.8.4": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" @@ -1146,7 +1146,7 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3": +"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": version "7.17.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== @@ -1185,32 +1185,32 @@ "@docsearch/css" "3.0.0" algoliasearch "^4.0.0" -"@docusaurus/core@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.17.tgz#f631aae04405de42a428a31928998242cd1d7b77" - integrity sha512-iNdW7CsmHNOgc4PxD9BFxa+MD8+i7ln7erOBkF3FSMMPnsKUeVqsR3rr31aLmLZRlTXMITSPLxlXwtBZa3KPCw== +"@docusaurus/core@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.18.tgz#44c6eefe29257462df630640a35f0c86bd80639a" + integrity sha512-puV7l+0/BPSi07Xmr8tVktfs1BzhC8P5pm6Bs2CfvysCJ4nefNCD1CosPc1PGBWy901KqeeEJ1aoGwj9tU3AUA== dependencies: - "@babel/core" "^7.17.5" - "@babel/generator" "^7.17.3" + "@babel/core" "^7.17.8" + "@babel/generator" "^7.17.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-transform-runtime" "^7.17.0" "@babel/preset-env" "^7.16.11" "@babel/preset-react" "^7.16.7" "@babel/preset-typescript" "^7.16.7" - "@babel/runtime" "^7.17.2" - "@babel/runtime-corejs3" "^7.17.2" + "@babel/runtime" "^7.17.8" + "@babel/runtime-corejs3" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/cssnano-preset" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" + "@docusaurus/cssnano-preset" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - "@slorber/static-site-generator-webpack-plugin" "^4.0.1" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + "@slorber/static-site-generator-webpack-plugin" "^4.0.4" "@svgr/webpack" "^6.2.1" - autoprefixer "^10.4.2" - babel-loader "^8.2.3" + autoprefixer "^10.4.4" + babel-loader "^8.2.4" babel-plugin-dynamic-import-node "2.3.0" boxen "^6.2.1" chokidar "^3.5.3" @@ -1220,9 +1220,9 @@ commander "^5.1.0" copy-webpack-plugin "^10.2.4" core-js "^3.21.1" - css-loader "^6.6.0" + css-loader "^6.7.1" css-minimizer-webpack-plugin "^3.4.1" - cssnano "^5.0.17" + cssnano "^5.1.5" del "^6.0.0" detect-port "^1.3.0" escape-html "^1.0.3" @@ -1236,9 +1236,9 @@ is-root "^2.1.0" leven "^3.1.0" lodash "^4.17.21" - mini-css-extract-plugin "^2.5.3" + mini-css-extract-plugin "^2.6.0" nprogress "^0.2.0" - postcss "^8.4.7" + postcss "^8.4.12" postcss-loader "^6.2.1" prompts "^2.4.2" react-dev-utils "^12.0.0" @@ -1250,7 +1250,7 @@ react-router-dom "^5.2.0" remark-admonitions "^1.2.1" rtl-detect "^1.0.4" - semver "^7.3.4" + semver "^7.3.5" serve-handler "^6.1.3" shelljs "^0.8.5" terser-webpack-plugin "^5.3.1" @@ -1258,38 +1258,38 @@ update-notifier "^5.1.0" url-loader "^4.1.1" wait-on "^6.0.1" - webpack "^5.69.1" + webpack "^5.70.0" webpack-bundle-analyzer "^4.5.0" webpack-dev-server "^4.7.4" webpack-merge "^5.8.0" webpackbar "^5.0.2" -"@docusaurus/cssnano-preset@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.17.tgz#f687bc6e5c8cb2139a7830dec757cfcb92dbb681" - integrity sha512-DoBwtLjJ9IY9/lNMHIEdo90L4NDayvU28nLgtjR2Sc6aBIMEB/3a5Ndjehnp+jZAkwcDdNASA86EkZVUyz1O1A== +"@docusaurus/cssnano-preset@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.18.tgz#235ac9064fe8f8da618349ce5305be3ed3a44e29" + integrity sha512-VxhYmpyx16Wv00W9TUfLVv0NgEK/BwP7pOdWoaiELEIAMV7SO1+6iB8gsFUhtfKZ31I4uPVLMKrCyWWakoFeFA== dependencies: - cssnano-preset-advanced "^5.1.12" - postcss "^8.4.7" + cssnano-preset-advanced "^5.3.1" + postcss "^8.4.12" postcss-sort-media-queries "^4.2.1" -"@docusaurus/logger@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.17.tgz#89c5ace3b4efd5274adb0d8919328892c4466d02" - integrity sha512-F9JDl06/VLg+ylsvnq9NpILSUeWtl0j4H2LtlLzX5gufEL4dGiCMlnUzYdHl7FSHSzYJ0A/R7vu0SYofsexC4w== +"@docusaurus/logger@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.18.tgz#12302f312a083eb018caa28505b63f5dd4ab6a91" + integrity sha512-frNe5vhH3mbPmH980Lvzaz45+n1PQl3TkslzWYXQeJOkFX17zUd3e3U7F9kR1+DocmAqHkgAoWuXVcvEoN29fg== dependencies: chalk "^4.1.2" tslib "^2.3.1" -"@docusaurus/mdx-loader@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.17.tgz#838f87f4cbf12701c4d8eb11e4f9698fb7155bf8" - integrity sha512-AhJ3GWRmjQYCyINHE595pff5tn3Rt83oGpdev5UT9uvG9lPYPC8nEmh1LI6c0ogfw7YkNznzxWSW4hyyVbYQ3A== +"@docusaurus/mdx-loader@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.18.tgz#4a9fc0607e0a210a7d7db3108415208dd36e33d3" + integrity sha512-pOmAQM4Y1jhuZTbEhjh4ilQa74Mh6Q0pMZn1xgIuyYDdqvIOrOlM/H0i34YBn3+WYuwsGim4/X0qynJMLDUA4A== dependencies: - "@babel/parser" "^7.17.3" + "@babel/parser" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" "@mdx-js/mdx" "^1.6.22" escape-html "^1.0.3" file-loader "^6.2.0" @@ -1301,30 +1301,30 @@ tslib "^2.3.1" unist-util-visit "^2.0.2" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/module-type-aliases@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.17.tgz#73f6d34be202ac093e78769ff72613d353087cd7" - integrity sha512-Tu+8geC/wyygBudbSwvWIHEvt5RwyA7dEoE1JmPbgQtmqUxOZ9bgnfemwXpJW5mKuDiJASbN4of1DhbLqf4sPg== +"@docusaurus/module-type-aliases@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.18.tgz#001379229c58cbc3ed565e19437cbda86d5e8742" + integrity sha512-e6mples8FZRyT7QyqidGS6BgkROjM+gljJsdOqoctbtBp+SZ5YDjwRHOmoY7eqEfsQNOaFZvT2hK38ui87hCRA== dependencies: - "@docusaurus/types" "2.0.0-beta.17" + "@docusaurus/types" "2.0.0-beta.18" "@types/react" "*" "@types/react-router-config" "*" "@types/react-router-dom" "*" react-helmet-async "*" -"@docusaurus/plugin-content-blog@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.17.tgz#1d1063bfda78a80d517694567b965d5c3a70479f" - integrity sha512-gcX4UR+WKT4bhF8FICBQHy+ESS9iRMeaglSboTZbA/YHGax/3EuZtcPU3dU4E/HFJeZ866wgUdbLKpIpsZOidg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/plugin-content-blog@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.18.tgz#95fe3dfc8bae9bf153c65a3a441234c450cbac0a" + integrity sha512-qzK83DgB+mxklk3PQC2nuTGPQD/8ogw1nXSmaQpyXAyhzcz4CXAZ9Swl/Ee9A/bvPwQGnSHSP3xqIYl8OkFtfw== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" cheerio "^1.0.0-rc.10" feed "^4.2.2" fs-extra "^10.0.1" @@ -1333,18 +1333,18 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" - -"@docusaurus/plugin-content-docs@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.17.tgz#97f13bb458e165224db6867836e8e9637ea15921" - integrity sha512-YYrBpuRfTfE6NtENrpSHTJ7K7PZifn6j6hcuvdC0QKE+WD8pS+O2/Ws30yoyvHwLnAnfhvaderh1v9Kaa0/ANg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + webpack "^5.70.0" + +"@docusaurus/plugin-content-docs@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.18.tgz#fef52d945da2928e0f4f3f9a9384d9ee7f2d4288" + integrity sha512-z4LFGBJuzn4XQiUA7OEA2SZTqlp+IYVjd3NrCk/ZUfNi1tsTJS36ATkk9Y6d0Nsp7K2kRXqaXPsz4adDgeIU+Q== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" combine-promises "^1.1.0" fs-extra "^10.0.1" import-fresh "^3.3.0" @@ -1353,80 +1353,80 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-content-pages@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.17.tgz#d5955d3cc23722518a6032f830cf8c7b7aeb3d5a" - integrity sha512-d5x0mXTMJ44ojRQccmLyshYoamFOep2AnBe69osCDnwWMbD3Or3pnc2KMK9N7mVpQFnNFKbHNCLrX3Rv0uwEHA== +"@docusaurus/plugin-content-pages@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.18.tgz#0fef392be3fea3d85c212caf4eb744ead920c30b" + integrity sha512-CJ2Xeb9hQrMeF4DGywSDVX2TFKsQpc8ZA7czyeBAAbSFsoRyxXPYeSh8aWljqR4F1u/EKGSKy0Shk/D4wumaHw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" remark-admonitions "^1.2.1" tslib "^2.3.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-debug@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.17.tgz#0185dfd5575aa940443d2cb9fab4bed3308ed3a1" - integrity sha512-p26fjYFRSC0esEmKo/kRrLVwXoFnzPCFDumwrImhPyqfVxbj+IKFaiXkayb2qHnyEGE/1KSDIgRF4CHt/pyhiw== +"@docusaurus/plugin-debug@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.18.tgz#d4582532e59b538a23398f7c444b005367efa922" + integrity sha512-inLnLERgG7q0WlVmK6nYGHwVqREz13ivkynmNygEibJZToFRdgnIPW+OwD8QzgC5MpQTJw7+uYjcitpBumy1Gw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" fs-extra "^10.0.1" react-json-view "^1.21.3" tslib "^2.3.1" -"@docusaurus/plugin-google-analytics@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.17.tgz#31ca1ef88f0f7874c6e12c642d64abe694494720" - integrity sha512-jvgYIhggYD1W2jymqQVAAyjPJUV1xMCn70bAzaCMxriureMWzhQ/kQMVQpop0ijTMvifOxaV9yTcL1VRXev++A== +"@docusaurus/plugin-google-analytics@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.18.tgz#a9b1659abb3f588e866aaa742ec4c82fe943eda3" + integrity sha512-s9dRBWDrZ1uu3wFXPCF7yVLo/+5LUFAeoxpXxzory8gn9GYDt8ZDj80h5DUyCLxiy72OG6bXWNOYS/Vc6cOPXQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-google-gtag@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.17.tgz#e6baf8f03cea756ed2259a5356fa689388bc303d" - integrity sha512-1pnWHtIk1Jfeqwvr8PlcPE5SODWT1gW4TI+ptmJbJ296FjjyvL/pG0AcGEJmYLY/OQc3oz0VQ0W2ognw9jmFIw== +"@docusaurus/plugin-google-gtag@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.18.tgz#b51611ac01915523ddcfc9732f7862cf4996a0e1" + integrity sha512-h7vPuLVo/9pHmbFcvb4tCpjg4SxxX4k+nfVDyippR254FM++Z/nA5pRB0WvvIJ3ZTe0ioOb5Wlx2xdzJIBHUNg== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-sitemap@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.17.tgz#e1aa67ff09d9145e8e5522c4541bbcdd6365560c" - integrity sha512-19/PaGCsap6cjUPZPGs87yV9e1hAIyd0CTSeVV6Caega8nmOKk20FTrQGFJjZPeX8jvD9QIXcdg6BJnPxcKkaQ== +"@docusaurus/plugin-sitemap@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.18.tgz#7e8217e95bede5719bd02265dcf7eb2fea76b675" + integrity sha512-Klonht0Ye3FivdBpS80hkVYNOH+8lL/1rbCPEV92rKhwYdwnIejqhdKct4tUTCl8TYwWiyeUFQqobC/5FNVZPQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" sitemap "^7.1.1" tslib "^2.3.1" -"@docusaurus/preset-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.17.tgz#a8fc3447aa6fe0e5f259d894cc8dd64c049c7605" - integrity sha512-7YUxPEgM09aZWr25/hpDEp1gPl+1KsCPV1ZTRW43sbQ9TinPm+9AKR3rHVDa8ea8MdiS7BpqCVyK+H/eiyQrUw== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/plugin-debug" "2.0.0-beta.17" - "@docusaurus/plugin-google-analytics" "2.0.0-beta.17" - "@docusaurus/plugin-google-gtag" "2.0.0-beta.17" - "@docusaurus/plugin-sitemap" "2.0.0-beta.17" - "@docusaurus/theme-classic" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-search-algolia" "2.0.0-beta.17" +"@docusaurus/preset-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.18.tgz#82f6905d34a13e46289ac4d2f1125e47033bd9d8" + integrity sha512-TfDulvFt/vLWr/Yy7O0yXgwHtJhdkZ739bTlFNwEkRMAy8ggi650e52I1I0T79s67llecb4JihgHPW+mwiVkCQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/plugin-debug" "2.0.0-beta.18" + "@docusaurus/plugin-google-analytics" "2.0.0-beta.18" + "@docusaurus/plugin-google-gtag" "2.0.0-beta.18" + "@docusaurus/plugin-sitemap" "2.0.0-beta.18" + "@docusaurus/theme-classic" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-search-algolia" "2.0.0-beta.18" "@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": version "5.5.2" @@ -1436,60 +1436,61 @@ "@types/react" "*" prop-types "^15.6.2" -"@docusaurus/theme-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.17.tgz#1f7a1dd714993819f266ce422d06dd4533d4ab3a" - integrity sha512-xfZ9kpgqo0lP9YO4rJj79wtiQJXU6ARo5wYy10IIwiWN+lg00scJHhkmNV431b05xIUjUr0cKeH9nqZmEsQRKg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/theme-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.18.tgz#a3632e83923ed4372f80999128375cd0b378d3f8" + integrity sha512-WJWofvSGKC4Luidk0lyUwkLnO3DDynBBHwmt4QrV+aAVWWSOHUjA2mPOF6GLGuzkZd3KfL9EvAfsU0aGE1Hh5g== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" "@mdx-js/react" "^1.6.22" clsx "^1.1.1" copy-text-to-clipboard "^3.0.1" - infima "0.2.0-alpha.37" + infima "0.2.0-alpha.38" lodash "^4.17.21" - postcss "^8.4.7" - prism-react-renderer "^1.2.1" + postcss "^8.4.12" + prism-react-renderer "^1.3.1" prismjs "^1.27.0" react-router-dom "^5.2.0" - rtlcss "^3.3.0" + rtlcss "^3.5.0" -"@docusaurus/theme-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.17.tgz#3b71bb8b0973a0cee969a1bb76794c81d597f290" - integrity sha512-LJBDhx+Qexn1JHBqZbE4k+7lBaV1LgpE33enXf43ShB7ebhC91d5HLHhBwgt0pih4+elZU4rG+BG/roAmsNM0g== +"@docusaurus/theme-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.18.tgz#abf74f82c37d2ce813f92447cb020831290059fb" + integrity sha512-3pI2Q6ttScDVTDbuUKAx+TdC8wmwZ2hfWk8cyXxksvC9bBHcyzXhSgcK8LTsszn2aANyZ3e3QY2eNSOikTFyng== dependencies: - "@docusaurus/module-type-aliases" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" + "@docusaurus/module-type-aliases" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" clsx "^1.1.1" parse-numeric-range "^1.3.0" prism-react-renderer "^1.3.1" tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-search-algolia@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.17.tgz#880fb965b71e5aa7f01d456a1a2aa8eb6c244082" - integrity sha512-W12XKM7QC5Jmrec359bJ7aDp5U8DNkCxjVKsMNIs8rDunBoI/N+R35ERJ0N7Bg9ONAWO6o7VkUERQsfGqdvr9w== +"@docusaurus/theme-search-algolia@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.18.tgz#cbdda8982deac4556848e04853b7f32d93886c02" + integrity sha512-2w97KO/gnjI49WVtYQqENpQ8iO1Sem0yaTxw7/qv/ndlmIAQD0syU4yx6GsA7bTQCOGwKOWWzZSetCgUmTnWgA== dependencies: "@docsearch/react" "^3.0.0" - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - algoliasearch "^4.12.1" - algoliasearch-helper "^3.7.0" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + algoliasearch "^4.13.0" + algoliasearch-helper "^3.7.4" clsx "^1.1.1" eta "^1.12.3" fs-extra "^10.0.1" @@ -1497,63 +1498,63 @@ tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-translations@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.17.tgz#a4b84fa63befc11847da471922387aa3eb4e5626" - integrity sha512-oxCX6khjZH3lgdRCL0DH06KkUM/kDr9+lzB35+vY8rpFeQruVgRdi8ekPqG3+Wr0U/N+LMhcYE5BmCb6D0Fv2A== +"@docusaurus/theme-translations@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.18.tgz#292699ce89b013262683faf7f4ee7b75a8745a79" + integrity sha512-1uTEUXlKC9nco1Lx9H5eOwzB+LP4yXJG5wfv1PMLE++kJEdZ40IVorlUi3nJnaa9/lJNq5vFvvUDrmeNWsxy/Q== dependencies: fs-extra "^10.0.1" tslib "^2.3.1" -"@docusaurus/types@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.17.tgz#582e3d961ce4409ed17454669b3f6a7a9f696cdd" - integrity sha512-4o7TXu5sKlQpybfFFtsGUElBXwSpiXKsQyyWaRKj7DRBkvMtkDX6ITZNnZO9+EHfLbP/cfrokB8C/oO7mCQ5BQ== +"@docusaurus/types@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.18.tgz#9446928a6b751eefde390420b39eac32ba26abb2" + integrity sha512-zkuSmPQYP3+z4IjGHlW0nGzSSpY7Sit0Nciu/66zSb5m07TK72t6T1MlpCAn/XijcB9Cq6nenC3kJh66nGsKYg== dependencies: commander "^5.1.0" joi "^17.6.0" - querystring "0.2.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" webpack-merge "^5.8.0" -"@docusaurus/utils-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.17.tgz#cefd950a7722f5f702690b4de27ea19fd65f3364" - integrity sha512-90WCVdj6zYzs7neEIS594qfLO78cUL6EVK1CsRHJgVkkGjcYlCQ1NwkyO7bOb+nIAwdJrPJRc2FBSpuEGxPD3w== +"@docusaurus/utils-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.18.tgz#46cf0bed2a7c532b2b85eab5bb914ff118b2c4e9" + integrity sha512-pK83EcOIiKCLGhrTwukZMo5jqd1sqqqhQwOVyxyvg+x9SY/lsnNzScA96OEfm+qQLBwK1OABA7Xc1wfkgkUxvw== dependencies: tslib "^2.3.1" -"@docusaurus/utils-validation@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.17.tgz#d7dbfc1a29768c37c0d8a6af85eb1bdfef7656df" - integrity sha512-5UjayUP16fDjgd52eSEhL7SlN9x60pIhyS+K7kt7RmpSLy42+4/bSr2pns2VlATmuaoNOO6iIFdB2jgSYJ6SGA== +"@docusaurus/utils-validation@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.18.tgz#0dabf113d2c53ee685a715cd4caae6e219e9e41e" + integrity sha512-3aDrXjJJ8Cw2MAYEk5JMNnr8UHPxmVNbPU/PIHFWmWK09nJvs3IQ8nc9+8I30aIjRdIyc/BIOCxgvAcJ4hsxTA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" joi "^17.6.0" + js-yaml "^4.1.0" tslib "^2.3.1" -"@docusaurus/utils@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.17.tgz#6a696e2ec5e50b2271f2d26d31562e9f3e2bc559" - integrity sha512-yRKGdzSc5v6M/6GyQ4omkrAHCleevwKYiIrufCJgRbOtkhYE574d8mIjjirOuA/emcyLxjh+TLtqAA5TwhIryA== +"@docusaurus/utils@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.18.tgz#c3fe0e9fac30db4510962263993fd0ee2679eebb" + integrity sha512-v2vBmH7xSbPwx3+GB90HgLSQdj+Rh5ELtZWy7M20w907k0ROzDmPQ/8Ke2DK3o5r4pZPGnCrsB3SaYI83AEmAA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@svgr/webpack" "^6.0.0" + "@docusaurus/logger" "2.0.0-beta.18" + "@svgr/webpack" "^6.2.1" file-loader "^6.2.0" fs-extra "^10.0.1" github-slugger "^1.4.0" - globby "^11.0.4" + globby "^11.1.0" gray-matter "^4.0.3" js-yaml "^4.1.0" lodash "^4.17.21" - micromatch "^4.0.4" + micromatch "^4.0.5" resolve-pathname "^3.0.0" shelljs "^0.8.5" tslib "^2.3.1" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" "@hapi/hoek@^9.0.0": version "9.2.1" @@ -1647,9 +1648,9 @@ integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== "@sideway/address@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" - integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== dependencies: "@hapi/hoek" "^9.0.0" @@ -1668,15 +1669,14 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@slorber/static-site-generator-webpack-plugin@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" - integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== +"@slorber/static-site-generator-webpack-plugin@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.4.tgz#2bf4a2545e027830d2aa5eb950437c26a289b0f1" + integrity sha512-FvMavoWEIePps6/JwGCOLYKCRhuwIHhMtmbKpBFgzNkxwpa/569LfTkrbRk1m1I3n+ezJK4on9E1A6cjuZmD9g== dependencies: bluebird "^3.7.1" cheerio "^0.22.0" - eval "^0.1.4" - url "^0.11.0" + eval "^0.1.8" webpack-sources "^1.4.3" "@svgr/babel-plugin-add-jsx-attribute@^6.0.0": @@ -1769,7 +1769,7 @@ deepmerge "^4.2.2" svgo "^2.5.0" -"@svgr/webpack@^6.0.0", "@svgr/webpack@^6.2.1": +"@svgr/webpack@^6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== @@ -1890,9 +1890,9 @@ "@types/node" "*" "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/mdast@^3.0.0": version "3.0.10" @@ -1907,9 +1907,9 @@ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== "@types/node@*", "@types/node@^17.0.5": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/parse-json@^4.0.0": version "4.0.0" @@ -1963,9 +1963,9 @@ "@types/react" "*" "@types/react@*": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2016,9 +2016,9 @@ integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== "@types/ws@^8.2.2": - version "8.5.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.2.tgz#77e0c2e360e9579da930ffcfa53c5975ea3bdd26" - integrity sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw== + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== dependencies: "@types/node" "*" @@ -2219,41 +2219,41 @@ ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" uri-js "^4.2.2" -algoliasearch-helper@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz#c0a0493df84d850360f664ad7a9d4fc78a94fd78" - integrity sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w== +algoliasearch-helper@^3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.4.tgz#3812ea161da52463ec88da52612c9a363c1b181d" + integrity sha512-KmJrsHVm5TmxZ9Oj53XdXuM4CQeu7eVFnB15tpSFt+7is1d1yVCv3hxCLMqYSw/rH42ccv013miQpRr268P8vw== dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.0.0, algoliasearch@^4.12.1: - version "4.12.2" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.2.tgz#d7672a15b8fd1b261d9ae193535b68bcb189cfd2" - integrity sha512-bn1P9+V415zeDQJtXn+1SwuwedEAv9/LJAxt8XwR6ygH/sMwaHSm2hpkz8wIbCBt/tKQ43TL672Kyxzv5PwGgQ== - dependencies: - "@algolia/cache-browser-local-storage" "4.12.2" - "@algolia/cache-common" "4.12.2" - "@algolia/cache-in-memory" "4.12.2" - "@algolia/client-account" "4.12.2" - "@algolia/client-analytics" "4.12.2" - "@algolia/client-common" "4.12.2" - "@algolia/client-personalization" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/logger-console" "4.12.2" - "@algolia/requester-browser-xhr" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/requester-node-http" "4.12.2" - "@algolia/transporter" "4.12.2" +algoliasearch@^4.0.0, algoliasearch@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.13.0.tgz#e36611fda82b1fc548c156ae7929a7f486e4b663" + integrity sha512-oHv4faI1Vl2s+YC0YquwkK/TsaJs79g2JFg5FDm2rKN12VItPTAeQ7hyJMHarOPPYuCnNC5kixbtcqvb21wchw== + dependencies: + "@algolia/cache-browser-local-storage" "4.13.0" + "@algolia/cache-common" "4.13.0" + "@algolia/cache-in-memory" "4.13.0" + "@algolia/client-account" "4.13.0" + "@algolia/client-analytics" "4.13.0" + "@algolia/client-common" "4.13.0" + "@algolia/client-personalization" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/logger-console" "4.13.0" + "@algolia/requester-browser-xhr" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/requester-node-http" "4.13.0" + "@algolia/transporter" "4.13.0" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -2358,14 +2358,14 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.3.7, autoprefixer@^10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" - integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== +autoprefixer@^10.3.7, autoprefixer@^10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: - browserslist "^4.19.1" - caniuse-lite "^1.0.30001297" - fraction.js "^4.1.2" + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" @@ -2377,13 +2377,13 @@ axios@^0.25.0: dependencies: follow-redirects "^1.14.7" -babel-loader@^8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -2544,20 +2544,20 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1: - version "4.19.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.3.tgz#29b7caad327ecf2859485f696f9604214bedd383" - integrity sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== dependencies: - caniuse-lite "^1.0.30001312" - electron-to-chromium "^1.4.71" + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" escalade "^3.1.1" node-releases "^2.0.2" picocolors "^1.0.0" @@ -2636,10 +2636,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001312: - version "1.0.30001312" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== ccount@^1.0.0, ccount@^1.0.3: version "1.1.0" @@ -3051,13 +3051,13 @@ css-declaration-sorter@^6.0.3: dependencies: timsort "^0.3.0" -css-loader@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3" - integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg== +css-loader@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" + integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== dependencies: icss-utils "^5.1.0" - postcss "^8.4.5" + postcss "^8.4.7" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" @@ -3121,37 +3121,37 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.1.12: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.0.tgz#fc87b7c7327b61306e3e707e2f0fda3fa468f713" - integrity sha512-E7jJoKc2GjZsRLm8wQd2wZa+1a6tslA1elimwpcJTnH6dBQBkjQ8tAwNWUeyT72owYcCNGWTnar60bTnrnEWzw== +cssnano-preset-advanced@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.1.tgz#f4fa7006aab67e354289b3efd512c93a272b3874" + integrity sha512-kfCknalY5VX/JKJ3Iri5/5rhZmQIqkbqgXsA6oaTnfA4flY/tt+w0hMxbExr0/fVuJL8w56j211op+pkQoNzoQ== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" postcss-discard-unused "^5.1.0" - postcss-merge-idents "^5.1.0" - postcss-reduce-idents "^5.1.0" + postcss-merge-idents "^5.1.1" + postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.0.tgz#2579d38b9217746f2cf9f938954a91e00418ded6" - integrity sha512-3N5Vcptj2pqVKpHVqH6ezOJvqikR2PdLTbTrsrhF61FbLRQuujAqZ2sKN5rvcMsb7hFjrNnjZT8CGEkxoN/Pwg== +cssnano-preset-default@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" + integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== dependencies: css-declaration-sorter "^6.0.3" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" postcss-colormin "^5.3.0" postcss-convert-values "^5.1.0" - postcss-discard-comments "^5.1.0" + postcss-discard-comments "^5.1.1" postcss-discard-duplicates "^5.1.0" - postcss-discard-empty "^5.1.0" + postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.0" - postcss-merge-rules "^5.1.0" + postcss-merge-longhand "^5.1.3" + postcss-merge-rules "^5.1.1" postcss-minify-font-values "^5.1.0" - postcss-minify-gradients "^5.1.0" - postcss-minify-params "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.2" postcss-minify-selectors "^5.2.0" postcss-normalize-charset "^5.1.0" postcss-normalize-display-values "^5.1.0" @@ -3161,24 +3161,24 @@ cssnano-preset-default@^5.2.0: postcss-normalize-timing-functions "^5.1.0" postcss-normalize-unicode "^5.1.0" postcss-normalize-url "^5.1.0" - postcss-normalize-whitespace "^5.1.0" - postcss-ordered-values "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.1" postcss-reduce-initial "^5.1.0" postcss-reduce-transforms "^5.1.0" postcss-svgo "^5.1.0" - postcss-unique-selectors "^5.1.0" + postcss-unique-selectors "^5.1.1" cssnano-utils@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.17, cssnano@^5.0.6: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.0.tgz#cf977d660a5824d0d5542639ed1d4045afd84cbe" - integrity sha512-wWxave1wMlThGg4ueK98jFKaNqXnQd1nVZpSkQ9XvR+YymlzP1ofWqES1JkHtI250LksP9z5JH+oDcrKDJezAg== +cssnano@^5.0.6, cssnano@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" + integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== dependencies: - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" lilconfig "^2.0.3" yaml "^1.10.2" @@ -3209,9 +3209,9 @@ debug@^3.1.1: ms "^2.1.1" debug@^4.1.0, debug@^4.1.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -3397,9 +3397,9 @@ domhandler@^2.3.0: domelementtype "1" domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" @@ -3463,10 +3463,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.4.71: - version "1.4.75" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz#d1ad9bb46f2f1bf432118c2be21d27ffeae82fdd" - integrity sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q== +electron-to-chromium@^1.4.84: + version "1.4.93" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.93.tgz#2e87ac28721cb31d472ec2bd04f7daf9f2e13de2" + integrity sha512-ywq9Pc5Gwwpv7NG767CtoU8xF3aAUQJjH9//Wy3MBCg4w5JSLbJUq2L8IsCdzPMjvSgxuue9WcVaTOyyxCL0aQ== emoji-regex@^8.0.0: version "8.0.0" @@ -3605,11 +3605,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eval@^0.1.4: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" - integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== +eval@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.8.tgz#2b903473b8cc1d1989b83a1e7923f883eb357f85" + integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== dependencies: + "@types/node" "*" require-like ">= 0.1.1" eventemitter3@^4.0.0: @@ -3861,10 +3862,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.3.tgz#be65b0f20762ef27e1e793860bc2dfb716e99e65" - integrity sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg== +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== fresh@0.5.2: version "0.5.2" @@ -4012,7 +4013,7 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.1, globby@^11.0.4: +globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -4330,14 +4331,14 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" - integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== + version "0.5.6" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" + integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== http-proxy-middleware@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz#5df04f69a89f530c2284cd71eeaa51ba52243289" - integrity sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA== + version "2.0.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz#03af0f4676d172ae775cb5c33f592f40e1a4e07a" + integrity sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" @@ -4411,10 +4412,10 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infima@0.2.0-alpha.37: - version "0.2.0-alpha.37" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.37.tgz#b87ff42d528d6d050098a560f0294fbdd12adb78" - integrity sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q== +infima@0.2.0-alpha.38: + version "0.2.0-alpha.38" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.38.tgz#e41d95c7cd82756549b17df12f613fed4af3d528" + integrity sha512-1WsmqSMI5IqzrUx3goq+miJznHBonbE3aoqZ1AR/i/oHhroxNeSV6Awv5VoVfXBhfTzLSnxkHaRI2qpAMYcCzw== inflight@^1.0.4: version "1.0.6" @@ -4772,19 +4773,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^6.0.1: version "6.1.0" @@ -4830,9 +4822,9 @@ leven@^3.1.0: integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== lilconfig@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== lines-and-columns@^1.1.6: version "1.2.4" @@ -4844,15 +4836,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" @@ -5097,20 +5080,15 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -"mime-db@>= 1.43.0 < 2": +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5128,11 +5106,11 @@ mime-types@2.1.18: mime-db "~1.33.0" mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.51.0" + mime-db "1.52.0" mime@1.6.0: version "1.6.0" @@ -5157,10 +5135,10 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@^2.5.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9" - integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw== +mini-css-extract-plugin@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== dependencies: schema-utils "^4.0.0" @@ -5183,17 +5161,17 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" mrmime@^1.0.0: version "1.0.0" @@ -5266,9 +5244,9 @@ node-fetch@2.6.7: whatwg-url "^5.0.0" node-forge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" - integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" + integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== node-releases@^2.0.2: version "2.0.2" @@ -5593,7 +5571,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -5646,20 +5624,20 @@ postcss-convert-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-discard-comments@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.0.tgz#87be4e0953bf599935837b940c701f8d4eca7d0b" - integrity sha512-L0IKF4jAshRyn03SkEO6ar/Ipz2oLywVbg2THf2EqqdNkBwmVMxuTR/RoAltOw4piiaLt3gCAdrbAqmTBInmhg== +postcss-discard-comments@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" + integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== postcss-discard-duplicates@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.0.tgz#7f51b16cd1b89f8180bbc7cee34d6cbabf2ef810" - integrity sha512-782T/buGgb3HOuHOJAHpdyKzAAKsv/BxWqsutnZ+QsiHEcDkY7v+6WWdturuBiSal6XMOO1p1aJvwXdqLD5vhA== +postcss-discard-empty@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== postcss-discard-overridden@^5.1.0: version "5.1.0" @@ -5682,26 +5660,26 @@ postcss-loader@^6.2.1: klona "^2.0.5" semver "^7.3.5" -postcss-merge-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.0.tgz#948e1183cd659cfb5f99c7389f5fcec83c8f9a00" - integrity sha512-l+awq6+uUiCILsHahWK5KE25495I4oCKlUrIA+EdBvklnVdWlBEsbkzq5+ouPKb8OAe4WwRBgFvaSq7f77FY+w== +postcss-merge-idents@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz#7753817c2e0b75d0853b56f78a89771e15ca04a1" + integrity sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.0.tgz#f716bffbf0bdfbde6ea78c36088e21559f8a0a95" - integrity sha512-Gr46srN2tsLD8fudKYoHO56RG0BLQ2nsBRnSZGY04eNBPwTeWa9KeHrbL3tOLAHyB2aliikycPH2TMJG1U+W6g== +postcss-merge-longhand@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" + integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== dependencies: postcss-value-parser "^4.2.0" stylehacks "^5.1.0" -postcss-merge-rules@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.0.tgz#a2d5117eba09c8686a5471d97bd9afcf30d1b41f" - integrity sha512-NecukEJovQ0mG7h7xV8wbYAkXGTO3MPKnXvuiXzOKcxoOodfTTKYjeo8TMhAswlSkjcPIBlnKbSFcTuVSDaPyQ== +postcss-merge-rules@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" + integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== dependencies: browserslist "^4.16.6" caniuse-api "^3.0.0" @@ -5715,19 +5693,19 @@ postcss-minify-font-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.0.tgz#de0260a67a13b7b321a8adc3150725f2c6612377" - integrity sha512-J/TMLklkONn3LuL8wCwfwU8zKC1hpS6VcxFkNUNjmVt53uKqrrykR3ov11mdUYyqVMEx67slMce0tE14cE4DTg== +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== dependencies: colord "^2.9.1" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.0.tgz#e0b1f4e05cfd396682f612856485907e4064f25e" - integrity sha512-q67dcts4Hct6x8+JmhBgctHkbvUsqGIg2IItenjE63iZXMbhjr7AlVZkNnKtIGt/1Wsv7p/7YzeSII6Q+KPXRg== +postcss-minify-params@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" + integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== dependencies: browserslist "^4.16.6" cssnano-utils "^3.1.0" @@ -5824,25 +5802,25 @@ postcss-normalize-url@^5.1.0: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.0.tgz#aed8b4580c9ad6e8eac034177291187ea16a059c" - integrity sha512-7O1FanKaJkpWFyCghFzIkLhehujV/frGkdofGLwhg5upbLyGsSfiTcZAdSzoPsSUgyPCkBkNMeWR8yVgPdQybg== +postcss-normalize-whitespace@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.0.tgz#04ef429e0991b0292bc918b135cd4c038f7b889f" - integrity sha512-wU4Z4D4uOIH+BUKkYid36gGDJNQtkVJT7Twv8qH6UyfttbbJWyw4/xIPuVEkkCtQLAJ0EdsNSh8dlvqkXb49TA== +postcss-ordered-values@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" + integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.1.0.tgz#386b65cf861a9045663bd349d572027ab138ca4a" - integrity sha512-2xDoPTzv98D/HFDrGTgVEBlcuS47wvua2oc4g2WoZdYPwzPWMWb2TCRruCyN7vbl+HAtVLGvEOMZIZb3wYgv7w== +postcss-reduce-idents@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" + integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" @@ -5884,10 +5862,10 @@ postcss-svgo@^5.1.0: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.0.tgz#70a945da1b0599d00f617222a44ba1d82a676694" - integrity sha512-LmUhgGobtpeVJJHuogzjLRwJlN7VH+BL5c9GKMVJSS/ejoyePZkXvNsYUtk//F6vKOGK86gfRS0xH7fXQSDtvA== +postcss-unique-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" + integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== dependencies: postcss-selector-parser "^6.0.5" @@ -5901,10 +5879,10 @@ postcss-zindex@^5.1.0: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== -postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.5, postcss@^8.4.7: - version "8.4.7" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.7.tgz#f99862069ec4541de386bf57f5660a6c7a0875a8" - integrity sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A== +postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: nanoid "^3.3.1" picocolors "^1.0.0" @@ -5928,7 +5906,7 @@ pretty-time@^1.1.0: resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== -prism-react-renderer@^1.2.1, prism-react-renderer@^1.3.1: +prism-react-renderer@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== @@ -5990,11 +5968,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -6022,16 +5995,6 @@ qs@6.9.7: resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystring@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -6121,7 +6084,7 @@ react-dev-utils@^12.0.0: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.1: +react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -6223,7 +6186,7 @@ react-textarea-autosize@^8.3.2: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react@^17.0.1: +react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -6508,7 +6471,7 @@ rtl-detect@^1.0.4: resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== -rtlcss@^3.3.0: +rtlcss@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== @@ -6526,9 +6489,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== dependencies: tslib "^2.1.0" @@ -7057,9 +7020,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.1: terser "^5.7.2" terser@^5.10.0, terser@^5.7.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" - integrity sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A== + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== dependencies: acorn "^8.5.0" commander "^2.20.0" @@ -7149,9 +7112,9 @@ type-fest@^0.20.2: integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^2.5.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.0.tgz#ce342f58cab9114912f54b493d60ab39c3fc82b6" - integrity sha512-Qe5GRT+n/4GoqCNGGVp5Snapg1Omq3V7irBJB3EaKsp7HWDo5Gv2d/67gfNyV+d5EXD+x/RF5l1h4yJ7qNkcGA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" + integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== type-is@~1.6.18: version "1.6.18" @@ -7345,14 +7308,6 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use-composed-ref@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" @@ -7547,7 +7502,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.69.1: +webpack@^5.70.0: version "5.70.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== diff --git a/examples/facebook/docs/tutorial-basics/create-a-document.md b/examples/facebook/docs/tutorial-basics/create-a-document.md index feaced79d0a3..a9bb9a4140b1 100644 --- a/examples/facebook/docs/tutorial-basics/create-a-document.md +++ b/examples/facebook/docs/tutorial-basics/create-a-document.md @@ -41,14 +41,14 @@ This is my **first Docusaurus document**! It is also possible to create your sidebar explicitly in `sidebars.js`: -```diff title="sidebars.js" +```js title="sidebars.js" module.exports = { tutorialSidebar: [ { type: 'category', label: 'Tutorial', -- items: [...], -+ items: ['hello'], + // highlight-next-line + items: ['hello'], }, ], }; diff --git a/examples/facebook/package.json b/examples/facebook/package.json index e715e47413b6..49d830ef9e63 100644 --- a/examples/facebook/package.json +++ b/examples/facebook/package.json @@ -19,25 +19,25 @@ "dev": "docusaurus start" }, "dependencies": { - "@docusaurus/core": "2.0.0-beta.17", - "@docusaurus/preset-classic": "2.0.0-beta.17", + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/preset-classic": "2.0.0-beta.18", "@mdx-js/react": "^1.6.22", "clsx": "^1.1.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "devDependencies": { - "@babel/eslint-parser": "^7.16.3", - "eslint": "^8.8.0", - "eslint-config-airbnb": "^19.0.0", - "eslint-config-prettier": "^8.4.0", + "@babel/eslint-parser": "^7.17.0", + "eslint": "^8.11.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", - "eslint-plugin-import": "^2.25.3", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.29.2", + "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.3.0", - "prettier": "^2.5.1", - "stylelint": "^14.5.3" + "prettier": "^2.6.0", + "stylelint": "^14.6.0" }, "browserslist": { "production": [ diff --git a/examples/facebook/yarn.lock b/examples/facebook/yarn.lock index a4a733394d48..c469926e4eb2 100644 --- a/examples/facebook/yarn.lock +++ b/examples/facebook/yarn.lock @@ -21,114 +21,114 @@ resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz#e157f9ad624ab8fd940ff28bd2094cdf199cdd79" integrity sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug== -"@algolia/cache-browser-local-storage@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.2.tgz#62935ddb81b50d539111b2146fa340495ec1cd53" - integrity sha512-z8LjFsQc0B6h6LEE3pkUGM4ErVktn6bkFbhnYbTccjmFVQ+wXFJd/D63e0WtaC+hwRB1xq8uKhkz9oojEKEsGA== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/cache-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.2.tgz#8512f311524f4d0aae8611e9879214a5e2a577ae" - integrity sha512-r//r7MF0Na0HxD2BHnjWsDKuI72Z5UEf/Rb/8MC08XKBsjCwBihGxWxycjRcNGjNEIxJBsvRMIEOipcd9qD54g== - -"@algolia/cache-in-memory@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.2.tgz#cacd13c02a7826bfad1c391d012ce00bc5db3859" - integrity sha512-opWpbBUloP1fcTG3wBDnAfcoyNXW5GFDgGtLXrSANdfnelPKkr3O8j01ZTkRlPIuBDR0izGZG8MVWMDlTf71Bw== - dependencies: - "@algolia/cache-common" "4.12.2" - -"@algolia/client-account@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.2.tgz#adc4833b78576d1558ba45b7d44be22747debdc9" - integrity sha512-HZqEyeVVjzOlfoSUyc+7+ueEJmRgqSuC+hqQOGECYa5JVno4d8eRVuDAMOb87I2LOdg/WoFMcAtaaRq2gpfV/w== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-analytics@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.2.tgz#741115db1af7db9526acdd702890480480dc09ce" - integrity sha512-7ktimzesu+vk3l+eG9w/nQh6/9AoIieCKmoiRIguKh6okGsaSBrcTHvUwIQEIiliqPuAFBk2M8eXYFqOZzwCZw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.2.tgz#88ffd3ddececdc5f343a4a9cb1f6c4058fe780c1" - integrity sha512-+dTicT1lklwOpeoiDspUoRSQYHhrr2IzllrX89/WuTPEBm2eww1xurqrSTQYC0MuVeX1s9/i4k34Q0ZnspypWg== - dependencies: - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-personalization@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.2.tgz#5aa1d2a4bbc64559a98bb6d029dda59dbc86e490" - integrity sha512-JBW3vYFGIm5sAAy3cLUdmUCpmSAdreo5S1fERg7xgF6KyxGrwyy5BViTNWrOKG+av2yusk1wKydOYJ1Fbpbaxw== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" - -"@algolia/client-search@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.2.tgz#940dd07ae4fa7aa86e382ecaf0a82445010b1b4c" - integrity sha512-JIqi14TgfEqAooNbSPBC1ZCk3Pnviqlaz9KofAqWBxSRTpPUFnU/XQCU5ihR0PC68SFVDnU/Y9cak/XotXPUeg== - dependencies: - "@algolia/client-common" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/transporter" "4.12.2" +"@algolia/cache-browser-local-storage@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.13.0.tgz#f8aa4fe31104b19d616ea392f9ed5c2ea847d964" + integrity sha512-nj1vHRZauTqP/bluwkRIgEADEimqojJgoTRCel5f6q8WCa9Y8QeI4bpDQP28FoeKnDRYa3J5CauDlN466jqRhg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/cache-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.13.0.tgz#27b83fd3939d08d72261b36a07eeafc4cb4d2113" + integrity sha512-f9mdZjskCui/dA/fA/5a+6hZ7xnHaaZI5tM/Rw9X8rRB39SUlF/+o3P47onZ33n/AwkpSbi5QOyhs16wHd55kA== + +"@algolia/cache-in-memory@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.13.0.tgz#10801a74550cbabb64b59ff08c56bce9c278ff2d" + integrity sha512-hHdc+ahPiMM92CQMljmObE75laYzNFYLrNOu0Q3/eyvubZZRtY2SUsEEgyUEyzXruNdzrkcDxFYa7YpWBJYHAg== + dependencies: + "@algolia/cache-common" "4.13.0" + +"@algolia/client-account@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.13.0.tgz#f8646dd40d1e9e3353e10abbd5d6c293ea92a8e2" + integrity sha512-FzFqFt9b0g/LKszBDoEsW+dVBuUe1K3scp2Yf7q6pgHWM1WqyqUlARwVpLxqyc+LoyJkTxQftOKjyFUqddnPKA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-analytics@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.13.0.tgz#a00bd02df45d71becb9dd4c5c993d805f2e1786d" + integrity sha512-klmnoq2FIiiMHImkzOm+cGxqRLLu9CMHqFhbgSy9wtXZrqb8BBUIUE2VyBe7azzv1wKcxZV2RUyNOMpFqmnRZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.13.0.tgz#8bc373d164dbdcce38b4586912bbe162492bcb86" + integrity sha512-GoXfTp0kVcbgfSXOjfrxx+slSipMqGO9WnNWgeMmru5Ra09MDjrcdunsiiuzF0wua6INbIpBQFTC2Mi5lUNqGA== + dependencies: + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-personalization@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.13.0.tgz#10fb7af356422551f11a67222b39c52306f1512c" + integrity sha512-KneLz2WaehJmNfdr5yt2HQETpLaCYagRdWwIwkTqRVFCv4DxRQ2ChPVW9jeTj4YfAAhfzE6F8hn7wkQ/Jfj6ZA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" + +"@algolia/client-search@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.13.0.tgz#2d8ff8e755c4a37ec89968f3f9b358eed005c7f0" + integrity sha512-blgCKYbZh1NgJWzeGf+caKE32mo3j54NprOf0LZVCubQb3Kx37tk1Hc8SDs9bCAE8hUvf3cazMPIg7wscSxspA== + dependencies: + "@algolia/client-common" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/transporter" "4.13.0" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.2.tgz#cdc9a685d7cf356a4d9e5915f741f1ee1a6baade" - integrity sha512-iOiJAymLjq137G7+8EQuUEkrgta0cZGMg6scp8s4hJ+X6k+6By4nyptdkCWYwKLsW/Xy927QcIhGlkWV78vQIQ== +"@algolia/logger-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.13.0.tgz#be2606e71aae618a1ff1ea9a1b5f5a74284b35a8" + integrity sha512-8yqXk7rMtmQJ9wZiHOt/6d4/JDEg5VCk83gJ39I+X/pwUPzIsbKy9QiK4uJ3aJELKyoIiDT1hpYVt+5ia+94IA== -"@algolia/logger-console@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.2.tgz#d7348e41378fbab5413cb5f97d8ae2ff378cfdb8" - integrity sha512-veuQZyTSqHoHJtr9mLMnYeal9Mee6hCie4eqY+645VbeOrgT9p/kCMbKg5GLJGoLPlXGu7C0XpHyUj5k7/NQyw== +"@algolia/logger-console@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.13.0.tgz#f28028a760e3d9191e28a10b12925e48f6c9afde" + integrity sha512-YepRg7w2/87L0vSXRfMND6VJ5d6699sFJBRWzZPOlek2p5fLxxK7O0VncYuc/IbVHEgeApvgXx0WgCEa38GVuQ== dependencies: - "@algolia/logger-common" "4.12.2" + "@algolia/logger-common" "4.13.0" -"@algolia/requester-browser-xhr@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.2.tgz#abfcb1901602ccdf51879b10d914208b776aa418" - integrity sha512-FpFdHNd81tS3zj6Glqd+lt+RV0ljPExKtx+QB+gani6HWZ9YlSCM+Zl82T4ibxN+hmkrMeAyT+TMzS0jiGhGyQ== +"@algolia/requester-browser-xhr@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.13.0.tgz#e2483f4e8d7f09e27cd0daf6c77711d15c5a919f" + integrity sha512-Dj+bnoWR5MotrnjblzGKZ2kCdQi2cK/VzPURPnE616NU/il7Ypy6U6DLGZ/ZYz+tnwPa0yypNf21uqt84fOgrg== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/requester-common@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.2.tgz#6d6181fb961205695bf535e108d2e5be8f8c9047" - integrity sha512-4szj/lvDQf/u8EyyRBBRZD1ZkKDyLBbckLj7meQDlnbfwnW1UpLwpB2l3XJ9wDmDSftGxUCeTl5oMFe4z9OEvQ== +"@algolia/requester-common@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.13.0.tgz#47fb3464cfb26b55ba43676d13f295d812830596" + integrity sha512-BRTDj53ecK+gn7ugukDWOOcBRul59C4NblCHqj4Zm5msd5UnHFjd/sGX+RLOEoFMhetILAnmg6wMrRrQVac9vw== -"@algolia/requester-node-http@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.2.tgz#f91e749ee6854c944cc741f13c539dff23363f67" - integrity sha512-UXfJNZt2KMwjBjiOa3cJ/PyoXWZa/F1vy6rdyG4xQeZDcLbqKP3O2b+bOJcGPmFbmdwBhtAyMVLt+hvAvAVfOw== +"@algolia/requester-node-http@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.13.0.tgz#7d981bbd31492f51dd11820a665f9d8906793c37" + integrity sha512-9b+3O4QFU4azLhGMrZAr/uZPydvzOR4aEZfSL8ZrpLZ7fbbqTO0S/5EVko+QIgglRAtVwxvf8UJ1wzTD2jvKxQ== dependencies: - "@algolia/requester-common" "4.12.2" + "@algolia/requester-common" "4.13.0" -"@algolia/transporter@4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.2.tgz#60189b626b170f3386deb1d7a0a1e70ed8156864" - integrity sha512-PUq79if4CukXsm27ymTQ3eD3juSvMcyJmt6mxCkSFE0zQRL4ert61HBlNH6S9y/quUVe3g7oggfHq3d5pdpqZA== +"@algolia/transporter@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.13.0.tgz#f6379e5329efa2127da68c914d1141f5f21dbd07" + integrity sha512-8tSQYE+ykQENAdeZdofvtkOr5uJ9VcQSWgRhQ9h01AehtBIPAczk/b2CLrMsw5yQZziLs5cZ3pJ3478yI+urhA== dependencies: - "@algolia/cache-common" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/requester-common" "4.12.2" + "@algolia/cache-common" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/requester-common" "4.13.0" "@ampproject/remapping@^2.1.0": version "2.1.2" @@ -144,10 +144,10 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" - integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== "@babel/core@7.12.9": version "7.12.9" @@ -171,18 +171,18 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.15.5", "@babel/core@^7.17.5": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== +"@babel/core@^7.15.5", "@babel/core@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" @@ -192,7 +192,7 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/eslint-parser@^7.16.3": +"@babel/eslint-parser@^7.17.0": version "7.17.0" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== @@ -201,10 +201,10 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== +"@babel/generator@^7.12.5", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== dependencies: "@babel/types" "^7.17.0" jsesc "^2.5.1" @@ -225,12 +225,12 @@ "@babel/helper-explode-assignable-expression" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.4" + "@babel/compat-data" "^7.17.7" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" @@ -308,11 +308,11 @@ "@babel/types" "^7.16.7" "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": version "7.16.7" @@ -321,14 +321,14 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" - integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" @@ -372,12 +372,12 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -413,13 +413,13 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" + "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" "@babel/highlight@^7.16.7": @@ -431,10 +431,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" @@ -760,9 +760,9 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz#c445f75819641788a27a0a3a759d9df911df6abc" - integrity sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -829,22 +829,22 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" - integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== dependencies: "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" @@ -1131,18 +1131,18 @@ "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-typescript" "^7.16.7" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" - integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284" + integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ== dependencies: core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.8.4": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" @@ -1155,7 +1155,7 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3": +"@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": version "7.17.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== @@ -1194,32 +1194,32 @@ "@docsearch/css" "3.0.0" algoliasearch "^4.0.0" -"@docusaurus/core@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.17.tgz#f631aae04405de42a428a31928998242cd1d7b77" - integrity sha512-iNdW7CsmHNOgc4PxD9BFxa+MD8+i7ln7erOBkF3FSMMPnsKUeVqsR3rr31aLmLZRlTXMITSPLxlXwtBZa3KPCw== +"@docusaurus/core@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.18.tgz#44c6eefe29257462df630640a35f0c86bd80639a" + integrity sha512-puV7l+0/BPSi07Xmr8tVktfs1BzhC8P5pm6Bs2CfvysCJ4nefNCD1CosPc1PGBWy901KqeeEJ1aoGwj9tU3AUA== dependencies: - "@babel/core" "^7.17.5" - "@babel/generator" "^7.17.3" + "@babel/core" "^7.17.8" + "@babel/generator" "^7.17.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-transform-runtime" "^7.17.0" "@babel/preset-env" "^7.16.11" "@babel/preset-react" "^7.16.7" "@babel/preset-typescript" "^7.16.7" - "@babel/runtime" "^7.17.2" - "@babel/runtime-corejs3" "^7.17.2" + "@babel/runtime" "^7.17.8" + "@babel/runtime-corejs3" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/cssnano-preset" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" + "@docusaurus/cssnano-preset" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - "@slorber/static-site-generator-webpack-plugin" "^4.0.1" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + "@slorber/static-site-generator-webpack-plugin" "^4.0.4" "@svgr/webpack" "^6.2.1" - autoprefixer "^10.4.2" - babel-loader "^8.2.3" + autoprefixer "^10.4.4" + babel-loader "^8.2.4" babel-plugin-dynamic-import-node "2.3.0" boxen "^6.2.1" chokidar "^3.5.3" @@ -1229,9 +1229,9 @@ commander "^5.1.0" copy-webpack-plugin "^10.2.4" core-js "^3.21.1" - css-loader "^6.6.0" + css-loader "^6.7.1" css-minimizer-webpack-plugin "^3.4.1" - cssnano "^5.0.17" + cssnano "^5.1.5" del "^6.0.0" detect-port "^1.3.0" escape-html "^1.0.3" @@ -1245,9 +1245,9 @@ is-root "^2.1.0" leven "^3.1.0" lodash "^4.17.21" - mini-css-extract-plugin "^2.5.3" + mini-css-extract-plugin "^2.6.0" nprogress "^0.2.0" - postcss "^8.4.7" + postcss "^8.4.12" postcss-loader "^6.2.1" prompts "^2.4.2" react-dev-utils "^12.0.0" @@ -1259,7 +1259,7 @@ react-router-dom "^5.2.0" remark-admonitions "^1.2.1" rtl-detect "^1.0.4" - semver "^7.3.4" + semver "^7.3.5" serve-handler "^6.1.3" shelljs "^0.8.5" terser-webpack-plugin "^5.3.1" @@ -1267,38 +1267,38 @@ update-notifier "^5.1.0" url-loader "^4.1.1" wait-on "^6.0.1" - webpack "^5.69.1" + webpack "^5.70.0" webpack-bundle-analyzer "^4.5.0" webpack-dev-server "^4.7.4" webpack-merge "^5.8.0" webpackbar "^5.0.2" -"@docusaurus/cssnano-preset@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.17.tgz#f687bc6e5c8cb2139a7830dec757cfcb92dbb681" - integrity sha512-DoBwtLjJ9IY9/lNMHIEdo90L4NDayvU28nLgtjR2Sc6aBIMEB/3a5Ndjehnp+jZAkwcDdNASA86EkZVUyz1O1A== +"@docusaurus/cssnano-preset@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.18.tgz#235ac9064fe8f8da618349ce5305be3ed3a44e29" + integrity sha512-VxhYmpyx16Wv00W9TUfLVv0NgEK/BwP7pOdWoaiELEIAMV7SO1+6iB8gsFUhtfKZ31I4uPVLMKrCyWWakoFeFA== dependencies: - cssnano-preset-advanced "^5.1.12" - postcss "^8.4.7" + cssnano-preset-advanced "^5.3.1" + postcss "^8.4.12" postcss-sort-media-queries "^4.2.1" -"@docusaurus/logger@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.17.tgz#89c5ace3b4efd5274adb0d8919328892c4466d02" - integrity sha512-F9JDl06/VLg+ylsvnq9NpILSUeWtl0j4H2LtlLzX5gufEL4dGiCMlnUzYdHl7FSHSzYJ0A/R7vu0SYofsexC4w== +"@docusaurus/logger@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.0.0-beta.18.tgz#12302f312a083eb018caa28505b63f5dd4ab6a91" + integrity sha512-frNe5vhH3mbPmH980Lvzaz45+n1PQl3TkslzWYXQeJOkFX17zUd3e3U7F9kR1+DocmAqHkgAoWuXVcvEoN29fg== dependencies: chalk "^4.1.2" tslib "^2.3.1" -"@docusaurus/mdx-loader@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.17.tgz#838f87f4cbf12701c4d8eb11e4f9698fb7155bf8" - integrity sha512-AhJ3GWRmjQYCyINHE595pff5tn3Rt83oGpdev5UT9uvG9lPYPC8nEmh1LI6c0ogfw7YkNznzxWSW4hyyVbYQ3A== +"@docusaurus/mdx-loader@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.18.tgz#4a9fc0607e0a210a7d7db3108415208dd36e33d3" + integrity sha512-pOmAQM4Y1jhuZTbEhjh4ilQa74Mh6Q0pMZn1xgIuyYDdqvIOrOlM/H0i34YBn3+WYuwsGim4/X0qynJMLDUA4A== dependencies: - "@babel/parser" "^7.17.3" + "@babel/parser" "^7.17.8" "@babel/traverse" "^7.17.3" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" "@mdx-js/mdx" "^1.6.22" escape-html "^1.0.3" file-loader "^6.2.0" @@ -1310,30 +1310,30 @@ tslib "^2.3.1" unist-util-visit "^2.0.2" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/module-type-aliases@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.17.tgz#73f6d34be202ac093e78769ff72613d353087cd7" - integrity sha512-Tu+8geC/wyygBudbSwvWIHEvt5RwyA7dEoE1JmPbgQtmqUxOZ9bgnfemwXpJW5mKuDiJASbN4of1DhbLqf4sPg== +"@docusaurus/module-type-aliases@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.0.0-beta.18.tgz#001379229c58cbc3ed565e19437cbda86d5e8742" + integrity sha512-e6mples8FZRyT7QyqidGS6BgkROjM+gljJsdOqoctbtBp+SZ5YDjwRHOmoY7eqEfsQNOaFZvT2hK38ui87hCRA== dependencies: - "@docusaurus/types" "2.0.0-beta.17" + "@docusaurus/types" "2.0.0-beta.18" "@types/react" "*" "@types/react-router-config" "*" "@types/react-router-dom" "*" react-helmet-async "*" -"@docusaurus/plugin-content-blog@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.17.tgz#1d1063bfda78a80d517694567b965d5c3a70479f" - integrity sha512-gcX4UR+WKT4bhF8FICBQHy+ESS9iRMeaglSboTZbA/YHGax/3EuZtcPU3dU4E/HFJeZ866wgUdbLKpIpsZOidg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/plugin-content-blog@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.18.tgz#95fe3dfc8bae9bf153c65a3a441234c450cbac0a" + integrity sha512-qzK83DgB+mxklk3PQC2nuTGPQD/8ogw1nXSmaQpyXAyhzcz4CXAZ9Swl/Ee9A/bvPwQGnSHSP3xqIYl8OkFtfw== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" cheerio "^1.0.0-rc.10" feed "^4.2.2" fs-extra "^10.0.1" @@ -1342,18 +1342,18 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" - -"@docusaurus/plugin-content-docs@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.17.tgz#97f13bb458e165224db6867836e8e9637ea15921" - integrity sha512-YYrBpuRfTfE6NtENrpSHTJ7K7PZifn6j6hcuvdC0QKE+WD8pS+O2/Ws30yoyvHwLnAnfhvaderh1v9Kaa0/ANg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + webpack "^5.70.0" + +"@docusaurus/plugin-content-docs@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.18.tgz#fef52d945da2928e0f4f3f9a9384d9ee7f2d4288" + integrity sha512-z4LFGBJuzn4XQiUA7OEA2SZTqlp+IYVjd3NrCk/ZUfNi1tsTJS36ATkk9Y6d0Nsp7K2kRXqaXPsz4adDgeIU+Q== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" combine-promises "^1.1.0" fs-extra "^10.0.1" import-fresh "^3.3.0" @@ -1362,80 +1362,80 @@ remark-admonitions "^1.2.1" tslib "^2.3.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-content-pages@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.17.tgz#d5955d3cc23722518a6032f830cf8c7b7aeb3d5a" - integrity sha512-d5x0mXTMJ44ojRQccmLyshYoamFOep2AnBe69osCDnwWMbD3Or3pnc2KMK9N7mVpQFnNFKbHNCLrX3Rv0uwEHA== +"@docusaurus/plugin-content-pages@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.18.tgz#0fef392be3fea3d85c212caf4eb744ead920c30b" + integrity sha512-CJ2Xeb9hQrMeF4DGywSDVX2TFKsQpc8ZA7czyeBAAbSFsoRyxXPYeSh8aWljqR4F1u/EKGSKy0Shk/D4wumaHw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/mdx-loader" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/mdx-loader" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" remark-admonitions "^1.2.1" tslib "^2.3.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@docusaurus/plugin-debug@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.17.tgz#0185dfd5575aa940443d2cb9fab4bed3308ed3a1" - integrity sha512-p26fjYFRSC0esEmKo/kRrLVwXoFnzPCFDumwrImhPyqfVxbj+IKFaiXkayb2qHnyEGE/1KSDIgRF4CHt/pyhiw== +"@docusaurus/plugin-debug@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.18.tgz#d4582532e59b538a23398f7c444b005367efa922" + integrity sha512-inLnLERgG7q0WlVmK6nYGHwVqREz13ivkynmNygEibJZToFRdgnIPW+OwD8QzgC5MpQTJw7+uYjcitpBumy1Gw== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" fs-extra "^10.0.1" react-json-view "^1.21.3" tslib "^2.3.1" -"@docusaurus/plugin-google-analytics@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.17.tgz#31ca1ef88f0f7874c6e12c642d64abe694494720" - integrity sha512-jvgYIhggYD1W2jymqQVAAyjPJUV1xMCn70bAzaCMxriureMWzhQ/kQMVQpop0ijTMvifOxaV9yTcL1VRXev++A== +"@docusaurus/plugin-google-analytics@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.18.tgz#a9b1659abb3f588e866aaa742ec4c82fe943eda3" + integrity sha512-s9dRBWDrZ1uu3wFXPCF7yVLo/+5LUFAeoxpXxzory8gn9GYDt8ZDj80h5DUyCLxiy72OG6bXWNOYS/Vc6cOPXQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-google-gtag@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.17.tgz#e6baf8f03cea756ed2259a5356fa689388bc303d" - integrity sha512-1pnWHtIk1Jfeqwvr8PlcPE5SODWT1gW4TI+ptmJbJ296FjjyvL/pG0AcGEJmYLY/OQc3oz0VQ0W2ognw9jmFIw== +"@docusaurus/plugin-google-gtag@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.18.tgz#b51611ac01915523ddcfc9732f7862cf4996a0e1" + integrity sha512-h7vPuLVo/9pHmbFcvb4tCpjg4SxxX4k+nfVDyippR254FM++Z/nA5pRB0WvvIJ3ZTe0ioOb5Wlx2xdzJIBHUNg== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" tslib "^2.3.1" -"@docusaurus/plugin-sitemap@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.17.tgz#e1aa67ff09d9145e8e5522c4541bbcdd6365560c" - integrity sha512-19/PaGCsap6cjUPZPGs87yV9e1hAIyd0CTSeVV6Caega8nmOKk20FTrQGFJjZPeX8jvD9QIXcdg6BJnPxcKkaQ== +"@docusaurus/plugin-sitemap@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.18.tgz#7e8217e95bede5719bd02265dcf7eb2fea76b675" + integrity sha512-Klonht0Ye3FivdBpS80hkVYNOH+8lL/1rbCPEV92rKhwYdwnIejqhdKct4tUTCl8TYwWiyeUFQqobC/5FNVZPQ== dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" fs-extra "^10.0.1" sitemap "^7.1.1" tslib "^2.3.1" -"@docusaurus/preset-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.17.tgz#a8fc3447aa6fe0e5f259d894cc8dd64c049c7605" - integrity sha512-7YUxPEgM09aZWr25/hpDEp1gPl+1KsCPV1ZTRW43sbQ9TinPm+9AKR3rHVDa8ea8MdiS7BpqCVyK+H/eiyQrUw== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/plugin-debug" "2.0.0-beta.17" - "@docusaurus/plugin-google-analytics" "2.0.0-beta.17" - "@docusaurus/plugin-google-gtag" "2.0.0-beta.17" - "@docusaurus/plugin-sitemap" "2.0.0-beta.17" - "@docusaurus/theme-classic" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-search-algolia" "2.0.0-beta.17" +"@docusaurus/preset-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.18.tgz#82f6905d34a13e46289ac4d2f1125e47033bd9d8" + integrity sha512-TfDulvFt/vLWr/Yy7O0yXgwHtJhdkZ739bTlFNwEkRMAy8ggi650e52I1I0T79s67llecb4JihgHPW+mwiVkCQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/plugin-debug" "2.0.0-beta.18" + "@docusaurus/plugin-google-analytics" "2.0.0-beta.18" + "@docusaurus/plugin-google-gtag" "2.0.0-beta.18" + "@docusaurus/plugin-sitemap" "2.0.0-beta.18" + "@docusaurus/theme-classic" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-search-algolia" "2.0.0-beta.18" "@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": version "5.5.2" @@ -1445,60 +1445,61 @@ "@types/react" "*" prop-types "^15.6.2" -"@docusaurus/theme-classic@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.17.tgz#1f7a1dd714993819f266ce422d06dd4533d4ab3a" - integrity sha512-xfZ9kpgqo0lP9YO4rJj79wtiQJXU6ARo5wYy10IIwiWN+lg00scJHhkmNV431b05xIUjUr0cKeH9nqZmEsQRKg== - dependencies: - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-common" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" +"@docusaurus/theme-classic@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.18.tgz#a3632e83923ed4372f80999128375cd0b378d3f8" + integrity sha512-WJWofvSGKC4Luidk0lyUwkLnO3DDynBBHwmt4QrV+aAVWWSOHUjA2mPOF6GLGuzkZd3KfL9EvAfsU0aGE1Hh5g== + dependencies: + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-common" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" "@mdx-js/react" "^1.6.22" clsx "^1.1.1" copy-text-to-clipboard "^3.0.1" - infima "0.2.0-alpha.37" + infima "0.2.0-alpha.38" lodash "^4.17.21" - postcss "^8.4.7" - prism-react-renderer "^1.2.1" + postcss "^8.4.12" + prism-react-renderer "^1.3.1" prismjs "^1.27.0" react-router-dom "^5.2.0" - rtlcss "^3.3.0" + rtlcss "^3.5.0" -"@docusaurus/theme-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.17.tgz#3b71bb8b0973a0cee969a1bb76794c81d597f290" - integrity sha512-LJBDhx+Qexn1JHBqZbE4k+7lBaV1LgpE33enXf43ShB7ebhC91d5HLHhBwgt0pih4+elZU4rG+BG/roAmsNM0g== +"@docusaurus/theme-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.18.tgz#abf74f82c37d2ce813f92447cb020831290059fb" + integrity sha512-3pI2Q6ttScDVTDbuUKAx+TdC8wmwZ2hfWk8cyXxksvC9bBHcyzXhSgcK8LTsszn2aANyZ3e3QY2eNSOikTFyng== dependencies: - "@docusaurus/module-type-aliases" "2.0.0-beta.17" - "@docusaurus/plugin-content-blog" "2.0.0-beta.17" - "@docusaurus/plugin-content-docs" "2.0.0-beta.17" - "@docusaurus/plugin-content-pages" "2.0.0-beta.17" + "@docusaurus/module-type-aliases" "2.0.0-beta.18" + "@docusaurus/plugin-content-blog" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/plugin-content-pages" "2.0.0-beta.18" clsx "^1.1.1" parse-numeric-range "^1.3.0" prism-react-renderer "^1.3.1" tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-search-algolia@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.17.tgz#880fb965b71e5aa7f01d456a1a2aa8eb6c244082" - integrity sha512-W12XKM7QC5Jmrec359bJ7aDp5U8DNkCxjVKsMNIs8rDunBoI/N+R35ERJ0N7Bg9ONAWO6o7VkUERQsfGqdvr9w== +"@docusaurus/theme-search-algolia@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.18.tgz#cbdda8982deac4556848e04853b7f32d93886c02" + integrity sha512-2w97KO/gnjI49WVtYQqENpQ8iO1Sem0yaTxw7/qv/ndlmIAQD0syU4yx6GsA7bTQCOGwKOWWzZSetCgUmTnWgA== dependencies: "@docsearch/react" "^3.0.0" - "@docusaurus/core" "2.0.0-beta.17" - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/theme-common" "2.0.0-beta.17" - "@docusaurus/theme-translations" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" - "@docusaurus/utils-validation" "2.0.0-beta.17" - algoliasearch "^4.12.1" - algoliasearch-helper "^3.7.0" + "@docusaurus/core" "2.0.0-beta.18" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/plugin-content-docs" "2.0.0-beta.18" + "@docusaurus/theme-common" "2.0.0-beta.18" + "@docusaurus/theme-translations" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" + "@docusaurus/utils-validation" "2.0.0-beta.18" + algoliasearch "^4.13.0" + algoliasearch-helper "^3.7.4" clsx "^1.1.1" eta "^1.12.3" fs-extra "^10.0.1" @@ -1506,74 +1507,74 @@ tslib "^2.3.1" utility-types "^3.10.0" -"@docusaurus/theme-translations@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.17.tgz#a4b84fa63befc11847da471922387aa3eb4e5626" - integrity sha512-oxCX6khjZH3lgdRCL0DH06KkUM/kDr9+lzB35+vY8rpFeQruVgRdi8ekPqG3+Wr0U/N+LMhcYE5BmCb6D0Fv2A== +"@docusaurus/theme-translations@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.18.tgz#292699ce89b013262683faf7f4ee7b75a8745a79" + integrity sha512-1uTEUXlKC9nco1Lx9H5eOwzB+LP4yXJG5wfv1PMLE++kJEdZ40IVorlUi3nJnaa9/lJNq5vFvvUDrmeNWsxy/Q== dependencies: fs-extra "^10.0.1" tslib "^2.3.1" -"@docusaurus/types@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.17.tgz#582e3d961ce4409ed17454669b3f6a7a9f696cdd" - integrity sha512-4o7TXu5sKlQpybfFFtsGUElBXwSpiXKsQyyWaRKj7DRBkvMtkDX6ITZNnZO9+EHfLbP/cfrokB8C/oO7mCQ5BQ== +"@docusaurus/types@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.18.tgz#9446928a6b751eefde390420b39eac32ba26abb2" + integrity sha512-zkuSmPQYP3+z4IjGHlW0nGzSSpY7Sit0Nciu/66zSb5m07TK72t6T1MlpCAn/XijcB9Cq6nenC3kJh66nGsKYg== dependencies: commander "^5.1.0" joi "^17.6.0" - querystring "0.2.1" utility-types "^3.10.0" - webpack "^5.69.1" + webpack "^5.70.0" webpack-merge "^5.8.0" -"@docusaurus/utils-common@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.17.tgz#cefd950a7722f5f702690b4de27ea19fd65f3364" - integrity sha512-90WCVdj6zYzs7neEIS594qfLO78cUL6EVK1CsRHJgVkkGjcYlCQ1NwkyO7bOb+nIAwdJrPJRc2FBSpuEGxPD3w== +"@docusaurus/utils-common@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.18.tgz#46cf0bed2a7c532b2b85eab5bb914ff118b2c4e9" + integrity sha512-pK83EcOIiKCLGhrTwukZMo5jqd1sqqqhQwOVyxyvg+x9SY/lsnNzScA96OEfm+qQLBwK1OABA7Xc1wfkgkUxvw== dependencies: tslib "^2.3.1" -"@docusaurus/utils-validation@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.17.tgz#d7dbfc1a29768c37c0d8a6af85eb1bdfef7656df" - integrity sha512-5UjayUP16fDjgd52eSEhL7SlN9x60pIhyS+K7kt7RmpSLy42+4/bSr2pns2VlATmuaoNOO6iIFdB2jgSYJ6SGA== +"@docusaurus/utils-validation@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.18.tgz#0dabf113d2c53ee685a715cd4caae6e219e9e41e" + integrity sha512-3aDrXjJJ8Cw2MAYEk5JMNnr8UHPxmVNbPU/PIHFWmWK09nJvs3IQ8nc9+8I30aIjRdIyc/BIOCxgvAcJ4hsxTA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@docusaurus/utils" "2.0.0-beta.17" + "@docusaurus/logger" "2.0.0-beta.18" + "@docusaurus/utils" "2.0.0-beta.18" joi "^17.6.0" + js-yaml "^4.1.0" tslib "^2.3.1" -"@docusaurus/utils@2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.17.tgz#6a696e2ec5e50b2271f2d26d31562e9f3e2bc559" - integrity sha512-yRKGdzSc5v6M/6GyQ4omkrAHCleevwKYiIrufCJgRbOtkhYE574d8mIjjirOuA/emcyLxjh+TLtqAA5TwhIryA== +"@docusaurus/utils@2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.18.tgz#c3fe0e9fac30db4510962263993fd0ee2679eebb" + integrity sha512-v2vBmH7xSbPwx3+GB90HgLSQdj+Rh5ELtZWy7M20w907k0ROzDmPQ/8Ke2DK3o5r4pZPGnCrsB3SaYI83AEmAA== dependencies: - "@docusaurus/logger" "2.0.0-beta.17" - "@svgr/webpack" "^6.0.0" + "@docusaurus/logger" "2.0.0-beta.18" + "@svgr/webpack" "^6.2.1" file-loader "^6.2.0" fs-extra "^10.0.1" github-slugger "^1.4.0" - globby "^11.0.4" + globby "^11.1.0" gray-matter "^4.0.3" js-yaml "^4.1.0" lodash "^4.17.21" - micromatch "^4.0.4" + micromatch "^4.0.5" resolve-pathname "^3.0.0" shelljs "^0.8.5" tslib "^2.3.1" url-loader "^4.1.1" - webpack "^5.69.1" + webpack "^5.70.0" -"@eslint/eslintrc@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" - integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== +"@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== dependencies: ajv "^6.12.4" debug "^4.3.2" espree "^9.3.1" globals "^13.9.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.0.4" @@ -1685,9 +1686,9 @@ integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== "@sideway/address@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" - integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== dependencies: "@hapi/hoek" "^9.0.0" @@ -1706,15 +1707,14 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@slorber/static-site-generator-webpack-plugin@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" - integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== +"@slorber/static-site-generator-webpack-plugin@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.4.tgz#2bf4a2545e027830d2aa5eb950437c26a289b0f1" + integrity sha512-FvMavoWEIePps6/JwGCOLYKCRhuwIHhMtmbKpBFgzNkxwpa/569LfTkrbRk1m1I3n+ezJK4on9E1A6cjuZmD9g== dependencies: bluebird "^3.7.1" cheerio "^0.22.0" - eval "^0.1.4" - url "^0.11.0" + eval "^0.1.8" webpack-sources "^1.4.3" "@svgr/babel-plugin-add-jsx-attribute@^6.0.0": @@ -1807,7 +1807,7 @@ deepmerge "^4.2.2" svgo "^2.5.0" -"@svgr/webpack@^6.0.0", "@svgr/webpack@^6.2.1": +"@svgr/webpack@^6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== @@ -1928,9 +1928,9 @@ "@types/node" "*" "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": version "0.0.29" @@ -1955,9 +1955,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*", "@types/node@^17.0.5": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2016,9 +2016,9 @@ "@types/react" "*" "@types/react@*": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2069,9 +2069,9 @@ integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== "@types/ws@^8.2.2": - version "8.5.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.2.tgz#77e0c2e360e9579da930ffcfa53c5975ea3bdd26" - integrity sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw== + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== dependencies: "@types/node" "*" @@ -2277,41 +2277,41 @@ ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" uri-js "^4.2.2" -algoliasearch-helper@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz#c0a0493df84d850360f664ad7a9d4fc78a94fd78" - integrity sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w== +algoliasearch-helper@^3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.4.tgz#3812ea161da52463ec88da52612c9a363c1b181d" + integrity sha512-KmJrsHVm5TmxZ9Oj53XdXuM4CQeu7eVFnB15tpSFt+7is1d1yVCv3hxCLMqYSw/rH42ccv013miQpRr268P8vw== dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.0.0, algoliasearch@^4.12.1: - version "4.12.2" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.2.tgz#d7672a15b8fd1b261d9ae193535b68bcb189cfd2" - integrity sha512-bn1P9+V415zeDQJtXn+1SwuwedEAv9/LJAxt8XwR6ygH/sMwaHSm2hpkz8wIbCBt/tKQ43TL672Kyxzv5PwGgQ== - dependencies: - "@algolia/cache-browser-local-storage" "4.12.2" - "@algolia/cache-common" "4.12.2" - "@algolia/cache-in-memory" "4.12.2" - "@algolia/client-account" "4.12.2" - "@algolia/client-analytics" "4.12.2" - "@algolia/client-common" "4.12.2" - "@algolia/client-personalization" "4.12.2" - "@algolia/client-search" "4.12.2" - "@algolia/logger-common" "4.12.2" - "@algolia/logger-console" "4.12.2" - "@algolia/requester-browser-xhr" "4.12.2" - "@algolia/requester-common" "4.12.2" - "@algolia/requester-node-http" "4.12.2" - "@algolia/transporter" "4.12.2" +algoliasearch@^4.0.0, algoliasearch@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.13.0.tgz#e36611fda82b1fc548c156ae7929a7f486e4b663" + integrity sha512-oHv4faI1Vl2s+YC0YquwkK/TsaJs79g2JFg5FDm2rKN12VItPTAeQ7hyJMHarOPPYuCnNC5kixbtcqvb21wchw== + dependencies: + "@algolia/cache-browser-local-storage" "4.13.0" + "@algolia/cache-common" "4.13.0" + "@algolia/cache-in-memory" "4.13.0" + "@algolia/client-account" "4.13.0" + "@algolia/client-analytics" "4.13.0" + "@algolia/client-common" "4.13.0" + "@algolia/client-personalization" "4.13.0" + "@algolia/client-search" "4.13.0" + "@algolia/logger-common" "4.13.0" + "@algolia/logger-console" "4.13.0" + "@algolia/requester-browser-xhr" "4.13.0" + "@algolia/requester-common" "4.13.0" + "@algolia/requester-node-http" "4.13.0" + "@algolia/transporter" "4.13.0" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -2468,14 +2468,14 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.3.7, autoprefixer@^10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" - integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== +autoprefixer@^10.3.7, autoprefixer@^10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: - browserslist "^4.19.1" - caniuse-lite "^1.0.30001297" - fraction.js "^4.1.2" + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" @@ -2497,13 +2497,13 @@ axobject-query@^2.2.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== -babel-loader@^8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@^8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -2669,20 +2669,20 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1: - version "4.19.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.3.tgz#29b7caad327ecf2859485f696f9604214bedd383" - integrity sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== dependencies: - caniuse-lite "^1.0.30001312" - electron-to-chromium "^1.4.71" + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" escalade "^3.1.1" node-releases "^2.0.2" picocolors "^1.0.0" @@ -2775,10 +2775,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001312: - version "1.0.30001312" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== ccount@^1.0.0, ccount@^1.0.3: version "1.1.0" @@ -3207,13 +3207,13 @@ css-functions-list@^3.0.1: resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.0.1.tgz#1460df7fb584d1692c30b105151dbb988c8094f9" integrity sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw== -css-loader@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3" - integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg== +css-loader@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" + integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== dependencies: icss-utils "^5.1.0" - postcss "^8.4.5" + postcss "^8.4.7" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" @@ -3277,37 +3277,37 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.1.12: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.2.0.tgz#fc87b7c7327b61306e3e707e2f0fda3fa468f713" - integrity sha512-E7jJoKc2GjZsRLm8wQd2wZa+1a6tslA1elimwpcJTnH6dBQBkjQ8tAwNWUeyT72owYcCNGWTnar60bTnrnEWzw== +cssnano-preset-advanced@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.1.tgz#f4fa7006aab67e354289b3efd512c93a272b3874" + integrity sha512-kfCknalY5VX/JKJ3Iri5/5rhZmQIqkbqgXsA6oaTnfA4flY/tt+w0hMxbExr0/fVuJL8w56j211op+pkQoNzoQ== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" postcss-discard-unused "^5.1.0" - postcss-merge-idents "^5.1.0" - postcss-reduce-idents "^5.1.0" + postcss-merge-idents "^5.1.1" + postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.0.tgz#2579d38b9217746f2cf9f938954a91e00418ded6" - integrity sha512-3N5Vcptj2pqVKpHVqH6ezOJvqikR2PdLTbTrsrhF61FbLRQuujAqZ2sKN5rvcMsb7hFjrNnjZT8CGEkxoN/Pwg== +cssnano-preset-default@^5.2.5: + version "5.2.5" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" + integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== dependencies: css-declaration-sorter "^6.0.3" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" postcss-colormin "^5.3.0" postcss-convert-values "^5.1.0" - postcss-discard-comments "^5.1.0" + postcss-discard-comments "^5.1.1" postcss-discard-duplicates "^5.1.0" - postcss-discard-empty "^5.1.0" + postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.0" - postcss-merge-rules "^5.1.0" + postcss-merge-longhand "^5.1.3" + postcss-merge-rules "^5.1.1" postcss-minify-font-values "^5.1.0" - postcss-minify-gradients "^5.1.0" - postcss-minify-params "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.2" postcss-minify-selectors "^5.2.0" postcss-normalize-charset "^5.1.0" postcss-normalize-display-values "^5.1.0" @@ -3317,24 +3317,24 @@ cssnano-preset-default@^5.2.0: postcss-normalize-timing-functions "^5.1.0" postcss-normalize-unicode "^5.1.0" postcss-normalize-url "^5.1.0" - postcss-normalize-whitespace "^5.1.0" - postcss-ordered-values "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.1" postcss-reduce-initial "^5.1.0" postcss-reduce-transforms "^5.1.0" postcss-svgo "^5.1.0" - postcss-unique-selectors "^5.1.0" + postcss-unique-selectors "^5.1.1" cssnano-utils@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.17, cssnano@^5.0.6: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.0.tgz#cf977d660a5824d0d5542639ed1d4045afd84cbe" - integrity sha512-wWxave1wMlThGg4ueK98jFKaNqXnQd1nVZpSkQ9XvR+YymlzP1ofWqES1JkHtI250LksP9z5JH+oDcrKDJezAg== +cssnano@^5.0.6, cssnano@^5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" + integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== dependencies: - cssnano-preset-default "^5.2.0" + cssnano-preset-default "^5.2.5" lilconfig "^2.0.3" yaml "^1.10.2" @@ -3369,10 +3369,10 @@ debug@^3.1.1, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -3590,9 +3590,9 @@ domhandler@^2.3.0: domelementtype "1" domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" @@ -3656,10 +3656,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.4.71: - version "1.4.75" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz#d1ad9bb46f2f1bf432118c2be21d27ffeae82fdd" - integrity sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q== +electron-to-chromium@^1.4.84: + version "1.4.93" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.93.tgz#2e87ac28721cb31d472ec2bd04f7daf9f2e13de2" + integrity sha512-ywq9Pc5Gwwpv7NG767CtoU8xF3aAUQJjH9//Wy3MBCg4w5JSLbJUq2L8IsCdzPMjvSgxuue9WcVaTOyyxCL0aQ== emoji-regex@^8.0.0: version "8.0.0" @@ -3798,7 +3798,7 @@ eslint-config-airbnb-base@^15.0.0: object.entries "^1.1.5" semver "^6.3.0" -eslint-config-airbnb@^19.0.0: +eslint-config-airbnb@^19.0.4: version "19.0.4" resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz#84d4c3490ad70a0ffa571138ebcdea6ab085fdc3" integrity sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew== @@ -3807,7 +3807,7 @@ eslint-config-airbnb@^19.0.0: object.assign "^4.1.2" object.entries "^1.1.5" -eslint-config-prettier@^8.4.0: +eslint-config-prettier@^8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== @@ -3833,7 +3833,7 @@ eslint-plugin-header@^3.1.1: resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6" integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg== -eslint-plugin-import@^2.25.3: +eslint-plugin-import@^2.25.4: version "2.25.4" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== @@ -3875,10 +3875,10 @@ eslint-plugin-react-hooks@^4.3.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== -eslint-plugin-react@^7.29.2: - version "7.29.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.2.tgz#2d4da69d30d0a736efd30890dc6826f3e91f3f7c" - integrity sha512-ypEBTKOy5liFQXZWMchJ3LN0JX1uPI6n7MN7OPHKacqXAxq5gYC30TdO7wqGYQyxD1OrzpobdHC3hDmlRWDg9w== +eslint-plugin-react@^7.29.4: + version "7.29.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: array-includes "^3.1.4" array.prototype.flatmap "^1.2.5" @@ -3928,12 +3928,12 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" - integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== +eslint@^8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" + integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== dependencies: - "@eslint/eslintrc" "^1.2.0" + "@eslint/eslintrc" "^1.2.1" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -4022,11 +4022,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eval@^0.1.4: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" - integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== +eval@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.8.tgz#2b903473b8cc1d1989b83a1e7923f883eb357f85" + integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== dependencies: + "@types/node" "*" require-like ">= 0.1.1" eventemitter3@^4.0.0: @@ -4322,10 +4323,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.3.tgz#be65b0f20762ef27e1e793860bc2dfb716e99e65" - integrity sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg== +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== fresh@0.5.2: version "0.5.2" @@ -4492,9 +4493,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.12.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.1.tgz#ec206be932e6c77236677127577aa8e50bf1c5cb" - integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw== + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== dependencies: type-fest "^0.20.2" @@ -4591,7 +4592,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1, has-symbols@^1.0.2: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -4843,14 +4844,14 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" - integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== + version "0.5.6" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" + integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== http-proxy-middleware@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz#5df04f69a89f530c2284cd71eeaa51ba52243289" - integrity sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA== + version "2.0.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz#03af0f4676d172ae775cb5c33f592f40e1a4e07a" + integrity sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg== dependencies: "@types/http-proxy" "^1.17.8" http-proxy "^1.18.1" @@ -4884,11 +4885,6 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.1.9, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" @@ -4934,10 +4930,10 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infima@0.2.0-alpha.37: - version "0.2.0-alpha.37" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.37.tgz#b87ff42d528d6d050098a560f0294fbdd12adb78" - integrity sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q== +infima@0.2.0-alpha.38: + version "0.2.0-alpha.38" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.38.tgz#e41d95c7cd82756549b17df12f613fed4af3d528" + integrity sha512-1WsmqSMI5IqzrUx3goq+miJznHBonbE3aoqZ1AR/i/oHhroxNeSV6Awv5VoVfXBhfTzLSnxkHaRI2qpAMYcCzw== inflight@^1.0.4: version "1.0.6" @@ -5390,11 +5386,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^6.0.1: version "6.1.0" @@ -5473,9 +5467,9 @@ levn@^0.4.1: type-check "~0.4.0" lilconfig@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== lines-and-columns@^1.1.6: version "1.2.4" @@ -5487,15 +5481,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" @@ -5786,20 +5771,15 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + braces "^3.0.2" + picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2": +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5817,11 +5797,11 @@ mime-types@2.1.18: mime-db "~1.33.0" mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.51.0" + mime-db "1.52.0" mime@1.6.0: version "1.6.0" @@ -5851,10 +5831,10 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@^2.5.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9" - integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw== +mini-css-extract-plugin@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== dependencies: schema-utils "^4.0.0" @@ -5886,17 +5866,17 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" mrmime@^1.0.0: version "1.0.0" @@ -5974,9 +5954,9 @@ node-fetch@2.6.7: whatwg-url "^5.0.0" node-forge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" - integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" + integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== node-releases@^2.0.2: version "2.0.2" @@ -6397,7 +6377,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -6450,20 +6430,20 @@ postcss-convert-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-discard-comments@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.0.tgz#87be4e0953bf599935837b940c701f8d4eca7d0b" - integrity sha512-L0IKF4jAshRyn03SkEO6ar/Ipz2oLywVbg2THf2EqqdNkBwmVMxuTR/RoAltOw4piiaLt3gCAdrbAqmTBInmhg== +postcss-discard-comments@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" + integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== postcss-discard-duplicates@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.0.tgz#7f51b16cd1b89f8180bbc7cee34d6cbabf2ef810" - integrity sha512-782T/buGgb3HOuHOJAHpdyKzAAKsv/BxWqsutnZ+QsiHEcDkY7v+6WWdturuBiSal6XMOO1p1aJvwXdqLD5vhA== +postcss-discard-empty@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== postcss-discard-overridden@^5.1.0: version "5.1.0" @@ -6491,26 +6471,26 @@ postcss-media-query-parser@^0.2.3: resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= -postcss-merge-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.0.tgz#948e1183cd659cfb5f99c7389f5fcec83c8f9a00" - integrity sha512-l+awq6+uUiCILsHahWK5KE25495I4oCKlUrIA+EdBvklnVdWlBEsbkzq5+ouPKb8OAe4WwRBgFvaSq7f77FY+w== +postcss-merge-idents@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz#7753817c2e0b75d0853b56f78a89771e15ca04a1" + integrity sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.0.tgz#f716bffbf0bdfbde6ea78c36088e21559f8a0a95" - integrity sha512-Gr46srN2tsLD8fudKYoHO56RG0BLQ2nsBRnSZGY04eNBPwTeWa9KeHrbL3tOLAHyB2aliikycPH2TMJG1U+W6g== +postcss-merge-longhand@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" + integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== dependencies: postcss-value-parser "^4.2.0" stylehacks "^5.1.0" -postcss-merge-rules@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.0.tgz#a2d5117eba09c8686a5471d97bd9afcf30d1b41f" - integrity sha512-NecukEJovQ0mG7h7xV8wbYAkXGTO3MPKnXvuiXzOKcxoOodfTTKYjeo8TMhAswlSkjcPIBlnKbSFcTuVSDaPyQ== +postcss-merge-rules@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" + integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== dependencies: browserslist "^4.16.6" caniuse-api "^3.0.0" @@ -6524,19 +6504,19 @@ postcss-minify-font-values@^5.1.0: dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.0.tgz#de0260a67a13b7b321a8adc3150725f2c6612377" - integrity sha512-J/TMLklkONn3LuL8wCwfwU8zKC1hpS6VcxFkNUNjmVt53uKqrrykR3ov11mdUYyqVMEx67slMce0tE14cE4DTg== +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== dependencies: colord "^2.9.1" cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.0.tgz#e0b1f4e05cfd396682f612856485907e4064f25e" - integrity sha512-q67dcts4Hct6x8+JmhBgctHkbvUsqGIg2IItenjE63iZXMbhjr7AlVZkNnKtIGt/1Wsv7p/7YzeSII6Q+KPXRg== +postcss-minify-params@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" + integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== dependencies: browserslist "^4.16.6" cssnano-utils "^3.1.0" @@ -6633,25 +6613,25 @@ postcss-normalize-url@^5.1.0: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.0.tgz#aed8b4580c9ad6e8eac034177291187ea16a059c" - integrity sha512-7O1FanKaJkpWFyCghFzIkLhehujV/frGkdofGLwhg5upbLyGsSfiTcZAdSzoPsSUgyPCkBkNMeWR8yVgPdQybg== +postcss-normalize-whitespace@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.0.tgz#04ef429e0991b0292bc918b135cd4c038f7b889f" - integrity sha512-wU4Z4D4uOIH+BUKkYid36gGDJNQtkVJT7Twv8qH6UyfttbbJWyw4/xIPuVEkkCtQLAJ0EdsNSh8dlvqkXb49TA== +postcss-ordered-values@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" + integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== dependencies: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.1.0.tgz#386b65cf861a9045663bd349d572027ab138ca4a" - integrity sha512-2xDoPTzv98D/HFDrGTgVEBlcuS47wvua2oc4g2WoZdYPwzPWMWb2TCRruCyN7vbl+HAtVLGvEOMZIZb3wYgv7w== +postcss-reduce-idents@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" + integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" @@ -6703,10 +6683,10 @@ postcss-svgo@^5.1.0: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.0.tgz#70a945da1b0599d00f617222a44ba1d82a676694" - integrity sha512-LmUhgGobtpeVJJHuogzjLRwJlN7VH+BL5c9GKMVJSS/ejoyePZkXvNsYUtk//F6vKOGK86gfRS0xH7fXQSDtvA== +postcss-unique-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" + integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== dependencies: postcss-selector-parser "^6.0.5" @@ -6720,10 +6700,10 @@ postcss-zindex@^5.1.0: resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== -postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.5, postcss@^8.4.6, postcss@^8.4.7: - version "8.4.7" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.7.tgz#f99862069ec4541de386bf57f5660a6c7a0875a8" - integrity sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A== +postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: nanoid "^3.3.1" picocolors "^1.0.0" @@ -6739,10 +6719,10 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +prettier@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" + integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== pretty-error@^4.0.0: version "4.0.0" @@ -6757,7 +6737,7 @@ pretty-time@^1.1.0: resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== -prism-react-renderer@^1.2.1, prism-react-renderer@^1.3.1: +prism-react-renderer@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== @@ -6819,11 +6799,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -6851,16 +6826,6 @@ qs@6.9.7: resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystring@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -6955,7 +6920,7 @@ react-dev-utils@^12.0.0: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.1: +react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== @@ -7057,7 +7022,7 @@ react-textarea-autosize@^8.3.2: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react@^17.0.1: +react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== @@ -7164,7 +7129,7 @@ regenerator-transform@^0.14.2: dependencies: "@babel/runtime" "^7.8.4" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== @@ -7387,7 +7352,7 @@ rtl-detect@^1.0.4: resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== -rtlcss@^3.3.0: +rtlcss@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== @@ -7405,9 +7370,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== dependencies: tslib "^2.1.0" @@ -7848,17 +7813,17 @@ string-width@^5.0.1: strip-ansi "^7.0.1" string.prototype.matchall@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -7966,16 +7931,16 @@ stylehacks@^5.1.0: browserslist "^4.16.6" postcss-selector-parser "^6.0.4" -stylelint@^14.5.3: - version "14.5.3" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.5.3.tgz#103b6670128ba3dea69fe3a1a07c4a5d3e0e3450" - integrity sha512-omHETL+kGHR+fCXFK1SkZD/A+emCP9esggAdWEl8GPjTNeyRYj+H6uetRDcU+7E451zwWiUYGVAX+lApsAZgsQ== +stylelint@^14.6.0: + version "14.6.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.1.tgz#aff137b0254515fc36b91921d88a3eb2edc194bf" + integrity sha512-FfNdvZUZdzh9KDQxDnO7Opp+prKh8OQVuSW8S13cBtxrooCbm6J6royhUeb++53WPMt04VB+ZbOz/QmzAijs6Q== dependencies: balanced-match "^2.0.0" colord "^2.9.2" cosmiconfig "^7.0.1" css-functions-list "^3.0.1" - debug "^4.3.3" + debug "^4.3.4" execall "^2.0.0" fast-glob "^3.2.11" fastest-levenshtein "^1.0.12" @@ -7996,7 +7961,7 @@ stylelint@^14.5.3: normalize-path "^3.0.0" normalize-selector "^0.2.0" picocolors "^1.0.0" - postcss "^8.4.6" + postcss "^8.4.12" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^6.0.0" @@ -8103,9 +8068,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.1: terser "^5.7.2" terser@^5.10.0, terser@^5.7.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" - integrity sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A== + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== dependencies: acorn "^8.5.0" commander "^2.20.0" @@ -8190,13 +8155,13 @@ trough@^1.0.0: integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== tsconfig-paths@^3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1: @@ -8232,9 +8197,9 @@ type-fest@^0.8.1: integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^2.5.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.0.tgz#ce342f58cab9114912f54b493d60ab39c3fc82b6" - integrity sha512-Qe5GRT+n/4GoqCNGGVp5Snapg1Omq3V7irBJB3EaKsp7HWDo5Gv2d/67gfNyV+d5EXD+x/RF5l1h4yJ7qNkcGA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" + integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== type-is@~1.6.18: version "1.6.18" @@ -8438,14 +8403,6 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use-composed-ref@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" @@ -8653,7 +8610,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.69.1: +webpack@^5.70.0: version "5.70.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== From 2dea99b5c85b55317ba1ded069b86af56dec55e3 Mon Sep 17 00:00:00 2001 From: Indermohan Singh <indermohansinghk7@gmail.com> Date: Fri, 25 Mar 2022 16:59:13 +0100 Subject: [PATCH 073/405] docs: remove unnecessary semicolon (#7000) * docs: remove unnecessary semicolon The semicolon after the TOCInline component is unnecessary and actually gets rendered on screen. * ignore prettier Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../markdown-features/markdown-features-inline-toc.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx b/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx index 8369a133184d..09e78d7447ac 100644 --- a/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx +++ b/website/docs/guides/markdown-features/markdown-features-inline-toc.mdx @@ -13,10 +13,11 @@ Each Markdown document displays a table of contents on the top-right corner. But The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components. +<!-- prettier-ignore --> ```jsx import TOCInline from '@theme/TOCInline'; -<TOCInline toc={toc} />; +<TOCInline toc={toc} /> ``` ```mdx-code-block @@ -41,6 +42,7 @@ type TOCItem = { Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. +<!-- prettier-ignore --> ```jsx import TOCInline from '@theme/TOCInline'; @@ -50,7 +52,7 @@ import TOCInline from '@theme/TOCInline'; minHeadingLevel={2} // Show h4 headings in addition to the default h2 and h3 headings maxHeadingLevel={4} -/>; +/> ``` ```mdx-code-block From 2964e6f65d3621af5516b66a0ca1aab25f5100ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Fri, 25 Mar 2022 18:59:31 +0100 Subject: [PATCH 074/405] refactor: split DocSidebarItem by item type (#7005) --- .../src/plugin-content-docs.d.ts | 2 + .../src/theme-classic.d.ts | 34 +++ .../src/theme/DocSidebarItem/Category.tsx | 212 ++++++++++++++ .../{styles.module.css => Html.module.css} | 4 - .../src/theme/DocSidebarItem/Html.tsx | 34 +++ .../src/theme/DocSidebarItem/Link.module.css | 10 + .../src/theme/DocSidebarItem/Link.tsx | 58 ++++ .../src/theme/DocSidebarItem/index.tsx | 263 +----------------- 8 files changed, 354 insertions(+), 263 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx rename packages/docusaurus-theme-classic/src/theme/DocSidebarItem/{styles.module.css => Html.module.css} (88%) create mode 100644 packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.module.css create mode 100644 packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.tsx diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 3d3898e0cf86..ad361efcb4ea 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -134,6 +134,8 @@ declare module '@docusaurus/plugin-content-docs' { export type PropSidebarItemLink = import('./sidebars/types').PropSidebarItemLink; + export type PropSidebarItemHtml = + import('./sidebars/types').PropSidebarItemHtml; export type PropSidebarItemCategory = import('./sidebars/types').PropSidebarItemCategory; export type PropSidebarItem = import('./sidebars/types').PropSidebarItem; diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 440eb8bbfc41..bb3e03137640 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -235,6 +235,40 @@ declare module '@theme/DocSidebarItem' { export default function DocSidebarItem(props: Props): JSX.Element; } +declare module '@theme/DocSidebarItem/Link' { + import type {Props as DocSidebarItemProps} from '@theme/DocSidebarItem'; + + import type {PropSidebarItemLink} from '@docusaurus/plugin-content-docs'; + + export interface Props extends DocSidebarItemProps { + item: PropSidebarItemLink; + } + + export default function DocSidebarItemLink(props: Props): JSX.Element; +} + +declare module '@theme/DocSidebarItem/Html' { + import type {Props as DocSidebarItemProps} from '@theme/DocSidebarItem'; + import type {PropSidebarItemHtml} from '@docusaurus/plugin-content-docs'; + + export interface Props extends DocSidebarItemProps { + item: PropSidebarItemHtml; + } + + export default function DocSidebarItemHtml(props: Props): JSX.Element; +} + +declare module '@theme/DocSidebarItem/Category' { + import type {Props as DocSidebarItemProps} from '@theme/DocSidebarItem'; + import type {PropSidebarItemCategory} from '@docusaurus/plugin-content-docs'; + + export interface Props extends DocSidebarItemProps { + item: PropSidebarItemCategory; + } + + export default function DocSidebarItemCategory(props: Props): JSX.Element; +} + declare module '@theme/DocSidebarItems' { import type {Props as DocSidebarItemProps} from '@theme/DocSidebarItem'; import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx new file mode 100644 index 000000000000..c75cf9d7c99a --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx @@ -0,0 +1,212 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ComponentProps, useEffect, useMemo} from 'react'; +import clsx from 'clsx'; +import { + isActiveSidebarItem, + usePrevious, + Collapsible, + useCollapsible, + findFirstCategoryLink, + ThemeClassNames, + useThemeConfig, + useDocSidebarItemsExpandedState, + isSamePath, +} from '@docusaurus/theme-common'; +import Link from '@docusaurus/Link'; +import {translate} from '@docusaurus/Translate'; + +import DocSidebarItems from '@theme/DocSidebarItems'; +import type {Props} from '@theme/DocSidebarItem/Category'; + +import useIsBrowser from '@docusaurus/useIsBrowser'; + +// If we navigate to a category and it becomes active, it should automatically +// expand itself +function useAutoExpandActiveCategory({ + isActive, + collapsed, + setCollapsed, +}: { + isActive: boolean; + collapsed: boolean; + setCollapsed: (b: boolean) => void; +}) { + const wasActive = usePrevious(isActive); + useEffect(() => { + const justBecameActive = isActive && !wasActive; + if (justBecameActive && collapsed) { + setCollapsed(false); + } + }, [isActive, wasActive, collapsed, setCollapsed]); +} + +/** + * When a collapsible category has no link, we still link it to its first child + * during SSR as a temporary fallback. This allows to be able to navigate inside + * the category even when JS fails to load, is delayed or simply disabled + * React hydration becomes an optional progressive enhancement + * see https://github.com/facebookincubator/infima/issues/36#issuecomment-772543188 + * see https://github.com/facebook/docusaurus/issues/3030 + */ +function useCategoryHrefWithSSRFallback( + item: Props['item'], +): string | undefined { + const isBrowser = useIsBrowser(); + return useMemo(() => { + if (item.href) { + return item.href; + } + // In these cases, it's not necessary to render a fallback + // We skip the "findFirstCategoryLink" computation + if (isBrowser || !item.collapsible) { + return undefined; + } + return findFirstCategoryLink(item); + }, [item, isBrowser]); +} + +function CollapseButton({ + categoryLabel, + onClick, +}: { + categoryLabel: string; + onClick: ComponentProps<'button'>['onClick']; +}) { + return ( + <button + aria-label={translate( + { + id: 'theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel', + message: "Toggle the collapsible sidebar category '{label}'", + description: + 'The ARIA label to toggle the collapsible sidebar category', + }, + {label: categoryLabel}, + )} + type="button" + className="clean-btn menu__caret" + onClick={onClick} + /> + ); +} + +export default function DocSidebarItemCategory({ + item, + onItemClick, + activePath, + level, + index, + ...props +}: Props): JSX.Element { + const {items, label, collapsible, className, href} = item; + const hrefWithSSRFallback = useCategoryHrefWithSSRFallback(item); + + const isActive = isActiveSidebarItem(item, activePath); + const isCurrentPage = isSamePath(href, activePath); + + const {collapsed, setCollapsed} = useCollapsible({ + // active categories are always initialized as expanded + // the default (item.collapsed) is only used for non-active categories + initialState: () => { + if (!collapsible) { + return false; + } + return isActive ? false : item.collapsed; + }, + }); + + useAutoExpandActiveCategory({isActive, collapsed, setCollapsed}); + const {expandedItem, setExpandedItem} = useDocSidebarItemsExpandedState(); + function updateCollapsed(toCollapsed: boolean = !collapsed) { + setExpandedItem(toCollapsed ? null : index); + setCollapsed(toCollapsed); + } + const {autoCollapseSidebarCategories} = useThemeConfig(); + useEffect(() => { + if ( + collapsible && + expandedItem && + expandedItem !== index && + autoCollapseSidebarCategories + ) { + setCollapsed(true); + } + }, [ + collapsible, + expandedItem, + index, + setCollapsed, + autoCollapseSidebarCategories, + ]); + + return ( + <li + className={clsx( + ThemeClassNames.docs.docSidebarItemCategory, + ThemeClassNames.docs.docSidebarItemCategoryLevel(level), + 'menu__list-item', + { + 'menu__list-item--collapsed': collapsed, + }, + className, + )}> + <div + className={clsx('menu__list-item-collapsible', { + 'menu__list-item-collapsible--active': isCurrentPage, + })}> + <Link + className={clsx('menu__link', { + 'menu__link--sublist': collapsible, + 'menu__link--sublist-caret': !href, + 'menu__link--active': isActive, + })} + onClick={ + collapsible + ? (e) => { + onItemClick?.(item); + if (href) { + updateCollapsed(false); + } else { + e.preventDefault(); + updateCollapsed(); + } + } + : () => { + onItemClick?.(item); + } + } + aria-current={isCurrentPage ? 'page' : undefined} + aria-expanded={collapsible ? !collapsed : undefined} + href={collapsible ? hrefWithSSRFallback ?? '#' : hrefWithSSRFallback} + {...props}> + {label} + </Link> + {href && collapsible && ( + <CollapseButton + categoryLabel={label} + onClick={(e) => { + e.preventDefault(); + updateCollapsed(); + }} + /> + )} + </div> + + <Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}> + <DocSidebarItems + items={items} + tabIndex={collapsed ? -1 : 0} + onItemClick={onItemClick} + activePath={activePath} + level={level + 1} + /> + </Collapsible> + </li> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.module.css similarity index 88% rename from packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.module.css index e8a2d6c96052..2bb6934d33ee 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.module.css @@ -11,7 +11,3 @@ var(--ifm-menu-link-padding-horizontal); } } - -.menuExternalLink { - align-items: center; -} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.tsx new file mode 100644 index 000000000000..0e97ec27788a --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Html.tsx @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import {ThemeClassNames} from '@docusaurus/theme-common'; +import type {Props} from '@theme/DocSidebarItem/Html'; + +import styles from './Html.module.css'; + +export default function DocSidebarItemHtml({ + item, + level, + index, +}: Props): JSX.Element { + const {value, defaultStyle, className} = item; + return ( + <li + className={clsx( + ThemeClassNames.docs.docSidebarItemLink, + ThemeClassNames.docs.docSidebarItemLinkLevel(level), + defaultStyle && `${styles.menuHtmlItem} menu__list-item`, + className, + )} + key={index} + // eslint-disable-next-line react/no-danger + dangerouslySetInnerHTML={{__html: value}} + /> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.module.css new file mode 100644 index 000000000000..4abcb5676233 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.module.css @@ -0,0 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.menuExternalLink { + align-items: center; +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.tsx new file mode 100644 index 000000000000..28c481eed42f --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link.tsx @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import {isActiveSidebarItem, ThemeClassNames} from '@docusaurus/theme-common'; +import Link from '@docusaurus/Link'; +import isInternalUrl from '@docusaurus/isInternalUrl'; +import IconExternalLink from '@theme/IconExternalLink'; + +import type {Props} from '@theme/DocSidebarItem/Link'; + +import styles from './Link.module.css'; + +export default function DocSidebarItemLink({ + item, + onItemClick, + activePath, + level, + index, + ...props +}: Props): JSX.Element { + const {href, label, className} = item; + const isActive = isActiveSidebarItem(item, activePath); + const isInternalLink = isInternalUrl(href); + return ( + <li + className={clsx( + ThemeClassNames.docs.docSidebarItemLink, + ThemeClassNames.docs.docSidebarItemLinkLevel(level), + 'menu__list-item', + className, + )} + key={label}> + <Link + className={clsx( + 'menu__link', + !isInternalLink && styles.menuExternalLink, + { + 'menu__link--active': isActive, + }, + )} + aria-current={isActive ? 'page' : undefined} + to={href} + {...(isInternalLink && { + onClick: onItemClick ? () => onItemClick(item) : undefined, + })} + {...props}> + {label} + {!isInternalLink && <IconExternalLink />} + </Link> + </li> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index eca309416aa5..34c40c18d81b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -5,34 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useEffect, useMemo} from 'react'; -import clsx from 'clsx'; -import { - isActiveSidebarItem, - usePrevious, - Collapsible, - useCollapsible, - findFirstCategoryLink, - ThemeClassNames, - useThemeConfig, - useDocSidebarItemsExpandedState, - isSamePath, -} from '@docusaurus/theme-common'; -import Link from '@docusaurus/Link'; -import isInternalUrl from '@docusaurus/isInternalUrl'; -import {translate} from '@docusaurus/Translate'; -import IconExternalLink from '@theme/IconExternalLink'; - -import DocSidebarItems from '@theme/DocSidebarItems'; +import React from 'react'; +import DocSidebarItemCategory from '@theme/DocSidebarItem/Category'; +import DocSidebarItemLink from '@theme/DocSidebarItem/Link'; +import DocSidebarItemHtml from '@theme/DocSidebarItem/Html'; import type {Props} from '@theme/DocSidebarItem'; -import type { - PropSidebarItemCategory, - PropSidebarItemLink, -} from '@docusaurus/plugin-content-docs'; - -import styles from './styles.module.css'; -import useIsBrowser from '@docusaurus/useIsBrowser'; -import type {SidebarItemHtml} from '@docusaurus/plugin-content-docs/src/sidebars/types'; export default function DocSidebarItem({ item, @@ -48,235 +25,3 @@ export default function DocSidebarItem({ return <DocSidebarItemLink item={item} {...props} />; } } - -// If we navigate to a category and it becomes active, it should automatically -// expand itself -function useAutoExpandActiveCategory({ - isActive, - collapsed, - setCollapsed, -}: { - isActive: boolean; - collapsed: boolean; - setCollapsed: (b: boolean) => void; -}) { - const wasActive = usePrevious(isActive); - useEffect(() => { - const justBecameActive = isActive && !wasActive; - if (justBecameActive && collapsed) { - setCollapsed(false); - } - }, [isActive, wasActive, collapsed, setCollapsed]); -} - -/** - * When a collapsible category has no link, we still link it to its first child - * during SSR as a temporary fallback. This allows to be able to navigate inside - * the category even when JS fails to load, is delayed or simply disabled - * React hydration becomes an optional progressive enhancement - * see https://github.com/facebookincubator/infima/issues/36#issuecomment-772543188 - * see https://github.com/facebook/docusaurus/issues/3030 - */ -function useCategoryHrefWithSSRFallback( - item: PropSidebarItemCategory, -): string | undefined { - const isBrowser = useIsBrowser(); - return useMemo(() => { - if (item.href) { - return item.href; - } - // In these cases, it's not necessary to render a fallback - // We skip the "findFirstCategoryLink" computation - if (isBrowser || !item.collapsible) { - return undefined; - } - return findFirstCategoryLink(item); - }, [item, isBrowser]); -} - -function DocSidebarItemCategory({ - item, - onItemClick, - activePath, - level, - index, - ...props -}: Props & {item: PropSidebarItemCategory}) { - const {items, label, collapsible, className, href} = item; - const hrefWithSSRFallback = useCategoryHrefWithSSRFallback(item); - - const isActive = isActiveSidebarItem(item, activePath); - const isCurrentPage = isSamePath(href, activePath); - - const {collapsed, setCollapsed} = useCollapsible({ - // active categories are always initialized as expanded - // the default (item.collapsed) is only used for non-active categories - initialState: () => { - if (!collapsible) { - return false; - } - return isActive ? false : item.collapsed; - }, - }); - - useAutoExpandActiveCategory({isActive, collapsed, setCollapsed}); - const {expandedItem, setExpandedItem} = useDocSidebarItemsExpandedState(); - function updateCollapsed(toCollapsed: boolean = !collapsed) { - setExpandedItem(toCollapsed ? null : index); - setCollapsed(toCollapsed); - } - const {autoCollapseSidebarCategories} = useThemeConfig(); - useEffect(() => { - if ( - collapsible && - expandedItem && - expandedItem !== index && - autoCollapseSidebarCategories - ) { - setCollapsed(true); - } - }, [ - collapsible, - expandedItem, - index, - setCollapsed, - autoCollapseSidebarCategories, - ]); - - return ( - <li - className={clsx( - ThemeClassNames.docs.docSidebarItemCategory, - ThemeClassNames.docs.docSidebarItemCategoryLevel(level), - 'menu__list-item', - { - 'menu__list-item--collapsed': collapsed, - }, - className, - )}> - <div - className={clsx('menu__list-item-collapsible', { - 'menu__list-item-collapsible--active': isCurrentPage, - })}> - <Link - className={clsx('menu__link', { - 'menu__link--sublist': collapsible, - 'menu__link--sublist-caret': !href, - 'menu__link--active': isActive, - })} - onClick={ - collapsible - ? (e) => { - onItemClick?.(item); - if (href) { - updateCollapsed(false); - } else { - e.preventDefault(); - updateCollapsed(); - } - } - : () => { - onItemClick?.(item); - } - } - aria-current={isCurrentPage ? 'page' : undefined} - aria-expanded={collapsible ? !collapsed : undefined} - href={collapsible ? hrefWithSSRFallback ?? '#' : hrefWithSSRFallback} - {...props}> - {label} - </Link> - {href && collapsible && ( - <button - aria-label={translate( - { - id: 'theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel', - message: "Toggle the collapsible sidebar category '{label}'", - description: - 'The ARIA label to toggle the collapsible sidebar category', - }, - {label}, - )} - type="button" - className="clean-btn menu__caret" - onClick={(e) => { - e.preventDefault(); - updateCollapsed(); - }} - /> - )} - </div> - - <Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}> - <DocSidebarItems - items={items} - tabIndex={collapsed ? -1 : 0} - onItemClick={onItemClick} - activePath={activePath} - level={level + 1} - /> - </Collapsible> - </li> - ); -} - -function DocSidebarItemHtml({ - item, - level, - index, -}: Props & {item: SidebarItemHtml}) { - const {value, defaultStyle, className} = item; - return ( - <li - className={clsx( - ThemeClassNames.docs.docSidebarItemLink, - ThemeClassNames.docs.docSidebarItemLinkLevel(level), - defaultStyle && `${styles.menuHtmlItem} menu__list-item`, - className, - )} - key={index} - // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{__html: value}} - /> - ); -} - -function DocSidebarItemLink({ - item, - onItemClick, - activePath, - level, - index, - ...props -}: Props & {item: PropSidebarItemLink}) { - const {href, label, className} = item; - const isActive = isActiveSidebarItem(item, activePath); - const isInternalLink = isInternalUrl(href); - return ( - <li - className={clsx( - ThemeClassNames.docs.docSidebarItemLink, - ThemeClassNames.docs.docSidebarItemLinkLevel(level), - 'menu__list-item', - className, - )} - key={label}> - <Link - className={clsx( - 'menu__link', - !isInternalLink && styles.menuExternalLink, - { - 'menu__link--active': isActive, - }, - )} - aria-current={isActive ? 'page' : undefined} - to={href} - {...(isInternalLink && { - onClick: onItemClick ? () => onItemClick(item) : undefined, - })} - {...props}> - {label} - {!isInternalLink && <IconExternalLink />} - </Link> - </li> - ); -} From 1b974e8b1b7969475d85469dbca43771a2af5afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= <slorber@users.noreply.github.com> Date: Fri, 25 Mar 2022 19:58:28 +0100 Subject: [PATCH 075/405] refactor: split and cleanup theme/DocPage (#7006) --- .../src/plugin-content-docs.d.ts | 34 +++ .../src/theme/DocPage/Layout/Aside.tsx | 100 +++++++++ .../src/theme/DocPage/Layout/Main.tsx | 37 ++++ .../src/theme/DocPage/Layout/index.tsx | 39 ++++ .../DocPage/{ => Layout}/styles.module.css | 0 .../src/theme/DocPage/index.tsx | 193 +++++------------- .../contexts/__tests__/docsSidebar.test.tsx | 13 +- .../src/contexts/docsSidebar.tsx | 38 ++-- .../src/utils/__tests__/docsUtils.test.tsx | 4 +- .../src/utils/docsUtils.tsx | 4 +- 10 files changed, 299 insertions(+), 163 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Aside.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main.tsx create mode 100644 packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx rename packages/docusaurus-theme-classic/src/theme/DocPage/{ => Layout}/styles.module.css (100%) diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index ad361efcb4ea..7c807019c7ea 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -275,6 +275,40 @@ declare module '@theme/DocPage' { export default function DocPage(props: Props): JSX.Element; } +declare module '@theme/DocPage/Layout' { + import type {ReactNode} from 'react'; + + export interface Props { + children: ReactNode; + } + + export default function DocPageLayout(props: Props): JSX.Element; +} + +declare module '@theme/DocPage/Layout/Aside' { + import type {Dispatch, SetStateAction} from 'react'; + import type {PropSidebar} from '@docusaurus/plugin-content-docs'; + + export interface Props { + sidebar: PropSidebar; + hiddenSidebarContainer: boolean; + setHiddenSidebarContainer: Dispatch<SetStateAction<boolean>>; + } + + export default function DocPageLayoutAside(props: Props): JSX.Element; +} + +declare module '@theme/DocPage/Layout/Main' { + import type {ReactNode} from 'react'; + + export interface Props { + hiddenSidebarContainer: boolean; + children: ReactNode; + } + + export default function DocPageLayoutMain(props: Props): JSX.Element; +} + // TODO until TS supports exports field... hope it's in 4.6 declare module '@docusaurus/plugin-content-docs/client' { export type ActivePlugin = { diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Aside.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Aside.tsx new file mode 100644 index 000000000000..236382eae4ff --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Aside.tsx @@ -0,0 +1,100 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {type ReactNode, useState, useCallback} from 'react'; +import DocSidebar from '@theme/DocSidebar'; +import IconArrow from '@theme/IconArrow'; +import {translate} from '@docusaurus/Translate'; +import {useLocation} from '@docusaurus/router'; +import type {Props} from '@theme/DocPage/Layout/Aside'; + +import clsx from 'clsx'; +import styles from './styles.module.css'; + +import {ThemeClassNames, useDocsSidebar} from '@docusaurus/theme-common'; + +function SidebarExpandButton({toggleSidebar}: {toggleSidebar: () => void}) { + return ( + <div + className={styles.collapsedDocSidebar} + title={translate({ + id: 'theme.docs.sidebar.expandButtonTitle', + message: 'Expand sidebar', + description: + 'The ARIA label and title attribute for expand button of doc sidebar', + })} + aria-label={translate({ + id: 'theme.docs.sidebar.expandButtonAriaLabel', + message: 'Expand sidebar', + description: + 'The ARIA label and title attribute for expand button of doc sidebar', + })} + tabIndex={0} + role="button" + onKeyDown={toggleSidebar} + onClick={toggleSidebar}> + <IconArrow className={styles.expandSidebarButtonIcon} /> + </div> + ); +} + +// Reset sidebar state when sidebar changes +// Use React key to unmount/remount the children +// See https://github.com/facebook/docusaurus/issues/3414 +function ResetOnSidebarChange({children}: {children: ReactNode}) { + const sidebar = useDocsSidebar(); + return ( + <React.Fragment key={sidebar?.name ?? 'noSidebar'}> + {children} + </React.Fragment> + ); +} + +export default function DocPageLayoutAside({ + sidebar, + hiddenSidebarContainer, + setHiddenSidebarContainer, +}: Props): JSX.Element { + const {pathname} = useLocation(); + + const [hiddenSidebar, setHiddenSidebar] = useState(false); + const toggleSidebar = useCallback(() => { + if (hiddenSidebar) { + setHiddenSidebar(false); + } + setHiddenSidebarContainer((value) => !value); + }, [setHiddenSidebarContainer, hiddenSidebar]); + + return ( + <aside + className={clsx( + ThemeClassNames.docs.docSidebarContainer, + styles.docSidebarContainer, + hiddenSidebarContainer && styles.docSidebarContainerHidden, + )} + onTransitionEnd={(e) => { + if (!e.currentTarget.classList.contains(styles.docSidebarContainer!)) { + return; + } + + if (hiddenSidebarContainer) { + setHiddenSidebar(true); + } + }}> + <ResetOnSidebarChange> + <DocSidebar + sidebar={sidebar} + path={pathname} + onCollapse={toggleSidebar} + isHidden={hiddenSidebar} + /> + </ResetOnSidebarChange> + + {hiddenSidebar && <SidebarExpandButton toggleSidebar={toggleSidebar} />} + </aside> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main.tsx new file mode 100644 index 000000000000..3cc4f0479e00 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/Main.tsx @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; + +import {useDocsSidebar} from '@docusaurus/theme-common'; + +import clsx from 'clsx'; +import styles from './styles.module.css'; +import type {Props} from '@theme/DocPage/Layout/Main'; + +export default function DocPageLayoutMain({ + hiddenSidebarContainer, + children, +}: Props): JSX.Element { + const sidebar = useDocsSidebar(); + return ( + <main + className={clsx( + styles.docMainContainer, + (hiddenSidebarContainer || !sidebar) && styles.docMainContainerEnhanced, + )}> + <div + className={clsx( + 'container padding-top--md padding-bottom--lg', + styles.docItemWrapper, + hiddenSidebarContainer && styles.docItemWrapperEnhanced, + )}> + {children} + </div> + </main> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx new file mode 100644 index 000000000000..77d148811826 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx @@ -0,0 +1,39 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {useState} from 'react'; +import Layout from '@theme/Layout'; +import BackToTopButton from '@theme/BackToTopButton'; +import type {Props} from '@theme/DocPage/Layout'; +import DocPageLayoutAside from '@theme/DocPage/Layout/Aside'; +import DocPageLayoutMain from '@theme/DocPage/Layout/Main'; + +import styles from './styles.module.css'; + +import {useDocsSidebar} from '@docusaurus/theme-common'; + +export default function DocPageLayout({children}: Props): JSX.Element { + const sidebar = useDocsSidebar(); + const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); + return ( + <Layout> + <BackToTopButton /> + <div className={styles.docPage}> + {sidebar && ( + <DocPageLayoutAside + sidebar={sidebar.items} + hiddenSidebarContainer={hiddenSidebarContainer} + setHiddenSidebarContainer={setHiddenSidebarContainer} + /> + )} + <DocPageLayoutMain hiddenSidebarContainer={hiddenSidebarContainer}> + {children} + </DocPageLayoutMain> + </div> + </Layout> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css similarity index 100% rename from packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index d75ffa55a5fe..8ee721f9862b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -5,145 +5,30 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode, useState, useCallback} from 'react'; +import React from 'react'; import renderRoutes from '@docusaurus/renderRoutes'; -import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs'; -import Layout from '@theme/Layout'; -import DocSidebar from '@theme/DocSidebar'; +import type {PropSidebar} from '@docusaurus/plugin-content-docs'; import NotFound from '@theme/NotFound'; -import type {DocumentRoute} from '@theme/DocItem'; import type {Props} from '@theme/DocPage'; -import IconArrow from '@theme/IconArrow'; -import BackToTopButton from '@theme/BackToTopButton'; +import DocPageLayout from '@theme/DocPage/Layout'; import {matchPath} from '@docusaurus/router'; -import {translate} from '@docusaurus/Translate'; import clsx from 'clsx'; -import styles from './styles.module.css'; import { HtmlClassNameProvider, ThemeClassNames, docVersionSearchTag, DocsSidebarProvider, - useDocsSidebar, DocsVersionProvider, } from '@docusaurus/theme-common'; import SearchMetadata from '@theme/SearchMetadata'; -type DocPageContentProps = { - readonly currentDocRoute: DocumentRoute; - readonly versionMetadata: PropVersionMetadata; - readonly children: ReactNode; - readonly sidebarName: string | undefined; -}; - -function DocPageContent({ - currentDocRoute, - versionMetadata, - children, - sidebarName, -}: DocPageContentProps): JSX.Element { - const sidebar = useDocsSidebar(); - const {pluginId, version} = versionMetadata; - const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); - const [hiddenSidebar, setHiddenSidebar] = useState(false); - const toggleSidebar = useCallback(() => { - if (hiddenSidebar) { - setHiddenSidebar(false); - } - - setHiddenSidebarContainer((value) => !value); - }, [hiddenSidebar]); - - return ( - <> - <SearchMetadata - version={version} - tag={docVersionSearchTag(pluginId, version)} - /> - <Layout> - <div className={styles.docPage}> - <BackToTopButton /> - - {sidebar && ( - <aside - className={clsx( - ThemeClassNames.docs.docSidebarContainer, - styles.docSidebarContainer, - hiddenSidebarContainer && styles.docSidebarContainerHidden, - )} - onTransitionEnd={(e) => { - if ( - !e.currentTarget.classList.contains( - styles.docSidebarContainer!, - ) - ) { - return; - } - - if (hiddenSidebarContainer) { - setHiddenSidebar(true); - } - }}> - <DocSidebar - key={ - // Reset sidebar state on sidebar changes - // See https://github.com/facebook/docusaurus/issues/3414 - sidebarName - } - sidebar={sidebar} - path={currentDocRoute.path} - onCollapse={toggleSidebar} - isHidden={hiddenSidebar} - /> - - {hiddenSidebar && ( - <div - className={styles.collapsedDocSidebar} - title={translate({ - id: 'theme.docs.sidebar.expandButtonTitle', - message: 'Expand sidebar', - description: - 'The ARIA label and title attribute for expand button of doc sidebar', - })} - aria-label={translate({ - id: 'theme.docs.sidebar.expandButtonAriaLabel', - message: 'Expand sidebar', - description: - 'The ARIA label and title attribute for expand button of doc sidebar', - })} - tabIndex={0} - role="button" - onKeyDown={toggleSidebar} - onClick={toggleSidebar}> - <IconArrow className={styles.expandSidebarButtonIcon} /> - </div> - )} - </aside> - )} - <main - className={clsx( - styles.docMainContainer, - (hiddenSidebarContainer || !sidebar) && - styles.docMainContainerEnhanced, - )}> - <div - className={clsx( - 'container padding-top--md padding-bottom--lg', - styles.docItemWrapper, - hiddenSidebarContainer && styles.docItemWrapperEnhanced, - )}> - {children} - </div> - </main> - </div> - </Layout> - </> - ); -} - -export default function DocPage(props: Props): JSX.Element { +function extractDocRouteMetadata(props: Props): null | { + docElement: JSX.Element; + sidebarName: string | undefined; + sidebarItems: PropSidebar | undefined; +} { const { route: {routes: docRoutes}, versionMetadata, @@ -153,33 +38,55 @@ export default function DocPage(props: Props): JSX.Element { matchPath(location.pathname, docRoute), ); if (!currentDocRoute) { - return <NotFound />; + return null; } // For now, the sidebarName is added as route config: not ideal! const sidebarName = currentDocRoute.sidebar; - const sidebar = sidebarName + const sidebarItems = sidebarName ? versionMetadata.docsSidebars[sidebarName] - : null; + : undefined; + + const docElement = renderRoutes(props.route.routes, { + versionMetadata, + }); + return { + docElement, + sidebarName, + sidebarItems, + }; +} + +export default function DocPage(props: Props): JSX.Element { + const {versionMetadata} = props; + const currentDocRouteMetadata = extractDocRouteMetadata(props); + if (!currentDocRouteMetadata) { + return <NotFound />; + } + const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata; return ( - <HtmlClassNameProvider - className={clsx( - ThemeClassNames.wrapper.docsPages, - ThemeClassNames.page.docsDocPage, - versionMetadata.className, - )}> - <DocsVersionProvider version={versionMetadata}> - <DocsSidebarProvider sidebar={sidebar ?? null}> - <DocPageContent - currentDocRoute={currentDocRoute} - versionMetadata={versionMetadata} - sidebarName={sidebarName}> - {renderRoutes(docRoutes, {versionMetadata})} - </DocPageContent> - </DocsSidebarProvider> - </DocsVersionProvider> - </HtmlClassNameProvider> + <> + <SearchMetadata + version={versionMetadata.version} + tag={docVersionSearchTag( + versionMetadata.pluginId, + versionMetadata.version, + )} + /> + <HtmlClassNameProvider + className={clsx( + ThemeClassNames.wrapper.docsPages, + ThemeClassNames.page.docsDocPage, + props.versionMetadata.className, + )}> + <DocsVersionProvider version={versionMetadata}> + <DocsSidebarProvider name={sidebarName} items={sidebarItems}> + <DocPageLayout>{docElement}</DocPageLayout> + </DocsSidebarProvider> + </DocsVersionProvider> + </HtmlClassNameProvider> + </> ); } diff --git a/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx b/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx index 5d66881b7d16..2082a9779aef 100644 --- a/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx +++ b/packages/docusaurus-theme-common/src/contexts/__tests__/docsSidebar.test.tsx @@ -13,19 +13,24 @@ import type {PropSidebar} from '@docusaurus/plugin-content-docs'; describe('useDocsSidebar', () => { it('throws if context provider is missing', () => { expect( - () => renderHook(() => useDocsSidebar()).result.current, + () => renderHook(() => useDocsSidebar()).result.current?.items, ).toThrowErrorMatchingInlineSnapshot( `"Hook useDocsSidebar is called outside the <DocsSidebarProvider>. "`, ); }); it('reads value from context provider', () => { - const sidebar: PropSidebar = []; + const name = 'mySidebarName'; + const items: PropSidebar = []; const {result} = renderHook(() => useDocsSidebar(), { wrapper: ({children}) => ( - <DocsSidebarProvider sidebar={sidebar}>{children}</DocsSidebarProvider> + <DocsSidebarProvider name={name} items={items}> + {children} + </DocsSidebarProvider> ), }); - expect(result.current).toBe(sidebar); + expect(result.current).toBeDefined(); + expect(result.current!.name).toBe(name); + expect(result.current!.items).toBe(items); }); }); diff --git a/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx index 4d2f7caa61d7..2fb4d1cb0f19 100644 --- a/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {type ReactNode, useContext} from 'react'; +import React, {useMemo, useContext, type ReactNode} from 'react'; import type {PropSidebar} from '@docusaurus/plugin-content-docs'; import {ReactContextError} from '../utils/reactUtils'; @@ -13,30 +13,44 @@ import {ReactContextError} from '../utils/reactUtils'; // Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx const EmptyContext: unique symbol = Symbol('EmptyContext'); -const Context = React.createContext<PropSidebar | null | typeof EmptyContext>( - EmptyContext, -); +type SidebarContextValue = {name: string; items: PropSidebar}; + +const Context = React.createContext< + SidebarContextValue | null | typeof EmptyContext +>(EmptyContext); /** * Provide the current sidebar to your children. */ export function DocsSidebarProvider({ children, - sidebar, + name, + items, }: { children: ReactNode; - sidebar: PropSidebar | null; + name: string | undefined; + items: PropSidebar | undefined; }): JSX.Element { - return <Context.Provider value={sidebar}>{children}</Context.Provider>; + const stableValue: SidebarContextValue | null = useMemo( + () => + name && items + ? { + name, + items, + } + : null, + [name, items], + ); + return <Context.Provider value={stableValue}>{children}</Context.Provider>; } /** - * Gets the sidebar that's currently displayed, or `null` if there isn't one + * Gets the sidebar data that's currently displayed, or `null` if there isn't one */ -export function useDocsSidebar(): PropSidebar | null { - const sidebar = useContext(Context); - if (sidebar === EmptyContext) { +export function useDocsSidebar(): SidebarContextValue | null { + const value = useContext(Context); + if (value === EmptyContext) { throw new ReactContextError('DocsSidebarProvider'); } - return sidebar; + return value; } diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index 4fd8df849b2a..532fb20a0acf 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -307,7 +307,7 @@ describe('useSidebarBreadcrumbs', () => { }, }, }}> - <DocsSidebarProvider sidebar={sidebar}> + <DocsSidebarProvider name="sidebarName" items={sidebar}> {children} </DocsSidebarProvider> </Context.Provider> @@ -430,7 +430,7 @@ describe('useCurrentSidebarCategory', () => { (sidebar?: PropSidebar) => (location: string) => renderHook(() => useCurrentSidebarCategory(), { wrapper: ({children}) => ( - <DocsSidebarProvider sidebar={sidebar}> + <DocsSidebarProvider name="sidebarName" items={sidebar}> <StaticRouter location={location}>{children}</StaticRouter> </DocsSidebarProvider> ), diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 2a16dc6f8eb0..e5e54478b415 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -105,7 +105,7 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory { if (!sidebar) { throw new Error('Unexpected: cant find current sidebar in context'); } - const category = findSidebarCategory(sidebar, (item) => + const category = findSidebarCategory(sidebar.items, (item) => isSamePath(item.href, pathname), ); if (!category) { @@ -174,7 +174,7 @@ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null { return false; } - extract(sidebar); + extract(sidebar.items); return breadcrumbs.reverse(); } From 72f005e85241a4d84be340f01fa7d8260b873ff9 Mon Sep 17 00:00:00 2001 From: sulu5890 <sulu@sulu.me> Date: Fri, 25 Mar 2022 23:28:49 -0700 Subject: [PATCH 076/405] fix(types): declare history and react-loadable as dependencies (#7014) * fix(types): declare history and react-loadable as dependencies * fix(types): downgrade history to 4.9.0 to match react-router * add @docusaurus/react-loadable such that it can be correctly resolved --- packages/docusaurus-types/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index 245d45cedd10..33ffb60a213f 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -16,7 +16,9 @@ "test": "tsc -p ." }, "dependencies": { + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", "commander": "^5.1.0", + "history": "^4.9.0", "joi": "^17.6.0", "utility-types": "^3.10.0", "webpack": "^5.70.0", From 3683f256374847e97ef54bfc210b7ae61dabc390 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sat, 26 Mar 2022 16:45:19 +0800 Subject: [PATCH 077/405] fix(theme-classic): do not add caret for non-collapsible categories (#7015) --- .../src/theme/DocSidebarItem/Category.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx index c75cf9d7c99a..202a9dae09c3 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category.tsx @@ -163,7 +163,7 @@ export default function DocSidebarItemCategory({ <Link className={clsx('menu__link', { 'menu__link--sublist': collapsible, - 'menu__link--sublist-caret': !href, + 'menu__link--sublist-caret': !href && collapsible, 'menu__link--active': isActive, })} onClick={ From 45b7a1b7c81a3b4a805932d93aa49dbcbcf1fdbf Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Sat, 26 Mar 2022 12:51:54 +0300 Subject: [PATCH 078/405] refactor: remove copyright comment from swizzled components (#7017) * refactor: remove copyright comment from swizzled components * Update packages/docusaurus/src/commands/swizzle/actions.ts Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../__fixtures__/theme/ComponentInFolder/index.css | 10 +++++++++- .../__fixtures__/theme/ComponentInFolder/index.tsx | 7 +++++++ .../__fixtures__/theme/FirstLevelComponent.css | 7 +++++++ .../__fixtures__/theme/FirstLevelComponent.tsx | 7 +++++++ packages/docusaurus/src/commands/swizzle/actions.ts | 6 +++++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.css b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.css index 7aa192f3b39f..555b0869f0c0 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.css +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.css @@ -1,3 +1,11 @@ -.testClass { + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + .testClass { background: black; } diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.tsx b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.tsx index c8a3a86a5f33..dc1a164502f2 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.tsx +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/ComponentInFolder/index.tsx @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import React from 'react'; export default function ComponentInFolder() { diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.css b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.css index 7aa192f3b39f..29c5ece80f3c 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.css +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.css @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + .testClass { background: black; } diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.tsx b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.tsx index 6cd8764e9150..3cde34503d66 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.tsx +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__fixtures__/theme/FirstLevelComponent.tsx @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import React from 'react'; export default function FirstLevelComponent() { diff --git a/packages/docusaurus/src/commands/swizzle/actions.ts b/packages/docusaurus/src/commands/swizzle/actions.ts index f85bfb7a0f79..8cb892950700 100644 --- a/packages/docusaurus/src/commands/swizzle/actions.ts +++ b/packages/docusaurus/src/commands/swizzle/actions.ts @@ -81,7 +81,11 @@ export async function eject({ const fileName = path.basename(sourceFile); const targetFile = path.join(toPath, fileName); try { - await fs.copy(sourceFile, targetFile, {overwrite: true}); + const fileContents = await fs.readFile(sourceFile, 'utf-8'); + await fs.outputFile( + targetFile, + fileContents.trimStart().replace(/^\/\*.+?\*\/\s*/ms, ''), + ); } catch (err) { throw new Error( logger.interpolate`Could not copy file from ${sourceFile} to ${targetFile}`, From cb03764ce513025dba2f34b6cbe2f2d539e02796 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sat, 26 Mar 2022 21:05:48 +0800 Subject: [PATCH 079/405] refactor(theme): extract plumbing code of BTT button into theme-common (#7021) * refactor(theme): extract plumbing code of BTT button into theme-common * oops --- .../src/theme/BackToTopButton/index.tsx | 117 +----------------- .../src/hooks/useBackToTopButton.ts | 73 +++++++++++ .../src/hooks/useHideableNavbar.ts | 4 +- packages/docusaurus-theme-common/src/index.ts | 2 + .../src/utils/scrollUtils.tsx | 73 +++++++++++ 5 files changed, 154 insertions(+), 115 deletions(-) create mode 100644 packages/docusaurus-theme-common/src/hooks/useBackToTopButton.ts diff --git a/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx index f9a3d04c5e67..d5e4edfc4134 100644 --- a/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx @@ -5,122 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useRef, useState} from 'react'; +import React from 'react'; import clsx from 'clsx'; import {translate} from '@docusaurus/Translate'; +import {ThemeClassNames, useBackToTopButton} from '@docusaurus/theme-common'; import styles from './styles.module.css'; -import { - ThemeClassNames, - useScrollPosition, - useLocationChange, -} from '@docusaurus/theme-common'; - -const threshold = 300; - -// Not all have support for smooth scrolling (particularly Safari mobile iOS) -// TODO proper detection is currently unreliable! -// see https://github.com/wessberg/scroll-behavior-polyfill/issues/16 -const SupportsNativeSmoothScrolling = false; -// const SupportsNativeSmoothScrolling = -// ExecutionEnvironment.canUseDOM && -// 'scrollBehavior' in document.documentElement.style; - -type CancelScrollTop = () => void; - -function smoothScrollTopNative(): CancelScrollTop { - window.scrollTo({top: 0, behavior: 'smooth'}); - return () => { - // Nothing to cancel, it's natively cancelled if user tries to scroll down - }; -} - -function smoothScrollTopPolyfill(): CancelScrollTop { - let raf: number | null = null; - function rafRecursion() { - const currentScroll = document.documentElement.scrollTop; - if (currentScroll > 0) { - raf = requestAnimationFrame(rafRecursion); - window.scrollTo(0, Math.floor(currentScroll * 0.85)); - } - } - rafRecursion(); - - // Break the recursion. Prevents the user from "fighting" against that - // recursion producing a weird UX - return () => raf && cancelAnimationFrame(raf); -} - -type UseSmoothScrollTopReturn = { - // We use a cancel function because the non-native smooth scroll-top - // implementation must be interrupted if user scroll down - smoothScrollTop: () => void; - cancelScrollToTop: CancelScrollTop; -}; - -function useSmoothScrollToTop(): UseSmoothScrollTopReturn { - const lastCancelRef = useRef<CancelScrollTop | null>(null); - - function smoothScrollTop(): void { - lastCancelRef.current = SupportsNativeSmoothScrolling - ? smoothScrollTopNative() - : smoothScrollTopPolyfill(); - } - - return { - smoothScrollTop, - cancelScrollToTop: () => lastCancelRef.current?.(), - }; -} export default function BackToTopButton(): JSX.Element { - const [show, setShow] = useState(false); - const isFocusedAnchor = useRef(false); - const {smoothScrollTop, cancelScrollToTop} = useSmoothScrollToTop(); - - useScrollPosition(({scrollY: scrollTop}, lastPosition) => { - const lastScrollTop = lastPosition?.scrollY; - - // No lastScrollTop means component is just being mounted. - // Not really a scroll event from the user, so we ignore it - if (!lastScrollTop) { - return; - } - - if (isFocusedAnchor.current) { - isFocusedAnchor.current = false; - return; - } - - const isScrollingUp = scrollTop < lastScrollTop; - - if (!isScrollingUp) { - cancelScrollToTop(); - } - - if (scrollTop < threshold) { - setShow(false); - return; - } - - if (isScrollingUp) { - const documentHeight = document.documentElement.scrollHeight; - const windowHeight = window.innerHeight; - if (scrollTop + windowHeight < documentHeight) { - setShow(true); - } - } else { - setShow(false); - } - }); - - useLocationChange((locationChangeEvent) => { - if (locationChangeEvent.location.hash) { - isFocusedAnchor.current = true; - setShow(false); - } - }); - + const {shown, scrollToTop} = useBackToTopButton({threshold: 300}); return ( <button aria-label={translate({ @@ -132,10 +25,10 @@ export default function BackToTopButton(): JSX.Element { 'clean-btn', ThemeClassNames.common.backToTopButton, styles.backToTopButton, - show && styles.backToTopButtonShow, + shown && styles.backToTopButtonShow, )} type="button" - onClick={() => smoothScrollTop()} + onClick={scrollToTop} /> ); } diff --git a/packages/docusaurus-theme-common/src/hooks/useBackToTopButton.ts b/packages/docusaurus-theme-common/src/hooks/useBackToTopButton.ts new file mode 100644 index 000000000000..aa7e2fd7b7dc --- /dev/null +++ b/packages/docusaurus-theme-common/src/hooks/useBackToTopButton.ts @@ -0,0 +1,73 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {useRef, useState} from 'react'; +import {useScrollPosition, useSmoothScrollTo} from '../utils/scrollUtils'; +import {useLocationChange} from '../utils/useLocationChange'; + +/** Wires the logic for the back to top button. */ +export function useBackToTopButton({ + threshold, +}: { + /** + * The minimum vertical scroll position, above which a scroll-up would not + * cause `shown` to become `true`. This is because BTT is only useful if the + * user is far down the page. + */ + threshold: number; +}): { + /** + * Whether the button should be displayed. We only show if the user has + * scrolled up and is on a vertical position greater than `threshold`. + */ + shown: boolean; + /** + * A (memoized) handle for starting the scroll, which you can directly plug + * into the props. + */ + scrollToTop: () => void; +} { + const [shown, setShown] = useState(false); + const isFocusedAnchor = useRef(false); + const {startScroll, cancelScroll} = useSmoothScrollTo(); + + useScrollPosition(({scrollY: scrollTop}, lastPosition) => { + const lastScrollTop = lastPosition?.scrollY; + // Component is just being mounted. Not really a scroll event from the user. + // Ignore it. + if (!lastScrollTop) { + return; + } + if (isFocusedAnchor.current) { + // This scroll position change is triggered by navigating to an anchor. + // Ignore it. + isFocusedAnchor.current = false; + } else if (scrollTop >= lastScrollTop) { + // The user has scrolled down to "fight against" the animation. Cancel any + // animation under progress. + cancelScroll(); + setShown(false); + } else if (scrollTop < threshold) { + // Scrolled to the minimum position; hide the button. + setShown(false); + } else if ( + scrollTop + window.innerHeight < + document.documentElement.scrollHeight + ) { + setShown(true); + } + }); + + useLocationChange((locationChangeEvent) => { + if (locationChangeEvent.location.hash) { + isFocusedAnchor.current = true; + setShown(false); + } + }); + + return {shown, scrollToTop: () => startScroll(0)}; +} diff --git a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts index 2eb85744e8de..70ef84e3d10b 100644 --- a/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts +++ b/packages/docusaurus-theme-common/src/hooks/useHideableNavbar.ts @@ -28,13 +28,11 @@ export function useHideableNavbar(hideOnScroll: boolean): { } }, []); - useScrollPosition((currentPosition, lastPosition) => { + useScrollPosition(({scrollY: scrollTop}, lastPosition) => { if (!hideOnScroll) { return; } - const scrollTop = currentPosition.scrollY; - // Needed mostly for handling rubber band scrolling. // See https://github.com/facebook/docusaurus/pull/5721 if (scrollTop < navbarHeight.current) { diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index a823af8d4220..82b95d849577 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -106,6 +106,7 @@ export { useScrollController, useScrollPosition, useScrollPositionBlocker, + useSmoothScrollTo, } from './utils/scrollUtils'; export { @@ -145,6 +146,7 @@ export { type NavbarSecondaryMenuComponent, } from './contexts/navbarSecondaryMenu'; +export {useBackToTopButton} from './hooks/useBackToTopButton'; export {useHideableNavbar} from './hooks/useHideableNavbar'; export { useKeyboardNavigation, diff --git a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx index 9c49e0c146bb..88142d54f221 100644 --- a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx @@ -232,3 +232,76 @@ export function useScrollPositionBlocker(): { blockElementScrollPositionUntilNextRender, }; } + +// Not all have support for smooth scrolling (particularly Safari mobile iOS) +// TODO proper detection is currently unreliable! +// see https://github.com/wessberg/scroll-behavior-polyfill/issues/16 +const SupportsNativeSmoothScrolling = false; +// const SupportsNativeSmoothScrolling = +// ExecutionEnvironment.canUseDOM && +// 'scrollBehavior' in document.documentElement.style; + +type CancelScrollTop = () => void; + +function smoothScrollNative(top: number): CancelScrollTop { + window.scrollTo({top, behavior: 'smooth'}); + return () => { + // Nothing to cancel, it's natively cancelled if user tries to scroll down + }; +} + +function smoothScrollPolyfill(top: number): CancelScrollTop { + let raf: number | null = null; + const isUpScroll = document.documentElement.scrollTop > top; + function rafRecursion() { + const currentScroll = document.documentElement.scrollTop; + if ( + (isUpScroll && currentScroll > top) || + (!isUpScroll && currentScroll < top) + ) { + raf = requestAnimationFrame(rafRecursion); + window.scrollTo( + 0, + Math.floor(Math.abs(currentScroll - top) * 0.85) + top, + ); + } + } + rafRecursion(); + + // Break the recursion. Prevents the user from "fighting" against that + // recursion producing a weird UX + return () => raf && cancelAnimationFrame(raf); +} + +/** + * A "smart polyfill" of `window.scrollTo({ top, behavior: "smooth" })`. + * This currently always uses a polyfilled implementation, because native + * support detection seems unreliable. + * + * This hook does not do anything by itself: it returns a start and a stop + * handle. You can execute either handle at any time. + */ +export function useSmoothScrollTo(): { + /** + * Start the scroll. + * + * @param top The final scroll top position. + */ + startScroll: (top: number) => void; + /** + * A cancel function, because the non-native smooth scroll-top + * implementation must be interrupted if user scrolls down. If there's no + * existing animation or the scroll is using native behavior, this is a no-op. + */ + cancelScroll: CancelScrollTop; +} { + const cancelRef = useRef<CancelScrollTop | null>(null); + return { + startScroll: (top: number) => { + cancelRef.current = SupportsNativeSmoothScrolling + ? smoothScrollNative(top) + : smoothScrollPolyfill(top); + }, + cancelScroll: () => cancelRef?.current, + }; +} From e6838dd7a648926171415cc4de143b464d7b5cb7 Mon Sep 17 00:00:00 2001 From: Martin Blom <martin@blom.org> Date: Sat, 26 Mar 2022 15:11:41 +0100 Subject: [PATCH 080/405] docs: add Divine WSF and Ghostly to showcase (#7020) * Added Divine WSF and Ghostly showcases. * optimize images Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/src/data/showcase/divine-wsf.png | Bin 0 -> 26943 bytes website/src/data/showcase/ghostly.png | Bin 0 -> 25208 bytes website/src/data/users.tsx | 16 ++++++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 website/src/data/showcase/divine-wsf.png create mode 100644 website/src/data/showcase/ghostly.png diff --git a/website/src/data/showcase/divine-wsf.png b/website/src/data/showcase/divine-wsf.png new file mode 100644 index 0000000000000000000000000000000000000000..a807ae6a532d29a6ce938f3180576b89bed0ab04 GIT binary patch literal 26943 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 Ef^l^!MF0Q* literal 0 HcmV?d00001 diff --git a/website/src/data/showcase/ghostly.png b/website/src/data/showcase/ghostly.png new file mode 100644 index 0000000000000000000000000000000000000000..74f4662decf9c630142c594a35634e66f9038c89 GIT binary patch literal 25208 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 SJN#efIQjonq-!KiLjDJ4Kh<Oa literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 624ca2c8d42f..96e4d1efc175 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -475,6 +475,14 @@ const Users: User[] = [ source: 'https://github.com/Discord-Resources-Wiki/Discord-Resources-Wiki', tags: ['opensource'], }, + { + title: 'Divine Web Service Framework', + description: 'A divine collection of awesome web-related Node.js modules', + preview: require('./showcase/divine-wsf.png'), + website: 'https://divine-software.github.io/WSF/', + source: 'https://github.com/Divine-Software/WSF/tree/master/website', + tags: ['opensource'], + }, { title: 'Djamaile Rahamat', description: 'Djamaile Rahamat Blog on making cool stuff', @@ -671,6 +679,14 @@ const Users: User[] = [ source: 'https://lab.frogg.it/froggit/www/froggit.fr', tags: ['opensource', 'product'], }, + { + title: 'Ghostly', + description: 'A divine template/print formatter engine', + preview: require('./showcase/ghostly.png'), + website: 'https://divine-software.github.io/ghostly/', + source: 'https://github.com/Divine-Software/ghostly/tree/master/website', + tags: ['opensource'], + }, { title: 'Gladys Assistant', description: 'A privacy-first, open-source home assistant', From 4957ec947b24d5fa6152d114b393c545b87c463b Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sat, 26 Mar 2022 22:49:50 +0800 Subject: [PATCH 081/405] refactor: fix a few places of path handling (#7023) --- packages/docusaurus-plugin-content-blog/src/feed.ts | 6 +----- .../src/__tests__/cli.test.ts | 2 +- packages/docusaurus-plugin-content-docs/src/cli.ts | 4 ++-- .../src/sidebars/generator.ts | 4 ++-- packages/docusaurus-utils/src/dataFileUtils.ts | 2 +- packages/docusaurus/src/commands/serve.ts | 4 +--- packages/docusaurus/src/server/translations/translations.ts | 2 +- 7 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index f9053bec3417..fa546fbf0f18 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -9,7 +9,6 @@ import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed'; import type {BlogPost} from './types'; import { normalizeUrl, - posixPath, mapAsyncSequential, readOutputHTMLFile, } from '@docusaurus/utils'; @@ -128,10 +127,7 @@ async function createBlogFeedFile({ } })(); try { - await fs.outputFile( - posixPath(path.join(generatePath, feedPath)), - feedContent, - ); + await fs.outputFile(path.join(generatePath, feedPath), feedContent); } catch (err) { throw new Error(`Generating ${feedType} feed failed: ${err}.`); } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 8ca46aeb8195..22aeed790cb9 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -181,7 +181,7 @@ describe('docsVersion', () => { DEFAULT_OPTIONS, ), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[docs]: there is no docs to version!"`, + `"[docs]: no docs found in <PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs."`, ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index 2aaceff79b2d..710a5c3d7c67 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -117,7 +117,7 @@ export async function cliDocsVersionCommand( const {path: docsPath, sidebarPath} = options; // Copy docs files. - const docsDir = path.join(siteDir, docsPath); + const docsDir = path.resolve(siteDir, docsPath); if ( (await fs.pathExists(docsDir)) && @@ -127,7 +127,7 @@ export async function cliDocsVersionCommand( const newVersionDir = path.join(versionedDir, `version-${version}`); await fs.copy(docsDir, newVersionDir); } else { - throw new Error(`${pluginIdLogPrefix}: there is no docs to version!`); + throw new Error(`${pluginIdLogPrefix}: no docs found in ${docsDir}.`); } await createVersionedSidebarFile({ diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts index 928731fc4fc5..4642897f3df4 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/generator.ts @@ -14,7 +14,7 @@ import type { SidebarItemCategoryLinkConfig, } from './types'; import _ from 'lodash'; -import {addTrailingSlash, posixPath} from '@docusaurus/utils'; +import {addTrailingSlash} from '@docusaurus/utils'; import logger from '@docusaurus/logger'; import path from 'path'; import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs'; @@ -157,7 +157,7 @@ Available doc IDs: folderName: string, ): WithPosition<NormalizedSidebarItemCategory> { const categoryMetadata = - categoriesMetadata[posixPath(path.join(autogenDir, fullPath))]; + categoriesMetadata[path.posix.join(autogenDir, fullPath)]; const allItems = Object.entries(dir).map(([key, content]) => dirToItem(content, key, `${fullPath}/${key}`), ); diff --git a/packages/docusaurus-utils/src/dataFileUtils.ts b/packages/docusaurus-utils/src/dataFileUtils.ts index 58fc8151165e..34ed9befeb83 100644 --- a/packages/docusaurus-utils/src/dataFileUtils.ts +++ b/packages/docusaurus-utils/src/dataFileUtils.ts @@ -37,7 +37,7 @@ export async function getDataFilePath({ filePath, ); if (contentPath) { - return path.join(contentPath, filePath); + return path.resolve(contentPath, filePath); } return undefined; } diff --git a/packages/docusaurus/src/commands/serve.ts b/packages/docusaurus/src/commands/serve.ts index 72f79bc06fbe..eed951fda525 100644 --- a/packages/docusaurus/src/commands/serve.ts +++ b/packages/docusaurus/src/commands/serve.ts @@ -18,9 +18,7 @@ export default async function serve( siteDir: string, cliOptions: ServeCLIOptions, ): Promise<void> { - let dir = path.isAbsolute(cliOptions.dir) - ? cliOptions.dir - : path.join(siteDir, cliOptions.dir); + let dir = path.resolve(siteDir, cliOptions.dir); if (cliOptions.build) { dir = await build( diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index 0cd6b0b37313..ba749f0aeff5 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -145,7 +145,7 @@ Maybe you should remove them? ${unknownKeys}`; // should we make this configurable? function getTranslationsDirPath(context: TranslationContext): string { - return path.resolve(path.join(context.siteDir, I18N_DIR_NAME)); + return path.join(context.siteDir, I18N_DIR_NAME); } export function getTranslationsLocaleDirPath( context: TranslationContext, From 50e38ec4c9eb556308bc6b229149358c17307b1d Mon Sep 17 00:00:00 2001 From: Viktor Chernodub <37013688+chernodub@users.noreply.github.com> Date: Sun, 27 Mar 2022 05:38:34 +0700 Subject: [PATCH 082/405] fix(theme-classic): adjust shadow on code block (#7013) * fix(theme-classic): adjust shadow on code block * More refactoring Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com> --- .../src/theme/CodeBlock/styles.module.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index 02e1e686768f..c74136412f0e 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -8,13 +8,14 @@ .codeBlockContainer { margin-bottom: var(--ifm-leading); box-shadow: var(--ifm-global-shadow-lw); + border-radius: var(--ifm-code-border-radius); } .codeBlockContent { position: relative; /* rtl:ignore */ direction: ltr; - border-radius: var(--ifm-global-radius); + border-radius: inherit; } .codeBlockTitle { @@ -22,8 +23,8 @@ font-size: var(--ifm-code-font-size); font-weight: 500; padding: 0.75rem var(--ifm-pre-padding); - border-top-left-radius: var(--ifm-global-radius); - border-top-right-radius: var(--ifm-global-radius); + border-top-left-radius: inherit; + border-top-right-radius: inherit; } .codeBlock { From b842197ac63895fea0cf4409e0751bf282a6cf84 Mon Sep 17 00:00:00 2001 From: Leedom <30711792+leedom92@users.noreply.github.com> Date: Sun, 27 Mar 2022 09:55:12 +0800 Subject: [PATCH 083/405] docs: consistently use sidebars.js filename (#7016) * modify sidebar.js to sidebars.js in installation.md * modify sidebar.js to sidebars.js Co-authored-by: leedom <leedom@jinlanzuan.com> --- website/docs/guides/docs/versioning.md | 2 +- website/docs/installation.md | 2 +- .../version-2.0.0-beta.17/guides/docs/versioning.md | 2 +- website/versioned_docs/version-2.0.0-beta.17/installation.md | 2 +- .../version-2.0.0-beta.18/guides/docs/versioning.md | 2 +- website/versioned_docs/version-2.0.0-beta.18/installation.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/guides/docs/versioning.md b/website/docs/guides/docs/versioning.md index 0e519937c721..40eb0a2f23ac 100644 --- a/website/docs/guides/docs/versioning.md +++ b/website/docs/guides/docs/versioning.md @@ -110,7 +110,7 @@ When tagging a new version, the document versioning mechanism will: docs/new.md # Edit the corresponding sidebar file. -sidebar.js +sidebars.js ``` </TabItem> diff --git a/website/docs/installation.md b/website/docs/installation.md index ceee8a5df6c8..944f9f8c2d77 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -140,7 +140,7 @@ my-website - `/static/` - Static directory. Any contents inside here will be copied into the root of the final `build` directory - `/docusaurus.config.js` - A config file containing the site configuration. This is the equivalent of `siteConfig.js` in Docusaurus v1 - `/package.json` - A Docusaurus website is a React app. You can install and use any npm packages you like in them -- `/sidebar.js` - Used by the documentation to specify the order of documents in the sidebar +- `/sidebars.js` - Used by the documentation to specify the order of documents in the sidebar ### Monorepos {#monorepos} diff --git a/website/versioned_docs/version-2.0.0-beta.17/guides/docs/versioning.md b/website/versioned_docs/version-2.0.0-beta.17/guides/docs/versioning.md index 0e519937c721..40eb0a2f23ac 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/guides/docs/versioning.md +++ b/website/versioned_docs/version-2.0.0-beta.17/guides/docs/versioning.md @@ -110,7 +110,7 @@ When tagging a new version, the document versioning mechanism will: docs/new.md # Edit the corresponding sidebar file. -sidebar.js +sidebars.js ``` </TabItem> diff --git a/website/versioned_docs/version-2.0.0-beta.17/installation.md b/website/versioned_docs/version-2.0.0-beta.17/installation.md index 0a79f9b3f7cb..0ea389caa8b2 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/installation.md +++ b/website/versioned_docs/version-2.0.0-beta.17/installation.md @@ -144,7 +144,7 @@ my-website - `/static/` - Static directory. Any contents inside here will be copied into the root of the final `build` directory - `/docusaurus.config.js` - A config file containing the site configuration. This is the equivalent of `siteConfig.js` in Docusaurus v1 - `/package.json` - A Docusaurus website is a React app. You can install and use any npm packages you like in them -- `/sidebar.js` - Used by the documentation to specify the order of documents in the sidebar +- `/sidebars.js` - Used by the documentation to specify the order of documents in the sidebar ### Monorepos {#monorepos} diff --git a/website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md index 0e519937c721..40eb0a2f23ac 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/docs/versioning.md @@ -110,7 +110,7 @@ When tagging a new version, the document versioning mechanism will: docs/new.md # Edit the corresponding sidebar file. -sidebar.js +sidebars.js ``` </TabItem> diff --git a/website/versioned_docs/version-2.0.0-beta.18/installation.md b/website/versioned_docs/version-2.0.0-beta.18/installation.md index ceee8a5df6c8..944f9f8c2d77 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/installation.md +++ b/website/versioned_docs/version-2.0.0-beta.18/installation.md @@ -140,7 +140,7 @@ my-website - `/static/` - Static directory. Any contents inside here will be copied into the root of the final `build` directory - `/docusaurus.config.js` - A config file containing the site configuration. This is the equivalent of `siteConfig.js` in Docusaurus v1 - `/package.json` - A Docusaurus website is a React app. You can install and use any npm packages you like in them -- `/sidebar.js` - Used by the documentation to specify the order of documents in the sidebar +- `/sidebars.js` - Used by the documentation to specify the order of documents in the sidebar ### Monorepos {#monorepos} From 2bcac29cd4a8a62f975d530a3ff609417eb710c5 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sun, 27 Mar 2022 12:57:15 +0800 Subject: [PATCH 084/405] refactor(content-docs): deduplicate types, JSDoc for some APIs (#7027) * refactor(content-docs): deduplicate types, JSDoc for some APIs * little refactor --- packages/docusaurus-mdx-loader/src/index.ts | 6 +- .../docusaurus-mdx-loader/src/mdx-loader.d.ts | 12 +- .../src/plugin-content-blog.d.ts | 63 +-- .../__snapshots__/translations.test.ts.snap | 12 +- .../src/__tests__/docs.test.ts | 16 +- .../src/__tests__/frontMatter.test.ts | 2 +- .../src/__tests__/globalData.test.ts | 10 +- .../src/__tests__/props.test.ts | 4 +- .../src/__tests__/translations.test.ts | 27 +- .../src/__tests__/versions.test.ts | 150 +++--- .../src/categoryGeneratedIndex.ts | 11 +- .../src/docs.ts | 30 +- .../src/frontMatter.ts | 2 +- .../src/globalData.ts | 8 +- .../src/index.ts | 16 +- .../src/markdown/__tests__/linkify.test.ts | 2 +- .../src/markdown/linkify.ts | 5 +- .../src/plugin-content-docs.d.ts | 443 +++++++++++++++--- .../src/props.ts | 15 +- .../src/routes.ts | 36 +- .../sidebars/__tests__/postProcessor.test.ts | 10 +- .../src/sidebars/__tests__/processor.test.ts | 2 +- .../src/sidebars/__tests__/utils.test.ts | 13 +- .../src/sidebars/postProcessor.ts | 2 +- .../src/sidebars/processor.ts | 5 +- .../src/sidebars/types.ts | 26 +- .../src/sidebars/utils.ts | 9 +- .../src/slug.ts | 6 +- .../src/tags.ts | 5 +- .../src/translations.ts | 5 +- .../src/types.ts | 105 +---- .../src/versions.ts | 69 ++- .../src/plugin-content-pages.d.ts | 4 +- .../src/theme-classic.d.ts | 7 + .../src/theme/DocItem/index.tsx | 2 +- .../docusaurus-theme-classic/src/types.d.ts | 11 - .../src/types.d.ts | 1 + .../docs/api/plugins/plugin-content-docs.md | 84 ++-- 38 files changed, 715 insertions(+), 521 deletions(-) delete mode 100644 packages/docusaurus-theme-classic/src/types.d.ts diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index ae3336d169a1..34cea4978d23 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -21,21 +21,21 @@ import toc from './remark/toc'; import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks'; import transformImage from './remark/transformImage'; import transformLinks from './remark/transformLinks'; -import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; +import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {LoaderContext} from 'webpack'; const { loaders: {inlineMarkdownImageFileLoader}, } = getFileLoaderUtils(); -const DEFAULT_OPTIONS: RemarkAndRehypePluginOptions = { +const DEFAULT_OPTIONS: MDXOptions = { rehypePlugins: [], remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc], beforeDefaultRemarkPlugins: [], beforeDefaultRehypePlugins: [], }; -type Options = RemarkAndRehypePluginOptions & { +type Options = MDXOptions & { staticDirs: string[]; siteDir: string; isMDXPartial?: (filePath: string) => boolean; diff --git a/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts b/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts index e1fff7113ef8..c84168aefdbd 100644 --- a/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts +++ b/packages/docusaurus-mdx-loader/src/mdx-loader.d.ts @@ -7,12 +7,12 @@ import type {Plugin} from 'unified'; -export type RemarkOrRehypePlugin = +export type MDXPlugin = // eslint-disable-next-line @typescript-eslint/no-explicit-any [Plugin<any[]>, any] | Plugin<any[]>; -export type RemarkAndRehypePluginOptions = { - remarkPlugins: RemarkOrRehypePlugin[]; - rehypePlugins: RemarkOrRehypePlugin[]; - beforeDefaultRemarkPlugins: RemarkOrRehypePlugin[]; - beforeDefaultRehypePlugins: RemarkOrRehypePlugin[]; +export type MDXOptions = { + remarkPlugins: MDXPlugin[]; + rehypePlugins: MDXPlugin[]; + beforeDefaultRemarkPlugins: MDXPlugin[]; + beforeDefaultRehypePlugins: MDXPlugin[]; }; diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index 10e4fd654752..e7fd5a65ab88 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -6,8 +6,8 @@ */ declare module '@docusaurus/plugin-content-blog' { - import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; - import type {FrontMatterTag} from '@docusaurus/utils'; + import type {MDXOptions} from '@docusaurus/mdx-loader'; + import type {FrontMatterTag, Tag} from '@docusaurus/utils'; import type {Overwrite} from 'utility-types'; export interface Assets { @@ -81,10 +81,7 @@ declare module '@docusaurus/plugin-content-blog' { * @see {@link BlogPostMetadata.tags} */ tags?: FrontMatterTag[]; - /** - * Custom slug appended after /<baseUrl>/<routeBasePath>/ - * @see {@link BlogPostMetadata.slug} - */ + /** Custom slug appended after `/<baseUrl>/<routeBasePath>/` */ slug?: string; /** * Marks the post as draft and excludes it from the production build. @@ -130,25 +127,18 @@ declare module '@docusaurus/plugin-content-blog' { /** @deprecated v1 legacy */ authorImageURL?: string; - /** - * @see {@link BlogPostMetadata.image} - */ + /** Used in the head meta. Should use `assets.image` in priority. */ image?: string; - /** - * Used in the head meta - */ + /** Used in the head meta. */ keywords?: string[]; - /** - * Hide the right TOC - */ + /** Hide the right TOC. */ hide_table_of_contents?: boolean; /** - * Minimum TOC heading level + * Minimum TOC heading level. Must be between 2 and 6 and lower or equal to + * the max value. */ toc_min_heading_level?: number; - /** - * Maximum TOC heading level - */ + /** Maximum TOC heading level. Must be between 2 and 6. */ toc_max_heading_level?: number; }; @@ -175,9 +165,7 @@ declare module '@docusaurus/plugin-content-blog' { | (string | BlogPostFrontMatterAuthor)[]; export type BlogPostMetadata = { - /** - * Path to the Markdown source, with `@site` alias. - */ + /** Path to the Markdown source, with `@site` alias. */ readonly source: string; /** * Used to generate the page h1 heading, tab title, and pagination title. @@ -193,9 +181,7 @@ declare module '@docusaurus/plugin-content-blog' { * render the date regardless of the existence of `Intl.DateTimeFormat`. */ readonly formattedDate: string; - /** - * Full link including base URL. - */ + /** Full link including base URL. */ readonly permalink: string; /** * Description used in the meta. Could be an empty string (empty content) @@ -229,17 +215,10 @@ declare module '@docusaurus/plugin-content-blog' { * `assets.authorsImageUrls` on client side. */ readonly authors: Author[]; - /** - * Front matter, as-is. - */ + /** Front matter, as-is. */ readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown}; - /** - * Tags, normalized. - */ - readonly tags: readonly { - readonly label: string; - readonly permalink: string; - }[]; + /** Tags, normalized. */ + readonly tags: Tag[]; }; /** * @returns The edit URL that's directly plugged into metadata. @@ -250,17 +229,11 @@ declare module '@docusaurus/plugin-content-blog' { * site path. Usually the same as `options.path` but can be localized */ blogDirPath: string; - /** - * Path to this post file, relative to `blogDirPath` - */ + /** Path to this post file, relative to `blogDirPath`. */ blogPath: string; - /** - * @see {@link BlogPostMetadata.permalink} - */ + /** @see {@link BlogPostMetadata.permalink} */ permalink: string; - /** - * Locale name. - */ + /** Locale name. */ locale: string; }) => string | undefined; @@ -325,7 +298,7 @@ declare module '@docusaurus/plugin-content-blog' { /** * Plugin options after normalization. */ - export type PluginOptions = RemarkAndRehypePluginOptions & { + export type PluginOptions = MDXOptions & { /** Plugin ID. */ id?: string; /** diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap index 30c85bc511e0..a67e0081748c 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap @@ -169,7 +169,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], "isLast": true, + "label": "current label (translated)", "mainDocId": "", + "path": "/docs/", "routePriority": undefined, "sidebarFilePath": "any", "sidebars": { @@ -221,9 +223,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], }, - "versionLabel": "current label (translated)", "versionName": "current", - "versionPath": "/docs/", }, { "contentPath": "any", @@ -311,7 +311,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], "isLast": true, + "label": "2.0.0 label (translated)", "mainDocId": "", + "path": "/docs/", "routePriority": undefined, "sidebarFilePath": "any", "sidebars": { @@ -363,9 +365,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], }, - "versionLabel": "2.0.0 label (translated)", "versionName": "2.0.0", - "versionPath": "/docs/", }, { "contentPath": "any", @@ -453,7 +453,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], "isLast": true, + "label": "1.0.0 label (translated)", "mainDocId": "", + "path": "/docs/", "routePriority": undefined, "sidebarFilePath": "any", "sidebars": { @@ -505,9 +507,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` }, ], }, - "versionLabel": "1.0.0 label (translated)", "versionName": "1.0.0", - "versionPath": "/docs/", }, ], } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 730e3d787e54..b7aa5cfe178b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -18,16 +18,14 @@ import { import {loadSidebars} from '../sidebars'; import type {Sidebars} from '../sidebars/types'; import {readVersionsMetadata} from '../versions'; -import type { - DocFile, - DocMetadataBase, - VersionMetadata, - DocNavLink, -} from '../types'; +import type {DocFile} from '../types'; import type { MetadataOptions, PluginOptions, EditUrlFunction, + DocMetadataBase, + VersionMetadata, + PropNavigationLink, } from '@docusaurus/plugin-content-docs'; import type {LoadContext} from '@docusaurus/types'; import {DEFAULT_OPTIONS} from '../options'; @@ -123,7 +121,11 @@ function createTestUtils({ } async function generateNavigation(docFiles: DocFile[]): Promise<{ - pagination: {prev?: DocNavLink; next?: DocNavLink; id: string}[]; + pagination: { + prev?: PropNavigationLink; + next?: PropNavigationLink; + id: string; + }[]; sidebars: Sidebars; }> { const rawDocs = docFiles.map((docFile) => diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index 734e7e0bbf49..7e295afb0cb0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -6,7 +6,7 @@ */ import {validateDocFrontMatter} from '../frontMatter'; -import type {DocFrontMatter} from '../types'; +import type {DocFrontMatter} from '@docusaurus/plugin-content-docs'; import escapeStringRegexp from 'escape-string-regexp'; function testField(params: { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts index 4c1cac6ecdcc..2c9a02966317 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts @@ -12,9 +12,9 @@ describe('toGlobalDataVersion', () => { expect( toGlobalDataVersion({ versionName: 'current', - versionLabel: 'Label', + label: 'Label', isLast: true, - versionPath: '/current', + path: '/current', mainDocId: 'main', docs: [ { @@ -86,9 +86,9 @@ describe('toGlobalDataVersion', () => { sidebar: 'tutorial', }, ], - versionBanner: 'unreleased', - versionBadge: true, - versionClassName: 'current-cls', + banner: 'unreleased', + badge: true, + className: 'current-cls', tagsPath: '/current/tags', contentPath: '', contentPathLocalized: '', diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts index 508913d6dd13..86bd7b88fc27 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts @@ -16,7 +16,7 @@ describe('toTagDocListProp', () => { it('works', () => { const tag: Tag = { - name: 'tag1', + label: 'tag1', permalink: '/tag1', docIds: ['id1', 'id3'], }; @@ -54,7 +54,7 @@ describe('toTagDocListProp', () => { expect(result).toEqual({ allTagsPath, - name: tag.name, + name: tag.label, permalink: tag.permalink, docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index b4ca8cf72b75..85af2ef203e0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -5,12 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -import type {LoadedContent, DocMetadata, LoadedVersion} from '../types'; +import type {LoadedContent, LoadedVersion} from '../types'; import {CURRENT_VERSION_NAME} from '../constants'; import { getLoadedContentTranslationFiles, translateLoadedContent, } from '../translations'; +import type {DocMetadata} from '@docusaurus/plugin-content-docs'; import {updateTranslationFileMessages} from '@docusaurus/utils'; function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata { @@ -36,8 +37,8 @@ function createSampleVersion( version: Pick<LoadedVersion, 'versionName'>, ): LoadedVersion { return { - versionLabel: `${version.versionName} label`, - versionPath: '/docs/', + label: `${version.versionName} label`, + path: '/docs/', mainDocId: '', routePriority: undefined, sidebarFilePath: 'any', @@ -45,21 +46,11 @@ function createSampleVersion( contentPath: 'any', contentPathLocalized: 'any', docs: [ - createSampleDoc({ - id: 'doc1', - }), - createSampleDoc({ - id: 'doc2', - }), - createSampleDoc({ - id: 'doc3', - }), - createSampleDoc({ - id: 'doc4', - }), - createSampleDoc({ - id: 'doc5', - }), + createSampleDoc({id: 'doc1'}), + createSampleDoc({id: 'doc2'}), + createSampleDoc({id: 'doc3'}), + createSampleDoc({id: 'doc4'}), + createSampleDoc({id: 'doc5'}), ], sidebars: { docs: [ diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index 9e5f2e483160..5209f7dfea05 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -15,9 +15,11 @@ import { } from '../versions'; import {DEFAULT_OPTIONS} from '../options'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; -import type {VersionMetadata} from '../types'; import type {I18n} from '@docusaurus/types'; -import type {PluginOptions} from '@docusaurus/plugin-content-docs'; +import type { + PluginOptions, + VersionMetadata, +} from '@docusaurus/plugin-content-docs'; const DefaultI18N: I18n = { currentLocale: 'en', @@ -85,12 +87,12 @@ describe('readVersionsMetadata', () => { routePriority: -1, sidebarFilePath: undefined, tagsPath: '/docs/tags', - versionLabel: 'Next', + label: 'Next', versionName: 'current', - versionPath: '/docs', - versionBanner: null, - versionBadge: false, - versionClassName: 'docs-version-current', + path: '/docs', + banner: null, + badge: false, + className: 'docs-version-current', }; return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; } @@ -120,7 +122,7 @@ describe('readVersionsMetadata', () => { expect(versionsMetadata).toEqual([ { ...vCurrent, - versionPath: '/myBaseUrl/docs', + path: '/myBaseUrl/docs', tagsPath: '/myBaseUrl/docs/tags', }, ]); @@ -148,13 +150,13 @@ describe('readVersionsMetadata', () => { expect(versionsMetadata).toEqual([ { ...vCurrent, - versionPath: '/myBaseUrl/docs/current-path', - versionLabel: 'current-label', + path: '/myBaseUrl/docs/current-path', + label: 'current-label', routePriority: undefined, sidebarFilePath: undefined, tagsPath: '/myBaseUrl/docs/current-path/tags', - versionEditUrl: undefined, - versionEditUrlLocalized: undefined, + editUrl: undefined, + editUrlLocalized: undefined, }, ]); }); @@ -245,12 +247,12 @@ describe('readVersionsMetadata', () => { routePriority: undefined, sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), tagsPath: '/docs/next/tags', - versionLabel: 'Next', + label: 'Next', versionName: 'current', - versionPath: '/docs/next', - versionBanner: 'unreleased', - versionBadge: true, - versionClassName: 'docs-version-current', + path: '/docs/next', + banner: 'unreleased', + badge: true, + className: 'docs-version-current', }; const v101: VersionMetadata = { @@ -269,12 +271,12 @@ describe('readVersionsMetadata', () => { 'versioned_sidebars/version-1.0.1-sidebars.json', ), tagsPath: '/docs/tags', - versionLabel: '1.0.1', + label: '1.0.1', versionName: '1.0.1', - versionPath: '/docs', - versionBanner: null, - versionBadge: true, - versionClassName: 'docs-version-1.0.1', + path: '/docs', + banner: null, + badge: true, + className: 'docs-version-1.0.1', }; const v100: VersionMetadata = { @@ -293,12 +295,12 @@ describe('readVersionsMetadata', () => { 'versioned_sidebars/version-1.0.0-sidebars.json', ), tagsPath: '/docs/1.0.0/tags', - versionLabel: '1.0.0', + label: '1.0.0', versionName: '1.0.0', - versionPath: '/docs/1.0.0', - versionBanner: 'unmaintained', - versionBadge: true, - versionClassName: 'docs-version-1.0.0', + path: '/docs/1.0.0', + banner: 'unmaintained', + badge: true, + className: 'docs-version-1.0.0', }; const vWithSlugs: VersionMetadata = { @@ -317,12 +319,12 @@ describe('readVersionsMetadata', () => { 'versioned_sidebars/version-withSlugs-sidebars.json', ), tagsPath: '/docs/withSlugs/tags', - versionLabel: 'withSlugs', + label: 'withSlugs', versionName: 'withSlugs', - versionPath: '/docs/withSlugs', - versionBanner: 'unmaintained', - versionBadge: true, - versionClassName: 'docs-version-withSlugs', + path: '/docs/withSlugs', + banner: 'unmaintained', + badge: true, + className: 'docs-version-withSlugs', }; return { @@ -393,27 +395,27 @@ describe('readVersionsMetadata', () => { { ...vCurrent, tagsPath: '/docs/current-path/tags', - versionPath: '/docs/current-path', - versionBanner: 'unmaintained', - versionBadge: false, - versionClassName: 'custom-current-className', + path: '/docs/current-path', + banner: 'unmaintained', + badge: false, + className: 'custom-current-className', }, { ...v101, isLast: false, routePriority: undefined, tagsPath: '/docs/1.0.1/tags', - versionPath: '/docs/1.0.1', - versionBanner: 'unreleased', + path: '/docs/1.0.1', + banner: 'unreleased', }, { ...v100, isLast: true, routePriority: -1, tagsPath: '/docs/tags', - versionLabel: '1.0.0-label', - versionPath: '/docs', - versionBanner: 'unreleased', + label: '1.0.0-label', + path: '/docs', + banner: 'unreleased', }, vWithSlugs, ]); @@ -434,30 +436,30 @@ describe('readVersionsMetadata', () => { expect(versionsMetadata).toEqual([ { ...vCurrent, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, { ...v101, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1', }, { ...v100, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0', }, { ...vWithSlugs, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs', }, ]); @@ -479,30 +481,30 @@ describe('readVersionsMetadata', () => { expect(versionsMetadata).toEqual([ { ...vCurrent, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, { ...v101, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, { ...v100, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, { ...vWithSlugs, - versionEditUrl: + editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs', - versionEditUrlLocalized: + editUrlLocalized: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', }, ]); @@ -538,9 +540,9 @@ describe('readVersionsMetadata', () => { isLast: true, routePriority: -1, tagsPath: '/docs/tags', - versionPath: '/docs', - versionBanner: null, - versionBadge: false, + path: '/docs', + banner: null, + badge: false, }, ]); }); @@ -679,12 +681,12 @@ describe('readVersionsMetadata', () => { routePriority: undefined, sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), tagsPath: '/communityBasePath/next/tags', - versionLabel: 'Next', + label: 'Next', versionName: 'current', - versionPath: '/communityBasePath/next', - versionBanner: 'unreleased', - versionBadge: true, - versionClassName: 'docs-version-current', + path: '/communityBasePath/next', + banner: 'unreleased', + badge: true, + className: 'docs-version-current', }; const v100: VersionMetadata = { @@ -703,12 +705,12 @@ describe('readVersionsMetadata', () => { 'community_versioned_sidebars/version-1.0.0-sidebars.json', ), tagsPath: '/communityBasePath/tags', - versionLabel: '1.0.0', + label: '1.0.0', versionName: '1.0.0', - versionPath: '/communityBasePath', - versionBanner: null, - versionBadge: true, - versionClassName: 'docs-version-1.0.0', + path: '/communityBasePath', + banner: null, + badge: true, + className: 'docs-version-1.0.0', }; return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100}; @@ -735,7 +737,7 @@ describe('readVersionsMetadata', () => { expect(versionsMetadata).toEqual([ // vCurrent removed - {...v100, versionBadge: false}, + {...v100, badge: false}, ]); }); @@ -753,9 +755,9 @@ describe('readVersionsMetadata', () => { isLast: true, routePriority: -1, tagsPath: '/communityBasePath/tags', - versionPath: '/communityBasePath', - versionBanner: null, - versionBadge: false, + path: '/communityBasePath', + banner: null, + badge: false, }, ]); }); diff --git a/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts b/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts index b3785f6fe9ec..4c87e711a515 100644 --- a/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts +++ b/packages/docusaurus-plugin-content-docs/src/categoryGeneratedIndex.ts @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import type {CategoryGeneratedIndexMetadata, DocMetadataBase} from './types'; +import type { + CategoryGeneratedIndexMetadata, + DocMetadataBase, +} from '@docusaurus/plugin-content-docs'; import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types'; import {type SidebarsUtils, toNavigationLink} from './sidebars/utils'; import {createDocsByIdIndex} from './docs'; @@ -29,8 +32,10 @@ function getCategoryGeneratedIndexMetadata({ slug: category.link.slug, permalink: category.link.permalink, sidebar: sidebarName!, - previous: toNavigationLink(previous, docsById), - next: toNavigationLink(next, docsById), + navigation: { + previous: toNavigationLink(previous, docsById), + next: toNavigationLink(next, docsById), + }, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 631daef5f73e..ee247ec0a97a 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -12,6 +12,7 @@ import { aliasedSitePath, getEditUrl, getFolderContainingFile, + getContentPathList, normalizeUrl, parseMarkdownString, posixPath, @@ -21,18 +22,9 @@ import { import type {LoadContext} from '@docusaurus/types'; import {getFileLastUpdate} from './lastUpdate'; -import type { - DocFile, - DocMetadataBase, - DocMetadata, - DocNavLink, - LastUpdateData, - VersionMetadata, - LoadedVersion, -} from './types'; +import type {DocFile, LoadedVersion} from './types'; import getSlug from './slug'; import {CURRENT_VERSION_NAME} from './constants'; -import {getDocsDirPaths} from './versions'; import {stripPathNumberPrefixes} from './numberPrefix'; import {validateDocFrontMatter} from './frontMatter'; import type {SidebarsUtils} from './sidebars/utils'; @@ -41,7 +33,11 @@ import type { MetadataOptions, PluginOptions, CategoryIndexMatcher, - CategoryIndexMatcherParam, + DocMetadataBase, + DocMetadata, + PropNavigationLink, + LastUpdateData, + VersionMetadata, } from '@docusaurus/plugin-content-docs'; type LastUpdateOptions = Pick< @@ -85,7 +81,7 @@ export async function readDocFile( options: LastUpdateOptions, ): Promise<DocFile> { const contentPath = await getFolderContainingFile( - getDocsDirPaths(versionMetadata), + getContentPathList(versionMetadata), source, ); @@ -213,7 +209,7 @@ function doProcessDocMetadata({ const description: string = frontMatter.description ?? excerpt ?? ''; - const permalink = normalizeUrl([versionMetadata.versionPath, docSlug]); + const permalink = normalizeUrl([versionMetadata.path, docSlug]); function getDocEditUrl() { const relativeFilePath = path.relative(contentPath, filePath); @@ -232,8 +228,8 @@ function doProcessDocMetadata({ const isLocalized = contentPath === versionMetadata.contentPathLocalized; const baseVersionEditUrl = isLocalized && options.editLocalizedFiles - ? versionMetadata.versionEditUrlLocalized - : versionMetadata.versionEditUrl; + ? versionMetadata.editUrlLocalized + : versionMetadata.editUrl; return getEditUrl(relativeFilePath, baseVersionEditUrl); } return undefined; @@ -304,7 +300,7 @@ export function addDocNavigation( const toNavigationLinkByDocId = ( docId: string | null | undefined, type: 'prev' | 'next', - ): DocNavLink | undefined => { + ): PropNavigationLink | undefined => { if (!docId) { return undefined; } @@ -401,7 +397,7 @@ export function toCategoryIndexMatcherParam({ }: Pick< DocMetadataBase, 'source' | 'sourceDirName' ->): CategoryIndexMatcherParam { +>): Parameters<CategoryIndexMatcher>[0] { // source + sourceDirName are always posix-style return { fileName: path.posix.parse(source).name, diff --git a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts index fe53b0573dec..52e5af68b383 100644 --- a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts @@ -12,7 +12,7 @@ import { FrontMatterTOCHeadingLevels, validateFrontMatter, } from '@docusaurus/utils-validation'; -import type {DocFrontMatter} from './types'; +import type {DocFrontMatter} from '@docusaurus/plugin-content-docs'; // NOTE: we don't add any default value on purpose here // We don't want default values to magically appear in doc metadata and props diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index 302fb77328de..ebeb61c8228e 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -8,11 +8,11 @@ import _ from 'lodash'; import type {Sidebars} from './sidebars/types'; import {createSidebarsUtils} from './sidebars/utils'; +import type {LoadedVersion} from './types'; import type { CategoryGeneratedIndexMetadata, DocMetadata, - LoadedVersion, -} from './types'; +} from '@docusaurus/plugin-content-docs'; import type { GlobalVersion, GlobalSidebar, @@ -65,9 +65,9 @@ function toGlobalSidebars( export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion { return { name: version.versionName, - label: version.versionLabel, + label: version.label, isLast: version.isLast, - path: version.versionPath, + path: version.path, mainDocId: version.mainDocId, docs: version.docs .map(toGlobalDataDoc) diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 4b659f48fa57..ed35fa390c55 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -11,6 +11,7 @@ import { normalizeUrl, docuHash, aliasedSitePath, + getContentPathList, reportMessage, posixPath, addTrailingPathSeparator, @@ -27,18 +28,14 @@ import { addDocNavigation, getMainDocId, } from './docs'; -import {getDocsDirPaths, readVersionsMetadata} from './versions'; - +import {readVersionsMetadata} from './versions'; import type { LoadedContent, SourceToPermalink, - DocMetadataBase, - VersionMetadata, LoadedVersion, DocFile, DocsMarkdownOption, VersionTag, - DocFrontMatter, } from './types'; import type {RuleSetRule} from 'webpack'; import {cliDocsVersionCommand} from './cli'; @@ -55,6 +52,9 @@ import {createVersionRoutes} from './routes'; import type { PropTagsListPage, PluginOptions, + DocMetadataBase, + VersionMetadata, + DocFrontMatter, } from '@docusaurus/plugin-content-docs'; import {createSidebarsUtils} from './sidebars/utils'; import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex'; @@ -114,7 +114,7 @@ export default async function pluginContentDocs( function getVersionPathsToWatch(version: VersionMetadata): string[] { const result = [ ...options.include.flatMap((pattern) => - getDocsDirPaths(version).map( + getContentPathList(version).map( (docsDirPath) => `${docsDirPath}/${pattern}`, ), ), @@ -228,7 +228,7 @@ export default async function pluginContentDocs( const tagsProp: PropTagsListPage['tags'] = Object.values( versionTags, ).map((tagValue) => ({ - name: tagValue.name, + name: tagValue.label, permalink: tagValue.permalink, count: tagValue.docIds.length, })); @@ -331,7 +331,7 @@ export default async function pluginContentDocs( }; function createMDXLoaderRule(): RuleSetRule { - const contentDirs = versionsMetadata.flatMap(getDocsDirPaths); + const contentDirs = versionsMetadata.flatMap(getContentPathList); return { test: /\.mdx?$/i, include: contentDirs diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index c6e5bb9ac52b..f106ea6edb9d 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -12,9 +12,9 @@ import {linkify} from '../linkify'; import type { DocsMarkdownOption, SourceToPermalink, - VersionMetadata, DocBrokenMarkdownLink, } from '../../types'; +import type {VersionMetadata} from '@docusaurus/plugin-content-docs'; import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants'; function createFakeVersion({ diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts index 39e45e8f399e..704bcbd4974f 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/linkify.ts @@ -6,12 +6,11 @@ */ import type {DocsMarkdownOption} from '../types'; -import {getDocsDirPaths} from '../versions'; -import {replaceMarkdownLinks} from '@docusaurus/utils'; +import {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils'; function getVersion(filePath: string, options: DocsMarkdownOption) { const versionFound = options.versionsMetadata.find((version) => - getDocsDirPaths(version).some((docsDirPath) => + getContentPathList(version).some((docsDirPath) => filePath.startsWith(docsDirPath), ), ); diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 7c807019c7ea..40aad894e8b6 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -6,18 +6,25 @@ */ declare module '@docusaurus/plugin-content-docs' { - import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; + import type {MDXOptions} from '@docusaurus/mdx-loader'; + import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils'; + import type {Required} from 'utility-types'; export interface Assets { image?: string; } + /** + * Custom callback for parsing number prefixes from file/folder names. + */ export type NumberPrefixParser = (filename: string) => { + /** file name without number prefix, without any other modification. */ filename: string; + /** The number prefix. Can be float, integer, negative, or anything. */ numberPrefix?: number; }; - export type CategoryIndexMatcherParam = { + export type CategoryIndexMatcher = (param: { /** The file name, without extension */ fileName: string; /** @@ -27,110 +34,442 @@ declare module '@docusaurus/plugin-content-docs' { directories: string[]; /** The extension, with a leading dot */ extension: string; - }; - export type CategoryIndexMatcher = ( - param: CategoryIndexMatcherParam, - ) => boolean; + }) => boolean; export type EditUrlFunction = (editUrlParams: { + /** Name of the version. */ version: string; + /** + * Path of the version's root content path, relative to the site directory. + * Usually the same as `options.path` but can be localized or versioned. + */ versionDocsDirPath: string; + /** Path of the doc file, relative to `versionDocsDirPath`. */ docPath: string; + /** @see {@link DocMetadata.permalink} */ permalink: string; + /** Locale name. */ locale: string; }) => string | undefined; export type MetadataOptions = { + /** + * URL route for the docs section of your site. **DO NOT** include a + * trailing slash. Use `/` for shipping docs without base path. + */ routeBasePath: string; + /** + * Base URL to edit your site. The final URL is computed by `editUrl + + * relativeDocPath`. Using a function allows more nuanced control for each + * file. Omitting this variable entirely will disable edit links. + */ editUrl?: string | EditUrlFunction; + /** + * The edit URL will always target the current version doc instead of older + * versions. Ignored when `editUrl` is a function. + */ editCurrentVersion: boolean; + /** + * The edit URL will target the localized file, instead of the original + * unlocalized file. Ignored when `editUrl` is a function. + */ editLocalizedFiles: boolean; + /** Whether to display the last date the doc was updated. */ showLastUpdateTime?: boolean; + /** Whether to display the author who last updated the doc. */ showLastUpdateAuthor?: boolean; + /** + * Custom parsing logic to extract number prefixes from file names. Use + * `false` to disable this behavior and leave the docs untouched, and `true` + * to use the default parser. + * + * @param filename One segment of the path, without any slashes. + * @see https://docusaurus.io/docs/sidebar#using-number-prefixes + */ numberPrefixParser: NumberPrefixParser; + /** Enable or disable the breadcrumbs on doc pages. */ breadcrumbs: boolean; }; export type PathOptions = { + /** + * Path to the docs content directory on the file system, relative to site + * directory. + */ path: string; + /** + * Path to sidebar configuration. Use `false` to disable sidebars, or + * `undefined` to create a fully autogenerated sidebar. + */ sidebarPath?: string | false | undefined; }; // TODO support custom version banner? // {type: "error", content: "html content"} export type VersionBanner = 'unreleased' | 'unmaintained'; - export type VersionOptions = { - path?: string; - label?: string; - banner?: 'none' | VersionBanner; - badge?: boolean; - className?: string; - }; export type VersionsOptions = { + /** + * The version navigated to in priority and displayed by default for docs + * navbar items. + * + * @see https://docusaurus.io/docs/versioning#terminology + */ lastVersion?: string; - versions: {[versionName: string]: VersionOptions}; + /** Only include a subset of all available versions. */ onlyIncludeVersions?: string[]; + /** + * Explicitly disable versioning even when multiple versions exist. This + * will make the site only include the current version. Will error if + * `includeCurrentVersion: false` and `disableVersioning: true`. + */ + disableVersioning: boolean; + /** Include the current version of your docs. */ + includeCurrentVersion: boolean; + /** Independent customization of each version's properties. */ + versions: { + [versionName: string]: { + /** + * The base path of the version, will be appended to `baseUrl` + + * `routeBasePath`. + */ + path?: string; + /** The label of the version to be used in badges, dropdowns, etc. */ + label?: string; + /** The banner to show at the top of a doc of that version. */ + banner?: 'none' | VersionBanner; + /** Show a badge with the version label at the top of each doc. */ + badge?: boolean; + /** Add a custom class name to the <html> element of each doc. */ + className?: string; + }; + }; }; export type SidebarOptions = { + /** + * Whether sidebar categories are collapsible by default. + * + * @see https://docusaurus.io/docs/sidebar#collapsible-categories + */ sidebarCollapsible: boolean; + /** + * Whether sidebar categories are collapsed by default. + * + * @see https://docusaurus.io/docs/sidebar#expanded-categories-by-default + */ sidebarCollapsed: boolean; }; export type PluginOptions = MetadataOptions & PathOptions & VersionsOptions & - RemarkAndRehypePluginOptions & + MDXOptions & SidebarOptions & { + /** Plugin ID. */ id: string; + /** + * Array of glob patterns matching Markdown files to be built, relative to + * the content path. + */ include: string[]; + /** + * Array of glob patterns matching Markdown files to be excluded. Serves + * as refinement based on the `include` option. + */ exclude: string[]; + /** + * Root layout component of each doc page. Provides the version data + * context, and is not unmounted when switching docs. + */ docLayoutComponent: string; + /** Main doc container, with TOC, pagination, etc. */ docItemComponent: string; + /** Root component of the "docs containing tag X" page. */ docTagDocListComponent: string; + /** Root component of the tags list page */ docTagsListComponent: string; + /** Root component of the generated category index page. */ docCategoryGeneratedIndexComponent: string; admonitions: {[key: string]: unknown}; - disableVersioning: boolean; - includeCurrentVersion: boolean; sidebarItemsGenerator: import('./sidebars/types').SidebarItemsGeneratorOption; + /** + * URL route for the tags section of your doc version. Will be appended to + * `routeBasePath`. **DO NOT** include a trailing slash. + */ tagsBasePath: string; }; export type Options = Partial<PluginOptions>; export type SidebarsConfig = import('./sidebars/types').SidebarsConfig; + export type VersionMetadata = ContentPaths & { + /** A name like `1.0.0`. Acquired from `versions.json`. */ + versionName: string; + /** Like `Version 1.0.0`. Can be configured through `versions.label`. */ + label: string; + /** + * Version's base path in the form of `/<baseUrl>/<routeBasePath>/1.0.0`. + * Can be configured through `versions.path`. + */ + path: string; + /** Tags base path in the form of `<versionPath>/tags`. */ + tagsPath: string; + /** + * The base URL to which the doc file path will be appended. Will be + * `undefined` if `editUrl` is `undefined` or a function. + */ + editUrl?: string | undefined; + /** + * The base URL to which the localized doc file path will be appended. Will + * be `undefined` if `editUrl` is `undefined` or a function. + */ + editUrlLocalized?: string | undefined; + /** + * "unmaintained" is the version before latest; "unreleased" is the version + * after latest. `null` is the latest version without a banner. Can be + * configured with `versions.banner`: `banner: "none"` will be transformed + * to `null` here. + */ + banner: VersionBanner | null; + /** Show a badge with the version label at the top of each doc. */ + badge: boolean; + /** Add a custom class name to the <html> element of each doc. */ + className: string; + /** + * Whether this version is the "last" version. Can be configured with + * `lastVersion` option. + */ + isLast: boolean; + /** + * Like `versioned_sidebars/1.0.0.json`. Versioned sidebars file may be + * nonexistent since we don't create empty files. + */ + sidebarFilePath: string | false | undefined; + /** + * Will be -1 for the latest docs, and `undefined` for everything else. + * Because `/docs/foo` should always be after `/docs/<versionName>/foo`. + */ + routePriority: number | undefined; + }; + + export type DocFrontMatter = { + /** + * The last part of the doc ID (will be refactored in the future to be the + * full ID instead) + * @see {@link DocMetadata.id} + */ + id?: string; + /** + * Will override the default title collected from h1 heading. + * @see {@link DocMetadata.title} + */ + title?: string; + /** + * Front matter tags, unnormalized. + * @see {@link DocMetadata.tags} + */ + tags?: FrontMatterTag[]; + /** + * If there isn't a Markdown h1 heading (which, if there is, we don't + * remove), this front matter will cause the front matter title to not be + * displayed in the doc page. + */ + hide_title?: boolean; + /** Hide the TOC on the right. */ + hide_table_of_contents?: boolean; + /** Used in the head meta. */ + keywords?: string[]; + /** Used in the head meta. Should use `assets.image` in priority. */ + image?: string; + /** + * Will override the default excerpt. + * @see {@link DocMetadata.description} + */ + description?: string; + /** + * Custom slug appended after /<baseUrl>/<routeBasePath>/<versionPath> + * @see {@link DocMetadata.slug} + */ + slug?: string; + /** Customizes the sidebar label for this doc. Will default to its title. */ + sidebar_label?: string; + /** + * Controls the position of a doc inside the generated sidebar slice when + * using autogenerated sidebar items. + * + * @see https://docusaurus.io/docs/sidebar#autogenerated-sidebar-metadata + */ + sidebar_position?: number; + /** + * Gives the corresponding sidebar label a special class name when using + * autogenerated sidebars. + */ + sidebar_class_name?: string; + /** + * Will be propagated to the final sidebars data structure. Useful if you + * have swizzled sidebar-related code or simply querying doc data through + * sidebars. + */ + sidebar_custom_props?: {[key: string]: unknown}; + /** + * Changes the sidebar association of the current doc. Use `null` to make + * the current doc not associated to any sidebar. + */ + displayed_sidebar?: string | null; + /** + * Customizes the pagination label for this doc. Will default to the sidebar + * label. + */ + pagination_label?: string; + /** Overrides the default URL computed for this doc. */ + custom_edit_url?: string | null; + /** + * Whether number prefix parsing is disabled on this doc. + * @see https://docusaurus.io/docs/sidebar#using-number-prefixes + */ + parse_number_prefixes?: boolean; + /** + * Minimum TOC heading level. Must be between 2 and 6 and lower or equal to + * the max value. + */ + toc_min_heading_level?: number; + /** Maximum TOC heading level. Must be between 2 and 6. */ + toc_max_heading_level?: number; + /** + * The ID of the documentation you want the "Next" pagination to link to. + * Use `null` to disable showing "Next" for this page. + * @see {@link DocMetadata.next} + */ + pagination_next?: string | null; + /** + * The ID of the documentation you want the "Previous" pagination to link + * to. Use `null` to disable showing "Previous" for this page. + * @see {@link DocMetadata.prev} + */ + pagination_prev?: string | null; + }; + + export type LastUpdateData = { + /** A timestamp in **seconds**, directly acquired from `git log`. */ + lastUpdatedAt?: number; + /** `lastUpdatedAt` formatted as a date according to the current locale. */ + formattedLastUpdatedAt?: string; + /** The author's name directly acquired from `git log`. */ + lastUpdatedBy?: string; + }; + + export type DocMetadataBase = LastUpdateData & { + // TODO + /** + * Legacy versioned ID. Will be refactored in the future to be unversioned. + */ + id: string; + // TODO + /** + * Unversioned ID. Should be preferred everywhere over `id` until the latter + * is refactored. + */ + unversionedId: string; + /** The name of the version this doc belongs to. */ + version: string; + /** + * Used to generate the page h1 heading, tab title, and pagination title. + */ + title: string; + /** + * Description used in the meta. Could be an empty string (empty content) + */ + description: string; + /** Path to the Markdown source, with `@site` alias. */ + source: string; + /** + * Posix path relative to the content path. Can be `"."`. + * e.g. "folder/subfolder/subsubfolder" + */ + sourceDirName: string; + /** `permalink` without base URL or version path. */ + slug: string; + /** Full URL to this doc, with base URL and version path. */ + permalink: string; + /** + * Position in an autogenerated sidebar slice, acquired through front matter + * or number prefix. + */ + sidebarPosition?: number; + /** + * Acquired from the options; can be customized with front matter. + * `custom_edit_url` will always lead to it being null, but you should treat + * `undefined` and `null` as equivalent. + */ + editUrl?: string | null; + /** Tags, normalized. */ + tags: Tag[]; + /** Front matter, as-is. */ + frontMatter: DocFrontMatter & {[key: string]: unknown}; + }; + + export type DocMetadata = DocMetadataBase & + PropNavigation & { + /** Name of the sidebar this doc is associated with. */ + sidebar?: string; + }; + + export type CategoryGeneratedIndexMetadata = Required< + Omit< + import('./sidebars/types').SidebarItemCategoryLinkGeneratedIndex, + 'type' + >, + 'title' + > & { + navigation: PropNavigation; + /** + * Name of the sidebar this doc is associated with. Unlike + * `DocMetadata.sidebar`, this will always be defined, because a generated + * index can only be generated from a category. + */ + sidebar: string; + }; + export type PropNavigationLink = { readonly title: string; readonly permalink: string; }; export type PropNavigation = { + /** + * Used in pagination. Content is just a subset of another doc's metadata. + */ readonly previous?: PropNavigationLink; + /** + * Used in pagination. Content is just a subset of another doc's metadata. + */ readonly next?: PropNavigationLink; }; - export type PropVersionDoc = import('./sidebars/types').PropVersionDoc; - export type PropVersionDocs = import('./sidebars/types').PropVersionDocs; + export type PropVersionDoc = Pick< + DocMetadata, + 'id' | 'title' | 'description' | 'sidebar' + >; - export type PropVersionMetadata = { + export type PropVersionDocs = { + [docId: string]: PropVersionDoc; + }; + + export type PropVersionMetadata = Pick< + VersionMetadata, + 'label' | 'banner' | 'badge' | 'className' | 'isLast' + > & { + /** ID of the docs plugin this version belongs to. */ pluginId: string; + /** Name of this version. */ version: string; - label: string; - banner: VersionBanner | null; - badge: boolean; - className: string; - isLast: boolean; + /** Sidebars contained in this version. */ docsSidebars: PropSidebars; + /** Docs contained in this version. */ docs: PropVersionDocs; }; - export type PropCategoryGeneratedIndex = { - title: string; - description?: string; - image?: string; - keywords?: string | readonly string[]; - slug: string; - permalink: string; - navigation: PropNavigation; - }; + export type PropCategoryGeneratedIndex = Omit< + CategoryGeneratedIndexMetadata, + 'sidebar' + >; export type PropSidebarItemLink = import('./sidebars/types').PropSidebarItemLink; @@ -169,9 +508,10 @@ declare module '@docusaurus/plugin-content-docs' { declare module '@theme/DocItem' { import type {TOCItem} from '@docusaurus/types'; import type { - PropNavigationLink, PropVersionMetadata, Assets, + DocMetadata, + DocFrontMatter, } from '@docusaurus/plugin-content-docs'; export type DocumentRoute = { @@ -181,41 +521,12 @@ declare module '@theme/DocItem' { readonly sidebar?: string; }; - export type FrontMatter = { - readonly id: string; - readonly title: string; - readonly image?: string; - readonly keywords?: readonly string[]; - readonly hide_title?: boolean; - readonly hide_table_of_contents?: boolean; - readonly toc_min_heading_level?: number; - readonly toc_max_heading_level?: number; - }; - - export type Metadata = { - readonly unversionedId?: string; - readonly description?: string; - readonly title?: string; - readonly permalink?: string; - readonly editUrl?: string; - readonly lastUpdatedAt?: number; - readonly formattedLastUpdatedAt?: string; - readonly lastUpdatedBy?: string; - readonly version?: string; - readonly previous?: PropNavigationLink; - readonly next?: PropNavigationLink; - readonly tags: readonly { - readonly label: string; - readonly permalink: string; - }[]; - }; - export interface Props { readonly route: DocumentRoute; readonly versionMetadata: PropVersionMetadata; readonly content: { - readonly frontMatter: FrontMatter; - readonly metadata: Metadata; + readonly frontMatter: DocFrontMatter; + readonly metadata: DocMetadata; readonly toc: readonly TOCItem[]; readonly contentTitle: string | undefined; readonly assets: Assets; diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 0a99bf8f5b7a..d25888db63a8 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -5,13 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import type {LoadedVersion, VersionTag, DocMetadata} from './types'; +import type {LoadedVersion, VersionTag} from './types'; import type { SidebarItemDoc, SidebarItem, SidebarItemCategory, SidebarItemCategoryLink, - PropVersionDocs, } from './sidebars/types'; import type { PropSidebars, @@ -21,6 +20,8 @@ import type { PropTagDocList, PropTagDocListDoc, PropSidebarItemLink, + PropVersionDocs, + DocMetadata, } from '@docusaurus/plugin-content-docs'; import _ from 'lodash'; import {createDocsByIdIndex} from './docs'; @@ -119,10 +120,10 @@ export function toVersionMetadataProp( return { pluginId, version: loadedVersion.versionName, - label: loadedVersion.versionLabel, - banner: loadedVersion.versionBanner, - badge: loadedVersion.versionBadge, - className: loadedVersion.versionClassName, + label: loadedVersion.label, + banner: loadedVersion.banner, + badge: loadedVersion.badge, + className: loadedVersion.className, isLast: loadedVersion.isLast, docsSidebars: toSidebarsProp(loadedVersion), docs: toVersionDocsProp(loadedVersion), @@ -153,7 +154,7 @@ export function toTagDocListProp({ } return { - name: tag.name, + name: tag.label, permalink: tag.permalink, docs: toDocListProp(), allTagsPath, diff --git a/packages/docusaurus-plugin-content-docs/src/routes.ts b/packages/docusaurus-plugin-content-docs/src/routes.ts index ad7608f449dc..3ef6e60ba146 100644 --- a/packages/docusaurus-plugin-content-docs/src/routes.ts +++ b/packages/docusaurus-plugin-content-docs/src/routes.ts @@ -7,12 +7,11 @@ import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types'; import {docuHash, createSlugger} from '@docusaurus/utils'; +import type {LoadedVersion} from './types'; import type { CategoryGeneratedIndexMetadata, DocMetadata, - LoadedVersion, -} from './types'; -import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs'; +} from '@docusaurus/plugin-content-docs'; import {toVersionMetadataProp} from './props'; import logger from '@docusaurus/logger'; @@ -32,42 +31,19 @@ export async function createCategoryGeneratedIndexRoutes({ async function createCategoryGeneratedIndexRoute( categoryGeneratedIndex: CategoryGeneratedIndexMetadata, ): Promise<RouteConfig> { - const { - sidebar, - title, - description, - slug, - permalink, - previous, - next, - image, - keywords, - } = categoryGeneratedIndex; + const {sidebar, ...prop} = categoryGeneratedIndex; const propFileName = slugs.slug( - `${version.versionPath}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`, + `${version.path}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`, ); - const prop: PropCategoryGeneratedIndex = { - title, - description, - slug, - permalink, - image, - keywords, - navigation: { - previous, - next, - }, - }; - const propData = await actions.createData( `${docuHash(`category/${propFileName}`)}.json`, JSON.stringify(prop, null, 2), ); return { - path: permalink, + path: categoryGeneratedIndex.permalink, component: docCategoryGeneratedIndexComponent, exact: true, modules: { @@ -162,7 +138,7 @@ export async function createVersionRoutes({ } actions.addRoute({ - path: version.versionPath, + path: version.path, // allow matching /docs/* as well exact: false, // main docs component (DocPage) diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts index 19cd6495831f..a1a8e56d8fd1 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/postProcessor.test.ts @@ -34,7 +34,7 @@ describe('postProcess', () => { }, { sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, - version: {versionPath: 'version'}, + version: {path: 'version'}, }, ); @@ -53,7 +53,7 @@ describe('postProcess', () => { }, { sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, - version: {versionPath: 'version'}, + version: {path: 'version'}, }, ); }).toThrowErrorMatchingInlineSnapshot( @@ -78,7 +78,7 @@ describe('postProcess', () => { { sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, - version: {versionPath: 'version'}, + version: {path: 'version'}, }, ), ).toMatchSnapshot(); @@ -98,7 +98,7 @@ describe('postProcess', () => { { sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false}, - version: {versionPath: 'version'}, + version: {path: 'version'}, }, ), ).toMatchSnapshot(); @@ -117,7 +117,7 @@ describe('postProcess', () => { { sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false}, - version: {versionPath: 'version'}, + version: {path: 'version'}, }, ), ).toMatchSnapshot(); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts index 1dad824917f9..500eefbfe1dd 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/processor.test.ts @@ -18,7 +18,7 @@ import type { } from '../types'; import {DefaultSidebarItemsGenerator} from '../generator'; import {createSlugger} from '@docusaurus/utils'; -import type {VersionMetadata} from '../../types'; +import type {VersionMetadata} from '@docusaurus/plugin-content-docs'; import {DefaultNumberPrefixParser} from '../../numberPrefix'; import {isCategoryIndex} from '../../docs'; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index 540f379a7f06..7c2d4428c642 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -16,7 +16,10 @@ import { toNavigationLink, } from '../utils'; import type {Sidebar, Sidebars} from '../types'; -import type {DocMetadataBase, DocNavLink} from '../../types'; +import type { + DocMetadataBase, + PropNavigationLink, +} from '@docusaurus/plugin-content-docs'; describe('createSidebarsUtils', () => { const sidebar1: Sidebar = [ @@ -618,7 +621,7 @@ describe('toDocNavigationLink', () => { ).toEqual({ title: 'Doc Title', permalink: '/docPermalink', - } as DocNavLink); + } as PropNavigationLink); }); it('with pagination_label front matter', () => { @@ -635,7 +638,7 @@ describe('toDocNavigationLink', () => { ).toEqual({ title: 'pagination_label', permalink: '/docPermalink', - } as DocNavLink); + } as PropNavigationLink); }); it('with sidebar_label front matter', () => { @@ -652,7 +655,7 @@ describe('toDocNavigationLink', () => { ).toEqual({ title: 'sidebar_label', permalink: '/docPermalink', - } as DocNavLink); + } as PropNavigationLink); }); it('with pagination_label + sidebar_label front matter', () => { @@ -670,7 +673,7 @@ describe('toDocNavigationLink', () => { ).toEqual({ title: 'pagination_label', permalink: '/docPermalink', - } as DocNavLink); + } as PropNavigationLink); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts index 44c652fe1959..363c731696b9 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts @@ -26,7 +26,7 @@ function normalizeCategoryLink( const getDefaultSlug = () => `/category/${params.categoryLabelSlugger.slug(category.label)}`; const slug = category.link.slug ?? getDefaultSlug(); - const permalink = normalizeUrl([params.version.versionPath, slug]); + const permalink = normalizeUrl([params.version.path, slug]); return { ...category.link, slug, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts index a4f55b6bf5d0..7e83dd08a921 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/processor.ts @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import type {DocMetadataBase, VersionMetadata} from '../types'; +import type { + DocMetadataBase, + VersionMetadata, +} from '@docusaurus/plugin-content-docs'; import type { NormalizedSidebarItem, NormalizedSidebar, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index 50a1e6185c2c..9f4d68a3ae45 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -6,11 +6,12 @@ */ import type {Optional, Required} from 'utility-types'; -import type {DocMetadataBase, VersionMetadata} from '../types'; import type { NumberPrefixParser, SidebarOptions, CategoryIndexMatcher, + DocMetadataBase, + VersionMetadata, } from '@docusaurus/plugin-content-docs'; import type {Slugger} from '@docusaurus/utils'; @@ -199,16 +200,6 @@ export type PropSidebarBreadcrumbsItem = | PropSidebarItemLink | PropSidebarItemCategory; -export type PropVersionDoc = { - id: string; - title: string; - description?: string; - sidebar?: string; -}; -export type PropVersionDocs = { - [docId: string]: PropVersionDoc; -}; - export type CategoryMetadataFile = { label?: string; position?: number; @@ -243,11 +234,20 @@ export type SidebarItemsGeneratorVersion = Pick< >; export type SidebarItemsGeneratorArgs = { + /** The sidebar item with type "autogenerated" to be transformed. */ item: SidebarItemAutogenerated; + /** Useful metadata for the version this sidebar belongs to. */ version: SidebarItemsGeneratorVersion; + /** All the docs of that version (unfiltered). */ docs: SidebarItemsGeneratorDoc[]; + /** Number prefix parser configured for this plugin. */ numberPrefixParser: NumberPrefixParser; + /** The default category index matcher which you can override. */ isCategoryIndex: CategoryIndexMatcher; + /** + * key is the path relative to the doc content directory, value is the + * category metadata file's content. + */ categoriesMetadata: {[filePath: string]: CategoryMetadataFile}; }; export type SidebarItemsGenerator = ( @@ -258,6 +258,10 @@ export type SidebarItemsGenerator = ( // default sidebar gen logic // see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320 export type SidebarItemsGeneratorOptionArgs = { + /** + * Useful to re-use/enhance the default sidebar generation logic from + * Docusaurus. + */ defaultSidebarItemsGenerator: SidebarItemsGenerator; } & SidebarItemsGeneratorArgs; export type SidebarItemsGeneratorOption = ( diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index 5caa93d94884..ee27177c1e4a 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -21,7 +21,10 @@ import type { import _ from 'lodash'; import {toMessageRelativeFilePath} from '@docusaurus/utils'; -import type {DocMetadataBase, DocNavLink} from '../types'; +import type { + DocMetadataBase, + PropNavigationLink, +} from '@docusaurus/plugin-content-docs'; export function isCategoriesShorthand( item: SidebarItemConfig, @@ -346,7 +349,7 @@ Available document ids are: }; } -export function toDocNavigationLink(doc: DocMetadataBase): DocNavLink { +export function toDocNavigationLink(doc: DocMetadataBase): PropNavigationLink { const { title, permalink, @@ -361,7 +364,7 @@ export function toDocNavigationLink(doc: DocMetadataBase): DocNavLink { export function toNavigationLink( navigationItem: SidebarNavigationItem | undefined, docsById: {[docId: string]: DocMetadataBase}, -): DocNavLink | undefined { +): PropNavigationLink | undefined { function getDocById(docId: string) { const doc = docsById[docId]; if (!doc) { diff --git a/packages/docusaurus-plugin-content-docs/src/slug.ts b/packages/docusaurus-plugin-content-docs/src/slug.ts index 9de48aa13f28..4815e210b01d 100644 --- a/packages/docusaurus-plugin-content-docs/src/slug.ts +++ b/packages/docusaurus-plugin-content-docs/src/slug.ts @@ -15,9 +15,11 @@ import { DefaultNumberPrefixParser, stripPathNumberPrefixes, } from './numberPrefix'; -import type {DocMetadataBase} from './types'; import {isCategoryIndex, toCategoryIndexMatcherParam} from './docs'; -import type {NumberPrefixParser} from '@docusaurus/plugin-content-docs'; +import type { + NumberPrefixParser, + DocMetadataBase, +} from '@docusaurus/plugin-content-docs'; export default function getSlug({ baseID, diff --git a/packages/docusaurus-plugin-content-docs/src/tags.ts b/packages/docusaurus-plugin-content-docs/src/tags.ts index 005b956bd804..1de963d81f56 100644 --- a/packages/docusaurus-plugin-content-docs/src/tags.ts +++ b/packages/docusaurus-plugin-content-docs/src/tags.ts @@ -6,13 +6,14 @@ */ import {groupTaggedItems} from '@docusaurus/utils'; -import type {VersionTags, DocMetadata} from './types'; +import type {VersionTags} from './types'; +import type {DocMetadata} from '@docusaurus/plugin-content-docs'; import _ from 'lodash'; export function getVersionTags(docs: DocMetadata[]): VersionTags { const groups = groupTaggedItems(docs, (doc) => doc.tags); return _.mapValues(groups, (group) => ({ - name: group.tag.label, + label: group.tag.label, docIds: group.items.map((item) => item.id), permalink: group.tag.permalink, })); diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index 40d9e24f0a6b..cc43d6b3f061 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -245,7 +245,7 @@ function translateSidebars( function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles { const versionTranslations: TranslationFileContent = { 'version.label': { - message: version.versionLabel, + message: version.label, description: `The label for version ${version.versionName}`, }, }; @@ -275,8 +275,7 @@ function translateVersion( translationFiles[getVersionFileName(version.versionName)]!.content; return { ...version, - versionLabel: - versionTranslations['version.label']?.message ?? version.versionLabel, + label: versionTranslations['version.label']?.message ?? version.label, sidebars: translateSidebars(version, versionTranslations), // docs: translateDocs(version.docs, versionTranslations), }; diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 7da32a8a3691..909a200da7e4 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -8,13 +8,13 @@ /// <reference types="@docusaurus/module-type-aliases" /> import type {Sidebars} from './sidebars/types'; +import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils'; import type { - Tag, - FrontMatterTag, - BrokenMarkdownLink, - ContentPaths, -} from '@docusaurus/utils'; -import type {VersionBanner} from '@docusaurus/plugin-content-docs'; + VersionMetadata, + LastUpdateData, + DocMetadata, + CategoryGeneratedIndexMetadata, +} from '@docusaurus/plugin-content-docs'; export type DocFile = { contentPath: string; // /!\ may be localized @@ -24,106 +24,19 @@ export type DocFile = { lastUpdate: LastUpdateData; }; -export type VersionMetadata = ContentPaths & { - versionName: string; // 1.0.0 - versionLabel: string; // Version 1.0.0 - versionPath: string; // /baseUrl/docs/1.0.0 - tagsPath: string; - versionEditUrl?: string | undefined; - versionEditUrlLocalized?: string | undefined; - versionBanner: VersionBanner | null; - versionBadge: boolean; - versionClassName: string; - isLast: boolean; - sidebarFilePath: string | false | undefined; // versioned_sidebars/1.0.0.json - routePriority: number | undefined; // -1 for the latest docs -}; - -export type LastUpdateData = { - lastUpdatedAt?: number; - formattedLastUpdatedAt?: string; - lastUpdatedBy?: string; -}; - -export type DocFrontMatter = { - // Front matter uses snake case - id?: string; - title?: string; - tags?: FrontMatterTag[]; - hide_title?: boolean; - hide_table_of_contents?: boolean; - keywords?: string[]; - image?: string; - description?: string; - slug?: string; - sidebar_label?: string; - sidebar_position?: number; - sidebar_class_name?: string; - sidebar_custom_props?: {[key: string]: unknown}; - displayed_sidebar?: string | null; - pagination_label?: string; - custom_edit_url?: string | null; - parse_number_prefixes?: boolean; - toc_min_heading_level?: number; - toc_max_heading_level?: number; - pagination_next?: string | null; - pagination_prev?: string | null; -}; - -export type DocMetadataBase = LastUpdateData & { - id: string; // TODO legacy versioned id => try to remove - unversionedId: string; // TODO new unversioned id => try to rename to "id" - version: string; - title: string; - description: string; - source: string; // @site aliased posix source => "@site/docs/folder/subFolder/subSubFolder/myDoc.md" - sourceDirName: string; // posix path relative to the versioned docs folder (can be ".") => "folder/subFolder/subSubFolder" - slug: string; - permalink: string; - sidebarPosition?: number; - editUrl?: string | null; - tags: Tag[]; - frontMatter: DocFrontMatter & {[key: string]: unknown}; -}; - -export type DocNavLink = { - title: string; - permalink: string; -}; - -export type DocMetadata = DocMetadataBase & { - sidebar?: string; - previous?: DocNavLink; - next?: DocNavLink; -}; - -export type CategoryGeneratedIndexMetadata = { - title: string; - description?: string; - slug: string; - permalink: string; - sidebar: string; - previous?: DocNavLink; - next?: DocNavLink; - image?: string; - keywords?: string | readonly string[]; -}; - export type SourceToPermalink = { [source: string]: string; }; -export type VersionTag = { - name: string; // normalized name/label of the tag - docIds: string[]; // all doc ids having this tag - permalink: string; // pathname of the tag +export type VersionTag = Tag & { + /** all doc ids having this tag. */ + docIds: string[]; }; export type VersionTags = { [key: string]: VersionTag; }; export type LoadedVersion = VersionMetadata & { - versionPath: string; mainDocId: string; docs: DocMetadata[]; sidebars: Sidebars; diff --git a/packages/docusaurus-plugin-content-docs/src/versions.ts b/packages/docusaurus-plugin-content-docs/src/versions.ts index 664118498155..7b06aa0e089c 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions.ts @@ -7,7 +7,6 @@ import path from 'path'; import fs from 'fs-extra'; -import type {VersionMetadata} from './types'; import { VERSIONS_JSON_FILE, VERSIONED_DOCS_DIR, @@ -17,8 +16,8 @@ import { import type { PluginOptions, VersionBanner, - VersionOptions, VersionsOptions, + VersionMetadata, } from '@docusaurus/plugin-content-docs'; import type {LoadContext} from '@docusaurus/types'; @@ -207,7 +206,12 @@ function getVersionEditUrls({ contentPath, contentPathLocalized, context: {siteDir, i18n}, - options: {id, path: currentVersionPath, editUrl, editCurrentVersion}, + options: { + id, + path: currentVersionPath, + editUrl: editUrlOption, + editCurrentVersion, + }, }: { contentPath: string; contentPathLocalized: string; @@ -216,15 +220,11 @@ function getVersionEditUrls({ PluginOptions, 'id' | 'path' | 'editUrl' | 'editCurrentVersion' >; -}): {versionEditUrl: string; versionEditUrlLocalized: string} | undefined { - if (!editUrl) { - return undefined; - } - - // if the user is using the functional form of editUrl, - // he has total freedom and we can't compute a "version edit url" - if (typeof editUrl === 'function') { - return undefined; +}): Pick<VersionMetadata, 'editUrl' | 'editUrlLocalized'> { + // If the user is using the functional form of editUrl, + // she has total freedom and we can't compute a "version edit url" + if (!editUrlOption || typeof editUrlOption === 'function') { + return {editUrl: undefined, editUrlLocalized: undefined}; } const editDirPath = editCurrentVersion ? currentVersionPath : contentPath; @@ -244,16 +244,16 @@ function getVersionEditUrls({ path.relative(siteDir, path.resolve(siteDir, editDirPathLocalized)), ); - const versionEditUrl = normalizeUrl([editUrl, versionPathSegment]); + const editUrl = normalizeUrl([editUrlOption, versionPathSegment]); - const versionEditUrlLocalized = normalizeUrl([ - editUrl, + const editUrlLocalized = normalizeUrl([ + editUrlOption, versionPathSegmentLocalized, ]); return { - versionEditUrl, - versionEditUrlLocalized, + editUrl, + editUrlLocalized, }; } @@ -370,12 +370,12 @@ function createVersionMetadata({ } const defaultVersionPathPart = getDefaultVersionPathPart(); - const versionOptions: VersionOptions = options.versions[versionName] ?? {}; + const versionOptions = options.versions[versionName] ?? {}; - const versionLabel = versionOptions.label ?? defaultVersionLabel; + const label = versionOptions.label ?? defaultVersionLabel; const versionPathPart = versionOptions.path ?? defaultVersionPathPart; - const versionPath = normalizeUrl([ + const routePath = normalizeUrl([ context.baseUrl, options.routeBasePath, versionPathPart, @@ -388,28 +388,27 @@ function createVersionMetadata({ options, }); - // Because /docs/:route` should always be after `/docs/versionName/:route`. const routePriority = versionPathPart === '' ? -1 : undefined; // the path that will be used to refer the docs tags // example below will be using /docs/tags - const tagsPath = normalizeUrl([versionPath, options.tagsBasePath]); + const tagsPath = normalizeUrl([routePath, options.tagsBasePath]); return { versionName, - versionLabel, - versionPath, + label, + path: routePath, tagsPath, - versionEditUrl: versionEditUrls?.versionEditUrl, - versionEditUrlLocalized: versionEditUrls?.versionEditUrlLocalized, - versionBanner: getVersionBanner({ + editUrl: versionEditUrls.editUrl, + editUrlLocalized: versionEditUrls.editUrlLocalized, + banner: getVersionBanner({ versionName, versionNames, lastVersionName, options, }), - versionBadge: getVersionBadge({versionName, versionNames, options}), - versionClassName: getVersionClassName({versionName, options}), + badge: getVersionBadge({versionName, versionNames, options}), + className: getVersionClassName({versionName, options}), isLast, routePriority, sidebarFilePath, @@ -592,15 +591,3 @@ export async function readVersionsMetadata({ ); return versionsMetadata; } - -// order matter! -// Read in priority the localized path, then the unlocalized one -// We want the localized doc to "override" the unlocalized one -export function getDocsDirPaths( - versionMetadata: Pick< - VersionMetadata, - 'contentPath' | 'contentPathLocalized' - >, -): [string, string] { - return [versionMetadata.contentPathLocalized, versionMetadata.contentPath]; -} diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index fabded2ba633..24fd413ca1f4 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -6,9 +6,9 @@ */ declare module '@docusaurus/plugin-content-pages' { - import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; + import type {MDXOptions} from '@docusaurus/mdx-loader'; - export type PluginOptions = RemarkAndRehypePluginOptions & { + export type PluginOptions = MDXOptions & { id?: string; path: string; routeBasePath: string; diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index bb3e03137640..04e8b6ccd92b 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -5,6 +5,13 @@ * LICENSE file in the root directory of this source tree. */ +/* eslint-disable @typescript-eslint/triple-slash-reference */ + +/// <reference types="@docusaurus/module-type-aliases" /> +/// <reference types="@docusaurus/plugin-content-docs" /> +/// <reference types="@docusaurus/plugin-content-blog" /> +/// <reference types="@docusaurus/plugin-content-pages" /> + declare module '@docusaurus/theme-classic' { export type Options = { customCss?: string | string[]; diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index aa675efa2c9b..77265efccbd2 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -47,7 +47,7 @@ function DocItemContent(props: Props): JSX.Element { const {title} = metadata; // We only add a title if: - // - user asks to hide it with front matter + // - user doesn't ask to hide it with front matter // - the markdown content does not already contain a top-level h1 heading const shouldAddTitle = !hideTitle && typeof DocContent.contentTitle === 'undefined'; diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts deleted file mode 100644 index db5e128fd3d1..000000000000 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/// <reference types="@docusaurus/module-type-aliases" /> -/// <reference types="@docusaurus/plugin-content-blog" /> -/// <reference types="@docusaurus/plugin-content-docs" /> -/// <reference types="@docusaurus/plugin-content-pages" /> diff --git a/packages/docusaurus-theme-live-codeblock/src/types.d.ts b/packages/docusaurus-theme-live-codeblock/src/types.d.ts index df2fa7d2162a..9ae9bb21cef3 100644 --- a/packages/docusaurus-theme-live-codeblock/src/types.d.ts +++ b/packages/docusaurus-theme-live-codeblock/src/types.d.ts @@ -6,6 +6,7 @@ */ /// <reference types="@docusaurus/theme-classic" /> +/// <reference types="@docusaurus/module-type-aliases" /> declare module '@theme-init/CodeBlock' { import type CodeBlock, {Props as BaseProps} from '@theme/CodeBlock'; diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index cf69f8f8a220..7ef92f29f5b1 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -31,24 +31,23 @@ Accepted fields: | Name | Type | Default | Description | | --- | --- | --- | --- | -| `path` | `string` | `'docs'` | Path to data on filesystem relative to site dir. | -| `breadcrumbs` | `boolean` | `true` | To enable or disable the breadcrumbs on docs pages. | +| `path` | `string` | `'docs'` | Path to the docs content directory on the file system, relative to site directory. | | `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | | `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. | | `editCurrentVersion` | `boolean` | `false` | The edit URL will always target the current version doc instead of older versions. Ignored when `editUrl` is a function. | | `routeBasePath` | `string` | `'docs'` | URL route for the docs section of your site. **DO NOT** include a trailing slash. Use `/` for shipping docs without base path. | | `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. | -| `include` | `string[]` | `['**/*.{md,mdx}']` | Matching files will be included and processed. | -| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. | -| `sidebarPath` | <code>false \| string</code> | `undefined` (creates autogenerated sidebar) | Path to sidebar configuration. | +| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. | +| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. | +| `sidebarPath` | <code>false \| string</code> | `undefined` | Path to sidebar configuration. Use `false` to disable sidebars, or `undefined` to create a fully autogenerated sidebar. | | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. See also [Collapsible categories](/docs/sidebar#collapsible-categories) | | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) | -| `sidebarItemsGenerator` | `SidebarGenerator` | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` by real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | +| `sidebarItemsGenerator` | `SidebarGenerator` | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` with real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | | `numberPrefixParser` | <code>boolean \| PrefixParser</code> | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) | -| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root Layout component of each doc page. | +| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root layout component of each doc page. Provides the version data context, and is not unmounted when switching docs. | | `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. | | `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page | -| `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag" page. | +| `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag X" page. | | `docCategoryGeneratedIndexComponent` | `string` | `'@theme/DocCategoryGeneratedIndexPage'` | Root component of the generated category index page. | | `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. | | `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. | @@ -56,11 +55,12 @@ Accepted fields: | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | | `showLastUpdateAuthor` | `boolean` | `false` | Whether to display the author who last updated the doc. | | `showLastUpdateTime` | `boolean` | `false` | Whether to display the last date the doc was updated. | -| `disableVersioning` | `boolean` | `false` | Explicitly disable versioning even with versions. This will make the site only include the current version. | +| `breadcrumbs` | `boolean` | `true` | Enable or disable the breadcrumbs on doc pages. | +| `disableVersioning` | `boolean` | `false` | Explicitly disable versioning even when multiple versions exist. This will make the site only include the current version. Will error if `includeCurrentVersion: false` and `disableVersioning: true`. | | `includeCurrentVersion` | `boolean` | `true` | Include the current version of your docs. | -| `lastVersion` | `string` | First version in `versions.json` | Set the version navigated to in priority and displayed by default for docs navbar items. | +| `lastVersion` | `string` | First version in `versions.json` | The version navigated to in priority and displayed by default for docs navbar items. | | `onlyIncludeVersions` | `string[]` | All versions available | Only include a subset of all available versions. | -| `versions` | `Versions` | `{}` | Independent customization of each version's properties. | +| `versions` | `VersionsConfig` | `{}` | Independent customization of each version's properties. | </APITable> @@ -78,15 +78,24 @@ type PrefixParser = (filename: string) => { numberPrefix?: number; }; -type CategoryIndexMatcher = (doc: { +type CategoryIndexMatcher = (param: { + /** The file name, without extension */ fileName: string; + /** + * The list of directories, from lowest level to highest. + * If there's no dir name, directories is ['.'] + */ directories: string[]; + /** The extension, with a leading dot */ extension: string; }) => boolean; type SidebarGenerator = (generatorArgs: { - item: {type: 'autogenerated'; dirName: string}; // the sidebar item with type "autogenerated" - version: {contentPath: string; versionName: string}; // the current version + /** The sidebar item with type "autogenerated" to be transformed. */ + item: {type: 'autogenerated'; dirName: string}; + /** Useful metadata for the version this sidebar belongs to. */ + version: {contentPath: string; versionName: string}; + /** All the docs of that version (unfiltered). */ docs: Array<{ id: string; title: string; @@ -94,23 +103,40 @@ type SidebarGenerator = (generatorArgs: { source: string; sourceDirName: string; sidebarPosition?: number | undefined; - }>; // all the docs of that version (unfiltered) - numberPrefixParser: PrefixParser; // numberPrefixParser configured for this plugin - categoriesMetadata: Record<string, CategoryMetadata>; // key is the path relative to the doc directory, value is the category metadata file's content - isCategoryIndex: CategoryIndexMatcher; // the default category index matcher, that you can override - defaultSidebarItemsGenerator: SidebarGenerator; // useful to re-use/enhance default sidebar generation logic from Docusaurus + }>; + /** Number prefix parser configured for this plugin. */ + numberPrefixParser: PrefixParser; + /** The default category index matcher which you can override. */ + isCategoryIndex: CategoryIndexMatcher; + /** + * key is the path relative to the doc content directory, value is the + * category metadata file's content. + */ + categoriesMetadata: {[filePath: string]: CategoryMetadata}; + /** + * Useful to re-use/enhance the default sidebar generation logic from + * Docusaurus. + */ + defaultSidebarItemsGenerator: SidebarGenerator; }) => Promise<SidebarItem[]>; -type Versions = Record< - string, // the version's ID - { - label: string; // the label of the version - path: string; // the route path of the version - banner: 'none' | 'unreleased' | 'unmaintained'; // the banner to show at the top of a doc of that version - badge: boolean; // show a badge with the version name at the top of a doc of that version - className; // add a custom className to the <html> element when browsing docs of that version - } ->; +type VersionsConfig = { + [versionName: string]: { + /** + * The base path of the version, will be appended to `baseUrl` + + * `routeBasePath`. + */ + path?: string; + /** The label of the version to be used in badges, dropdowns, etc. */ + label?: string; + /** The banner to show at the top of a doc of that version. */ + banner?: 'none' | 'unreleased' | 'unmaintained'; + /** Show a badge with the version label at the top of each doc. */ + badge?: boolean; + /** Add a custom class name to the <html> element of each doc */ + className?: string; + }; +}; ``` ### Example configuration {#ex-config} From a307da0b9f5964cc5d3cdeac4284e319c3753cbc Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Sun, 27 Mar 2022 09:59:20 +0300 Subject: [PATCH 085/405] feat(logger): new "url" format, add double quotes around paths (#7019) * refactor(logger): add double quotes around paths * Introduce url formatter * Fix --- packages/create-docusaurus/src/index.ts | 6 +++--- packages/docusaurus-logger/README.md | 4 +++- packages/docusaurus-logger/src/__tests__/index.test.ts | 10 +++++++--- packages/docusaurus-logger/src/index.ts | 6 +++++- .../src/sidebars/normalization.ts | 2 +- packages/docusaurus/src/client/serverEntry.tsx | 2 +- packages/docusaurus/src/server/plugins/index.ts | 2 +- 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index f6b276585cd0..1ca4627e7006 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -271,7 +271,7 @@ export default async function init( return logger.red('Invalid repository URL'); }, message: logger.interpolate`Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo. -(e.g: path=${'https://github.com/ownerName/repoName.git'})`, +(e.g: url=${'https://github.com/ownerName/repoName.git'})`, }); ({gitStrategy} = await prompts({ type: 'select', @@ -318,7 +318,7 @@ export default async function init( logger.info('Creating new Docusaurus project...'); if (isValidGitRepoUrl(template)) { - logger.info`Cloning Git template path=${template}...`; + logger.info`Cloning Git template url=${template}...`; if (!gitStrategies.includes(gitStrategy)) { logger.error`Invalid git strategy: name=${gitStrategy}. Value must be one of ${gitStrategies.join( ', ', @@ -416,7 +416,7 @@ export default async function init( } const useNpm = pkgManager === 'npm'; - logger.success`Created path=${cdpath}.`; + logger.success`Created name=${cdpath}.`; logger.info`Inside that directory, you can run several commands: code=${`${pkgManager} start`} diff --git a/packages/docusaurus-logger/README.md b/packages/docusaurus-logger/README.md index 2c4cea3bf5fd..8b173b8bab9a 100644 --- a/packages/docusaurus-logger/README.md +++ b/packages/docusaurus-logger/README.md @@ -8,7 +8,8 @@ It exports a single object as default export: `logger`. `logger` has the followi - Some useful colors. - Formatters. These functions have the same signature as the formatters of `picocolors`. Note that their implementations are not guaranteed. You should only care about their semantics. - - `path`: formats a file path or URL. + - `path`: formats a file path. + - `url`: formats a URL. - `id`: formats an identifier. - `code`: formats a code snippet. - `subdue`: subdues the text. @@ -34,6 +35,7 @@ To buy anything, enter code=${'buy x'} where code=${'x'} is the item's name; to An embedded expression is optionally preceded by a flag in the form `%[a-z]+` (a percentage sign followed by a few lowercase letters). If it's not preceded by any flag, it's printed out as-is. Otherwise, it's formatted with one of the formatters: - `path=`: `path` +- `url=`: `url` - `name=`: `id` - `code=`: `code` - `subdue=`: `subdue` diff --git a/packages/docusaurus-logger/src/__tests__/index.test.ts b/packages/docusaurus-logger/src/__tests__/index.test.ts index ba7ecfbebcbf..0b2b710769fd 100644 --- a/packages/docusaurus-logger/src/__tests__/index.test.ts +++ b/packages/docusaurus-logger/src/__tests__/index.test.ts @@ -11,7 +11,12 @@ import logger from '../index'; describe('formatters', () => { it('path', () => { // cSpell:ignore mhey - expect(logger.path('hey')).toMatchInlineSnapshot(`"hey"`); + expect(logger.path('hey')).toMatchInlineSnapshot(`"\\"hey\\""`); + }); + it('url', () => { + expect(logger.url('https://docusaurus.io/')).toMatchInlineSnapshot( + `"https://docusaurus.io/"`, + ); }); it('id', () => { expect(logger.name('hey')).toMatchInlineSnapshot(`"hey"`); @@ -40,8 +45,7 @@ describe('interpolate', () => { expect( logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, ).toMatchInlineSnapshot( - // cSpell:ignore mpackages - `"The package at packages/docusaurus has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, + `"The package at \\"packages/docusaurus\\" has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, ); }); it('interpolates arrays with flags', () => { diff --git a/packages/docusaurus-logger/src/index.ts b/packages/docusaurus-logger/src/index.ts index 041d1d04b4b4..08e985e77ed4 100644 --- a/packages/docusaurus-logger/src/index.ts +++ b/packages/docusaurus-logger/src/index.ts @@ -9,7 +9,8 @@ import chalk, {type Chalk} from 'chalk'; type InterpolatableValue = string | number | (string | number)[]; -const path = (msg: unknown): string => chalk.cyan(chalk.underline(msg)); +const path = (msg: unknown): string => chalk.cyan(chalk.underline(`"${msg}"`)); +const url = (msg: unknown): string => chalk.cyan(chalk.underline(msg)); const name = (msg: unknown): string => chalk.blue(chalk.bold(msg)); const code = (msg: unknown): string => chalk.cyan(`\`${msg}\``); const subdue: Chalk = chalk.gray; @@ -30,6 +31,8 @@ function interpolate( switch (flag[0]) { case 'path=': return path; + case 'url=': + return url; case 'number=': return num; case 'name=': @@ -131,6 +134,7 @@ const logger = { bold: chalk.bold, dim: chalk.dim, path, + url, name, code, subdue, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/normalization.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/normalization.ts index dad431fbd172..d36be98fcd6a 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/normalization.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/normalization.ts @@ -65,7 +65,7 @@ function normalizeSidebar( throw new Error( logger.interpolate`Invalid sidebar items collection code=${JSON.stringify( sidebar, - )} in ${place}: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a code=${'type'} property). See path=${'https://docusaurus.io/docs/sidebar/items'} for all valid syntaxes.`, + )} in ${place}: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a code=${'type'} property). See url=${'https://docusaurus.io/docs/sidebar/items'} for all valid syntaxes.`, ); } diff --git a/packages/docusaurus/src/client/serverEntry.tsx b/packages/docusaurus/src/client/serverEntry.tsx index 5c6bccdc2474..32af3e4e1576 100644 --- a/packages/docusaurus/src/client/serverEntry.tsx +++ b/packages/docusaurus/src/client/serverEntry.tsx @@ -55,7 +55,7 @@ export default async function render( if (isNotDefinedErrorRegex.test((err as Error).message)) { logger.info`It looks like you are using code that should run on the client-side only. -To get around it, try using code=${'<BrowserOnly>'} (path=${'https://docusaurus.io/docs/docusaurus-core/#browseronly'}) or code=${'ExecutionEnvironment'} (path=${'https://docusaurus.io/docs/docusaurus-core/#executionenvironment'}). +To get around it, try using code=${'<BrowserOnly>'} (url=${'https://docusaurus.io/docs/docusaurus-core/#browseronly'}) or code=${'ExecutionEnvironment'} (url=${'https://docusaurus.io/docs/docusaurus-core/#executionenvironment'}). It might also require to wrap your client code in code=${'useEffect'} hook and/or import a third-party library dynamically (if any).`; } diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index fc2cf0cff7ef..169bd81115d2 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -230,7 +230,7 @@ export async function loadPlugins({ // TODO remove this deprecated lifecycle soon // deprecated since alpha-60 // TODO, 1 user reported usage of this lifecycle! https://github.com/facebook/docusaurus/issues/3918 - logger.error`Plugin code=${'routesLoaded'} lifecycle is deprecated. If you think we should keep this lifecycle, please report here: path=${'https://github.com/facebook/docusaurus/issues/3918'}`; + logger.error`Plugin code=${'routesLoaded'} lifecycle is deprecated. If you think we should keep this lifecycle, please report here: url=${'https://github.com/facebook/docusaurus/issues/3918'}`; await plugin.routesLoaded(pluginsRouteConfigs); }), From 0b3b642cfbc17d0e211c77ae9ff43c98d5df73c9 Mon Sep 17 00:00:00 2001 From: Andrei Canta <deiucanta@gmail.com> Date: Sun, 27 Mar 2022 10:01:48 +0300 Subject: [PATCH 086/405] docs: add Easypanel to showcase (#7022) * Add Easypanel site to showcase page * Upload easypanel.png * fixes Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/src/data/showcase/easypanel.png | Bin 0 -> 12556 bytes website/src/data/users.tsx | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 website/src/data/showcase/easypanel.png diff --git a/website/src/data/showcase/easypanel.png b/website/src/data/showcase/easypanel.png new file mode 100644 index 0000000000000000000000000000000000000000..400975b3d62b625622025348a29529f84fdd90f1 GIT binary patch literal 12556 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 PC;*DGsxp;QrosOU^-Uiy literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 96e4d1efc175..d9e1bf63b1ec 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -522,6 +522,14 @@ const Users: User[] = [ source: 'https://github.com/authdog/easyjwt/tree/master/docs', tags: ['opensource', 'i18n'], }, + { + title: 'Easypanel', + description: 'Server control panel based on Docker', + preview: require('./showcase/easypanel.png'), + website: 'https://easypanel.io', + source: null, + tags: ['product'], + }, { title: 'EduLinks', description: 'Catalog of free educational resources. STEM, ESL and more.', From 39486682ba184b6daf35bb8c9fb97e1544825fef Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Sun, 27 Mar 2022 11:20:49 +0300 Subject: [PATCH 087/405] fix: make docs page wrapper take full height (#7025) * fix: make page wrapper take full height * Better solution --- .../src/theme/DocPage/Layout/index.tsx | 2 +- .../src/theme/DocPage/Layout/styles.module.css | 6 +++++- .../docusaurus-theme-classic/src/theme/DocPage/index.tsx | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx index 77d148811826..858a24e39183 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx @@ -20,7 +20,7 @@ export default function DocPageLayout({children}: Props): JSX.Element { const sidebar = useDocsSidebar(); const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); return ( - <Layout> + <Layout wrapperClassName={styles.docsWrapper}> <BackToTopButton /> <div className={styles.docPage}> {sidebar && ( diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css index 8b3e52ce13e5..bd1e23dfd80f 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css @@ -10,10 +10,14 @@ --doc-sidebar-hidden-width: 30px; } +.docPage { + width: 100%; +} + +.docsWrapper, .docPage, .docMainContainer { display: flex; - width: 100%; } .docSidebarContainer { diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index 8ee721f9862b..2c908cc05535 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -77,6 +77,7 @@ export default function DocPage(props: Props): JSX.Element { /> <HtmlClassNameProvider className={clsx( + // TODO: it should be removed from here ThemeClassNames.wrapper.docsPages, ThemeClassNames.page.docsDocPage, props.versionMetadata.className, From 2b58485c8391a35b01b890829c5842b5aafc555c Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Sun, 27 Mar 2022 14:04:59 +0300 Subject: [PATCH 088/405] refactor: console output improvements (#7029) --- packages/docusaurus/src/commands/serve.ts | 2 +- packages/docusaurus/src/commands/start.ts | 4 ++-- .../swizzle/__tests__/__snapshots__/actions.test.ts.snap | 6 +++--- .../swizzle/__tests__/__snapshots__/index.test.ts.snap | 8 ++++---- packages/docusaurus/src/commands/swizzle/actions.ts | 4 ++-- packages/docusaurus/src/commands/swizzle/index.ts | 4 ++-- .../server/__tests__/__snapshots__/config.test.ts.snap | 2 +- .../__tests__/__snapshots__/configValidation.test.ts.snap | 4 ++-- packages/docusaurus/src/server/configValidation.ts | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus/src/commands/serve.ts b/packages/docusaurus/src/commands/serve.ts index eed951fda525..80d3c51a25db 100644 --- a/packages/docusaurus/src/commands/serve.ts +++ b/packages/docusaurus/src/commands/serve.ts @@ -69,7 +69,7 @@ export default async function serve( }); }); - logger.success`Serving path=${cliOptions.dir} directory at path=${ + logger.success`Serving path=${cliOptions.dir} directory at url=${ servingUrl + baseUrl }.`; server.listen(port); diff --git a/packages/docusaurus/src/commands/start.ts b/packages/docusaurus/src/commands/start.ts index 776128478c29..bf3e37e26af3 100644 --- a/packages/docusaurus/src/commands/start.ts +++ b/packages/docusaurus/src/commands/start.ts @@ -60,7 +60,7 @@ export default async function start( const urls = prepareUrls(protocol, host, port); const openUrl = normalizeUrl([urls.localUrlForBrowser, baseUrl]); - logger.success`Docusaurus website is running at path=${openUrl}.`; + logger.success`Docusaurus website is running at url=${openUrl}.`; // Reload files processing. const reload = _.debounce(() => { @@ -68,7 +68,7 @@ export default async function start( .then(({baseUrl: newBaseUrl}) => { const newOpenUrl = normalizeUrl([urls.localUrlForBrowser, newBaseUrl]); if (newOpenUrl !== openUrl) { - logger.success`Docusaurus website is running at path=${newOpenUrl}.`; + logger.success`Docusaurus website is running at url=${newOpenUrl}.`; } }) .catch((err) => { diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap index 7473f7a0233d..3483ffb8a487 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/actions.test.ts.snap @@ -47,7 +47,7 @@ exports[`wrap TypeScript wrap ComponentInFolder 2`] = ` import type ComponentInFolderType from '@theme/ComponentInFolder'; import ComponentInFolder from '@theme-original/ComponentInFolder'; -type Props = ComponentProps<typeof ComponentInFolderType> +type Props = ComponentProps<typeof ComponentInFolderType>; export default function ComponentInFolderWrapper(props: Props): JSX.Element { return ( @@ -64,7 +64,7 @@ exports[`wrap TypeScript wrap ComponentInFolder/ComponentInSubFolder 2`] = ` import type ComponentInSubFolderType from '@theme/ComponentInFolder/ComponentInSubFolder'; import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; -type Props = ComponentProps<typeof ComponentInSubFolderType> +type Props = ComponentProps<typeof ComponentInSubFolderType>; export default function ComponentInSubFolderWrapper(props: Props): JSX.Element { return ( @@ -81,7 +81,7 @@ exports[`wrap TypeScript wrap FirstLevelComponent 2`] = ` import type FirstLevelComponentType from '@theme/FirstLevelComponent'; import FirstLevelComponent from '@theme-original/FirstLevelComponent'; -type Props = ComponentProps<typeof FirstLevelComponentType> +type Props = ComponentProps<typeof FirstLevelComponentType>; export default function FirstLevelComponentWrapper(props: Props): JSX.Element { return ( diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/index.test.ts.snap index faeadf641e2f..e48def8da891 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/commands/swizzle/__tests__/__snapshots__/index.test.ts.snap @@ -275,7 +275,7 @@ exports[`swizzle wrap ComponentInFolder TS: ComponentInFolder/index.tsx 1`] = ` import type ComponentInFolderType from '@theme/ComponentInFolder'; import ComponentInFolder from '@theme-original/ComponentInFolder'; -type Props = ComponentProps<typeof ComponentInFolderType> +type Props = ComponentProps<typeof ComponentInFolderType>; export default function ComponentInFolderWrapper(props: Props): JSX.Element { return ( @@ -319,7 +319,7 @@ exports[`swizzle wrap ComponentInFolder/ComponentInSubFolder TS: ComponentInFold import type ComponentInSubFolderType from '@theme/ComponentInFolder/ComponentInSubFolder'; import ComponentInSubFolder from '@theme-original/ComponentInFolder/ComponentInSubFolder'; -type Props = ComponentProps<typeof ComponentInSubFolderType> +type Props = ComponentProps<typeof ComponentInSubFolderType>; export default function ComponentInSubFolderWrapper(props: Props): JSX.Element { return ( @@ -363,7 +363,7 @@ exports[`swizzle wrap ComponentInFolder/Sibling TS: ComponentInFolder/Sibling.ts import type SiblingType from '@theme/ComponentInFolder/Sibling'; import Sibling from '@theme-original/ComponentInFolder/Sibling'; -type Props = ComponentProps<typeof SiblingType> +type Props = ComponentProps<typeof SiblingType>; export default function SiblingWrapper(props: Props): JSX.Element { return ( @@ -405,7 +405,7 @@ exports[`swizzle wrap FirstLevelComponent TS: FirstLevelComponent.tsx 1`] = ` import type FirstLevelComponentType from '@theme/FirstLevelComponent'; import FirstLevelComponent from '@theme-original/FirstLevelComponent'; -type Props = ComponentProps<typeof FirstLevelComponentType> +type Props = ComponentProps<typeof FirstLevelComponentType>; export default function FirstLevelComponentWrapper(props: Props): JSX.Element { return ( diff --git a/packages/docusaurus/src/commands/swizzle/actions.ts b/packages/docusaurus/src/commands/swizzle/actions.ts index 8cb892950700..5e4592ff544f 100644 --- a/packages/docusaurus/src/commands/swizzle/actions.ts +++ b/packages/docusaurus/src/commands/swizzle/actions.ts @@ -88,7 +88,7 @@ export async function eject({ ); } catch (err) { throw new Error( - logger.interpolate`Could not copy file from ${sourceFile} to ${targetFile}`, + logger.interpolate`Could not copy file from path=${sourceFile} to path=${targetFile}`, ); } return targetFile; @@ -126,7 +126,7 @@ export async function wrap({ import type ${componentName}Type from '@theme/${themeComponentName}'; import ${componentName} from '@theme-${importType}/${themeComponentName}'; -type Props = ComponentProps<typeof ${componentName}Type> +type Props = ComponentProps<typeof ${componentName}Type>; export default function ${wrapperComponentName}(props: Props): JSX.Element { return ( diff --git a/packages/docusaurus/src/commands/swizzle/index.ts b/packages/docusaurus/src/commands/swizzle/index.ts index a391bd1cc906..604b7266c96d 100644 --- a/packages/docusaurus/src/commands/swizzle/index.ts +++ b/packages/docusaurus/src/commands/swizzle/index.ts @@ -133,7 +133,7 @@ export default async function swizzle( typescript, }); logger.success` -Created wrapper of name=${componentName} from name=${themeName} in path=${result.createdFiles}. +Created wrapper of name=${componentName} from name=${themeName} in path=${result.createdFiles} `; return result; } @@ -144,7 +144,7 @@ Created wrapper of name=${componentName} from name=${themeName} in path=${result componentName, }); logger.success` -Ejected name=${componentName} from name=${themeName} to path=${result.createdFiles}. +Ejected name=${componentName} from name=${themeName} to path=${result.createdFiles} `; return result; } diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index 05963da88ac7..01a7674fb5c0 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -8,7 +8,7 @@ exports[`loadConfig website with incomplete siteConfig 1`] = ` exports[`loadConfig website with useless field (wrong field) in siteConfig 1`] = ` "These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js. If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/docusaurus.config.js/#customfields" +See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `; exports[`loadConfig website with valid async config 1`] = ` diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap index 0c24cbaf8b8a..0d5185c5a678 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -153,11 +153,11 @@ exports[`normalizeConfig throws error for required fields 1`] = ` \\"stylesheets\\" must be an array These field(s) (\\"invalidField\\",) are not recognized in docusaurus.config.js. If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/docusaurus.config.js/#customfields" +See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `; exports[`normalizeConfig throws error for unknown field 1`] = ` "These field(s) (\\"invalid\\",) are not recognized in docusaurus.config.js. If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/docusaurus.config.js/#customfields" +See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `; diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 4ad81037565b..a25659ae892e 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -258,7 +258,7 @@ export function validateConfig( '', ); formattedError = unknownFields - ? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${DEFAULT_CONFIG_FILE_NAME}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/docusaurus.config.js/#customfields` + ? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${DEFAULT_CONFIG_FILE_NAME}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/api/docusaurus-config/#customfields` : formattedError; throw new Error(formattedError); } else { From 57f7881a3d40e7d53c904256986ed59273e65c44 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Sun, 27 Mar 2022 18:44:38 +0300 Subject: [PATCH 089/405] fix: expand doc main container to full width on mobiles (#7030) --- .../src/theme/DocPage/Layout/styles.module.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css index bd1e23dfd80f..bcd30b7193b2 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/styles.module.css @@ -10,7 +10,8 @@ --doc-sidebar-hidden-width: 30px; } -.docPage { +.docPage, +.docMainContainer { width: 100%; } From 755b03861cf89de47adf38992c6df175fe37f74d Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 28 Mar 2022 09:57:04 +0800 Subject: [PATCH 090/405] fix(theme): only parse HTML- and JSX-style comments in MD code (#7033) --- packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index 8b89983bcbac..dbc24112151c 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -61,6 +61,10 @@ function getAllMagicCommentDirectiveStyles(lang: string) { case 'py': return getCommentPattern(['python']); + case 'markdown': + case 'md': + return getCommentPattern(['html', 'jsx']); + default: // all comment types return getCommentPattern(Object.keys(commentPatterns) as CommentType[]); From c81d21a641ace97598ebe794edd073b1baaab40c Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 28 Mar 2022 11:15:37 +0800 Subject: [PATCH 091/405] refactor: minor type improvements (#7035) --- .../docusaurus-module-type-aliases/src/index.d.ts | 15 +++------------ .../src/plugin-content-docs.d.ts | 10 ++++------ packages/docusaurus-types/package.json | 1 + packages/docusaurus-types/src/index.d.ts | 9 ++------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 5cc70d825d4d..3e5d0bc0663b 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -56,18 +56,9 @@ declare module '@generated/globalData' { } declare module '@generated/i18n' { - const i18n: { - defaultLocale: string; - locales: [string, ...string[]]; - currentLocale: string; - localeConfigs: { - [localeName: string]: { - label: string; - direction: string; - htmlLang: string; - }; - }; - }; + import type {I18n} from '@docusaurus/types'; + + const i18n: I18n; export = i18n; } diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 40aad894e8b6..92d375fc700a 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -647,13 +647,11 @@ declare module '@docusaurus/plugin-content-docs/client' { sidebars?: {[sidebarId: string]: GlobalSidebar}; }; - export type GlobalSidebarLink = { - label: string; - path: string; - }; - export type GlobalSidebar = { - link?: GlobalSidebarLink; + link?: { + label: string; + path: string; + }; // ... we may add other things here later }; export type GlobalPluginData = { diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index 33ffb60a213f..df32340b1745 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -16,6 +16,7 @@ "test": "tsc -p ." }, "dependencies": { + "@docusaurus/react-loadable": "5.5.2", "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", "commander": "^5.1.0", "history": "^4.9.0", diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 41866831df71..4b8ec2208704 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -10,7 +10,7 @@ import type {CustomizeRuleString} from 'webpack-merge/dist/types'; import type {CommanderStatic} from 'commander'; import type {ParsedUrlQueryInput} from 'querystring'; import type Joi from 'joi'; -import type {Overwrite, DeepPartial} from 'utility-types'; +import type {Overwrite, DeepPartial, DeepRequired} from 'utility-types'; import type {Location} from 'history'; import type Loadable from 'react-loadable'; @@ -130,12 +130,7 @@ export type I18nConfig = { localeConfigs: {[locale: string]: Partial<I18nLocaleConfig>}; }; -export type I18n = { - defaultLocale: string; - locales: [string, ...string[]]; - currentLocale: string; - localeConfigs: {[locale: string]: I18nLocaleConfig}; -}; +export type I18n = DeepRequired<I18nConfig> & {currentLocale: string}; export type GlobalData = {[pluginName: string]: {[pluginId: string]: unknown}}; From 85a79fd9b96c82ca7cde162d7e5b77a0bac95697 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 28 Mar 2022 17:12:36 +0800 Subject: [PATCH 092/405] refactor(core): reorganize functions (#7037) --- .../src/__tests__/index.test.ts | 2 +- .../src/__tests__/i18nUtils.test.ts | 84 ++++++ packages/docusaurus-utils/src/i18nUtils.ts | 50 +++- packages/docusaurus-utils/src/index.ts | 1 + packages/docusaurus/src/commands/build.ts | 2 +- packages/docusaurus/src/commands/clear.ts | 2 +- packages/docusaurus/src/commands/deploy.ts | 4 +- packages/docusaurus/src/commands/external.ts | 9 +- packages/docusaurus/src/commands/serve.ts | 4 +- packages/docusaurus/src/commands/start.ts | 2 +- .../commands/swizzle/__tests__/index.test.ts | 2 +- .../src/commands/swizzle/context.ts | 12 +- .../docusaurus/src/commands/swizzle/index.ts | 2 +- .../src/commands/writeHeadingIds.ts | 12 +- .../src/commands/writeTranslations.ts | 12 +- packages/docusaurus/src/index.ts | 30 +-- .../siteMetadata}/dummy-plugin.js | 0 .../__fixtures__/siteMetadata}/package.json | 0 .../server/__tests__/clientModules.test.ts | 107 ++++++++ .../src/server/__tests__/config.test.ts | 2 +- .../src/server/__tests__/htmlTags.test.ts | 224 ++++++++++++++++ .../src/server/__tests__/i18n.test.ts | 85 +----- .../src/server/__tests__/routes.test.ts | 2 +- .../siteMetadata.test.ts} | 10 +- .../__tests__/__fixtures__/plugin-empty.js | 13 - .../__tests__/__fixtures__/plugin-foo-bar.js | 16 -- .../__fixtures__/plugin-hello-world.js | 16 -- .../client-modules/__tests__/index.test.ts | 91 ------- .../index.ts => clientModules.ts} | 4 +- packages/docusaurus/src/server/config.ts | 2 +- .../__tests__/__fixtures__/plugin-empty.js | 12 - .../__tests__/__fixtures__/plugin-headTags.js | 26 -- .../__fixtures__/plugin-postBodyTags.js | 22 -- .../__fixtures__/plugin-preBodyTags.js | 23 -- .../html-tags/__tests__/htmlTags.test.ts | 122 --------- .../server/html-tags/__tests__/index.test.ts | 92 ------- .../src/server/html-tags/htmlTags.ts | 50 ---- .../docusaurus/src/server/html-tags/index.ts | 52 ---- packages/docusaurus/src/server/htmlTags.ts | 81 ++++++ packages/docusaurus/src/server/i18n.ts | 30 +-- packages/docusaurus/src/server/index.ts | 243 +----------------- .../__fixtures__/presets}/preset-mixed.js | 0 .../__fixtures__/presets}/preset-plugins.js | 0 .../__fixtures__/presets}/preset-themes.js | 0 .../__snapshots__/index.test.ts.snap | 129 ++-------- .../__snapshots__/presets.test.ts.snap} | 0 .../__snapshots__/routeConfig.test.ts.snap | 105 ++++++++ .../server/plugins/__tests__/index.test.ts | 152 +++-------- .../src/server/plugins/__tests__/init.test.ts | 14 +- .../__tests__/presets.test.ts} | 30 ++- ...ilingSlash.test.ts => routeConfig.test.ts} | 88 ++++++- .../server/plugins/applyRouteTrailingSlash.ts | 27 -- .../docusaurus/src/server/plugins/configs.ts | 55 ++++ .../docusaurus/src/server/plugins/index.ts | 64 +---- .../docusaurus/src/server/plugins/init.ts | 14 +- .../{presets/index.ts => plugins/presets.ts} | 2 +- .../src/server/plugins/routeConfig.ts | 67 +++++ .../src/server/plugins/synthetic.ts | 129 ++++++++++ packages/docusaurus/src/server/routes.ts | 2 +- .../{versions/index.ts => siteMetadata.ts} | 58 ++++- .../src/server/themes/__tests__/alias.test.ts | 2 +- .../docusaurus/src/server/themes/alias.ts | 2 +- .../docusaurus/src/server/themes/index.ts | 4 +- .../src/server/translations/translations.ts | 12 +- 64 files changed, 1207 insertions(+), 1304 deletions(-) rename packages/docusaurus/src/server/{versions/__tests__/__fixtures__ => __tests__/__fixtures__/siteMetadata}/dummy-plugin.js (100%) rename packages/docusaurus/src/server/{versions/__tests__/__fixtures__ => __tests__/__fixtures__/siteMetadata}/package.json (100%) create mode 100644 packages/docusaurus/src/server/__tests__/clientModules.test.ts create mode 100644 packages/docusaurus/src/server/__tests__/htmlTags.test.ts rename packages/docusaurus/src/server/{versions/__tests__/index.test.ts => __tests__/siteMetadata.test.ts} (73%) delete mode 100644 packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js delete mode 100644 packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js delete mode 100644 packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js delete mode 100644 packages/docusaurus/src/server/client-modules/__tests__/index.test.ts rename packages/docusaurus/src/server/{client-modules/index.ts => clientModules.ts} (81%) delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-empty.js delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-headTags.js delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-postBodyTags.js delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-preBodyTags.js delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts delete mode 100644 packages/docusaurus/src/server/html-tags/__tests__/index.test.ts delete mode 100644 packages/docusaurus/src/server/html-tags/htmlTags.ts delete mode 100644 packages/docusaurus/src/server/html-tags/index.ts create mode 100644 packages/docusaurus/src/server/htmlTags.ts rename packages/docusaurus/src/server/{presets/__tests__/__fixtures__ => plugins/__tests__/__fixtures__/presets}/preset-mixed.js (100%) rename packages/docusaurus/src/server/{presets/__tests__/__fixtures__ => plugins/__tests__/__fixtures__/presets}/preset-plugins.js (100%) rename packages/docusaurus/src/server/{presets/__tests__/__fixtures__ => plugins/__tests__/__fixtures__/presets}/preset-themes.js (100%) rename packages/docusaurus/src/server/{presets/__tests__/__snapshots__/index.test.ts.snap => plugins/__tests__/__snapshots__/presets.test.ts.snap} (100%) create mode 100644 packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap rename packages/docusaurus/src/server/{presets/__tests__/index.test.ts => plugins/__tests__/presets.test.ts} (73%) rename packages/docusaurus/src/server/plugins/__tests__/{applyRouteTrailingSlash.test.ts => routeConfig.test.ts} (71%) delete mode 100644 packages/docusaurus/src/server/plugins/applyRouteTrailingSlash.ts create mode 100644 packages/docusaurus/src/server/plugins/configs.ts rename packages/docusaurus/src/server/{presets/index.ts => plugins/presets.ts} (95%) create mode 100644 packages/docusaurus/src/server/plugins/routeConfig.ts create mode 100644 packages/docusaurus/src/server/plugins/synthetic.ts rename packages/docusaurus/src/server/{versions/index.ts => siteMetadata.ts} (50%) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 382b0f636580..8093071f166e 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -17,7 +17,7 @@ import {loadContext} from '@docusaurus/core/src/server/index'; import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils'; import type {RouteConfig} from '@docusaurus/types'; import {posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; -import {sortConfig} from '@docusaurus/core/src/server/plugins'; +import {sortConfig} from '@docusaurus/core/src/server/plugins/routeConfig'; import * as cliDocs from '../cli'; import {validateOptions} from '../options'; diff --git a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts index e33207afc6d0..6e66d7e4a056 100644 --- a/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/i18nUtils.test.ts @@ -5,10 +5,12 @@ * LICENSE file in the root directory of this source tree. */ +import path from 'path'; import { mergeTranslations, updateTranslationFileMessages, getPluginI18nPath, + localizePath, } from '../i18nUtils'; describe('mergeTranslations', () => { @@ -93,3 +95,85 @@ describe('getPluginI18nPath', () => { ).toMatchInlineSnapshot(`"/i18n/zh-Hans/plugin-content-docs"`); }); }); + +describe('localizePath', () => { + it('localizes url path with current locale', () => { + expect( + localizePath({ + pathType: 'url', + path: '/baseUrl', + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + currentLocale: 'fr', + localeConfigs: {}, + }, + options: {localizePath: true}, + }), + ).toBe('/baseUrl/fr/'); + }); + + it('localizes fs path with current locale', () => { + expect( + localizePath({ + pathType: 'fs', + path: '/baseFsPath', + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + currentLocale: 'fr', + localeConfigs: {}, + }, + options: {localizePath: true}, + }), + ).toBe(`${path.sep}baseFsPath${path.sep}fr`); + }); + + it('localizes path for default locale, if requested', () => { + expect( + localizePath({ + pathType: 'url', + path: '/baseUrl/', + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + currentLocale: 'en', + localeConfigs: {}, + }, + options: {localizePath: true}, + }), + ).toBe('/baseUrl/en/'); + }); + + it('does not localize path for default locale by default', () => { + expect( + localizePath({ + pathType: 'url', + path: '/baseUrl/', + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + currentLocale: 'en', + localeConfigs: {}, + }, + // options: {localizePath: true}, + }), + ).toBe('/baseUrl/'); + }); + + it('localizes path for non-default locale by default', () => { + expect( + localizePath({ + pathType: 'url', + path: '/baseUrl/', + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + currentLocale: 'en', + localeConfigs: {}, + }, + // options: {localizePath: true}, + }), + ).toBe('/baseUrl/'); + }); +}); diff --git a/packages/docusaurus-utils/src/i18nUtils.ts b/packages/docusaurus-utils/src/i18nUtils.ts index 83bec7163ff5..950f3719a7b0 100644 --- a/packages/docusaurus-utils/src/i18nUtils.ts +++ b/packages/docusaurus-utils/src/i18nUtils.ts @@ -7,8 +7,13 @@ import path from 'path'; import _ from 'lodash'; -import type {TranslationFileContent, TranslationFile} from '@docusaurus/types'; +import type { + TranslationFileContent, + TranslationFile, + I18n, +} from '@docusaurus/types'; import {DEFAULT_PLUGIN_ID, I18N_DIR_NAME} from './constants'; +import {normalizeUrl} from './urlUtils'; /** * Takes a list of translation file contents, and shallow-merges them into one. @@ -65,3 +70,46 @@ export function getPluginI18nPath({ ...subPaths, ); } + +/** + * Takes a path and returns a localized a version (which is basically `path + + * i18n.currentLocale`). + */ +export function localizePath({ + pathType, + path: originalPath, + i18n, + options = {}, +}: { + /** + * FS paths will treat Windows specially; URL paths will always have a + * trailing slash to make it a valid base URL. + */ + pathType: 'fs' | 'url'; + /** The path, URL or file path, to be localized. */ + path: string; + /** The current i18n context. */ + i18n: I18n; + options?: { + /** + * By default, we don't localize the path of defaultLocale. This option + * would override that behavior. Setting `false` is useful for `yarn build + * -l zh-Hans` to always emit into the root build directory. + */ + localizePath?: boolean; + }; +}): string { + const shouldLocalizePath: boolean = + // + options.localizePath ?? i18n.currentLocale !== i18n.defaultLocale; + + if (!shouldLocalizePath) { + return originalPath; + } + // FS paths need special care, for Windows support + if (pathType === 'fs') { + return path.join(originalPath, i18n.currentLocale); + } + // Url paths; add a trailing slash so it's a valid base URL + return normalizeUrl([originalPath, i18n.currentLocale, '/']); +} diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index a41197ea0666..999cc1928f08 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -32,6 +32,7 @@ export { mergeTranslations, updateTranslationFileMessages, getPluginI18nPath, + localizePath, } from './i18nUtils'; export { removeSuffix, diff --git a/packages/docusaurus/src/commands/build.ts b/packages/docusaurus/src/commands/build.ts index e72761653397..ef8df767c6e7 100644 --- a/packages/docusaurus/src/commands/build.ts +++ b/packages/docusaurus/src/commands/build.ts @@ -28,7 +28,7 @@ import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin'; import {loadI18n} from '../server/i18n'; import {mapAsyncSequential} from '@docusaurus/utils'; -export default async function build( +export async function build( siteDir: string, cliOptions: Partial<BuildCLIOptions> = {}, // When running build, we force terminate the process to prevent async diff --git a/packages/docusaurus/src/commands/clear.ts b/packages/docusaurus/src/commands/clear.ts index b7e230a06b56..600ab0703472 100644 --- a/packages/docusaurus/src/commands/clear.ts +++ b/packages/docusaurus/src/commands/clear.ts @@ -26,7 +26,7 @@ async function removePath(entry: {path: string; description: string}) { } } -export default async function clear(siteDir: string): Promise<unknown> { +export async function clear(siteDir: string): Promise<unknown> { const generatedFolder = { path: path.join(siteDir, GENERATED_FILES_DIR_NAME), description: 'generated folder', diff --git a/packages/docusaurus/src/commands/deploy.ts b/packages/docusaurus/src/commands/deploy.ts index 75a4cd9799cc..ac7400f349d4 100644 --- a/packages/docusaurus/src/commands/deploy.ts +++ b/packages/docusaurus/src/commands/deploy.ts @@ -10,7 +10,7 @@ import shell from 'shelljs'; import logger from '@docusaurus/logger'; import {hasSSHProtocol, buildSshUrl, buildHttpsUrl} from '@docusaurus/utils'; import {loadContext} from '../server'; -import build from './build'; +import {build} from './build'; import type {BuildCLIOptions} from '@docusaurus/types'; import path from 'path'; import os from 'os'; @@ -34,7 +34,7 @@ function shellExecLog(cmd: string) { } } -export default async function deploy( +export async function deploy( siteDir: string, cliOptions: Partial<BuildCLIOptions> = {}, ): Promise<void> { diff --git a/packages/docusaurus/src/commands/external.ts b/packages/docusaurus/src/commands/external.ts index 799ac9e4c648..52d06b6f336f 100644 --- a/packages/docusaurus/src/commands/external.ts +++ b/packages/docusaurus/src/commands/external.ts @@ -6,16 +6,15 @@ */ import type {CommanderStatic} from 'commander'; -import {loadContext, loadPluginConfigs} from '../server'; -import initPlugins from '../server/plugins/init'; +import {loadContext} from '../server'; +import {initPlugins} from '../server/plugins/init'; -export default async function externalCommand( +export async function externalCommand( cli: CommanderStatic, siteDir: string, ): Promise<void> { const context = await loadContext(siteDir); - const pluginConfigs = await loadPluginConfigs(context); - const plugins = await initPlugins({pluginConfigs, context}); + const plugins = await initPlugins(context); // Plugin Lifecycle - extendCli. plugins.forEach((plugin) => { diff --git a/packages/docusaurus/src/commands/serve.ts b/packages/docusaurus/src/commands/serve.ts index 80d3c51a25db..039e477422e1 100644 --- a/packages/docusaurus/src/commands/serve.ts +++ b/packages/docusaurus/src/commands/serve.ts @@ -10,11 +10,11 @@ import serveHandler from 'serve-handler'; import logger from '@docusaurus/logger'; import path from 'path'; import {loadSiteConfig} from '../server'; -import build from './build'; +import {build} from './build'; import {getCLIOptionHost, getCLIOptionPort} from './commandUtils'; import type {ServeCLIOptions} from '@docusaurus/types'; -export default async function serve( +export async function serve( siteDir: string, cliOptions: ServeCLIOptions, ): Promise<void> { diff --git a/packages/docusaurus/src/commands/start.ts b/packages/docusaurus/src/commands/start.ts index bf3e37e26af3..81f2314c91b9 100644 --- a/packages/docusaurus/src/commands/start.ts +++ b/packages/docusaurus/src/commands/start.ts @@ -28,7 +28,7 @@ import { import {getCLIOptionHost, getCLIOptionPort} from './commandUtils'; import {getTranslationsLocaleDirPath} from '../server/translations/translations'; -export default async function start( +export async function start( siteDir: string, cliOptions: Partial<StartCLIOptions>, ): Promise<void> { diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts index 3e45151411f3..7faa5c74c91f 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts @@ -10,7 +10,7 @@ import path from 'path'; import fs from 'fs-extra'; import {ThemePath, createTempSiteDir, Components} from './testUtils'; import tree from 'tree-node-cli'; -import swizzle from '../index'; +import {swizzle} from '../index'; import {escapePath, Globby, posixPath} from '@docusaurus/utils'; const FixtureThemeName = 'fixture-theme-name'; diff --git a/packages/docusaurus/src/commands/swizzle/context.ts b/packages/docusaurus/src/commands/swizzle/context.ts index 7c06ef00c7f2..d14bce6407ee 100644 --- a/packages/docusaurus/src/commands/swizzle/context.ts +++ b/packages/docusaurus/src/commands/swizzle/context.ts @@ -5,21 +5,17 @@ * LICENSE file in the root directory of this source tree. */ -import {loadContext, loadPluginConfigs} from '../../server'; -import initPlugins, {normalizePluginConfigs} from '../../server/plugins/init'; -import type {InitializedPlugin} from '@docusaurus/types'; +import {loadContext} from '../../server'; +import {initPlugins, normalizePluginConfigs} from '../../server/plugins/init'; +import {loadPluginConfigs} from '../../server/plugins/configs'; import type {SwizzleContext} from './common'; export async function initSwizzleContext( siteDir: string, ): Promise<SwizzleContext> { const context = await loadContext(siteDir); - + const plugins = await initPlugins(context); const pluginConfigs = await loadPluginConfigs(context); - const plugins: InitializedPlugin[] = await initPlugins({ - pluginConfigs, - context, - }); const pluginsNormalized = await normalizePluginConfigs( pluginConfigs, diff --git a/packages/docusaurus/src/commands/swizzle/index.ts b/packages/docusaurus/src/commands/swizzle/index.ts index 604b7266c96d..1937785328a1 100644 --- a/packages/docusaurus/src/commands/swizzle/index.ts +++ b/packages/docusaurus/src/commands/swizzle/index.ts @@ -86,7 +86,7 @@ If you want to swizzle it, use the code=${'--danger'} flag, or confirm that you return undefined; } -export default async function swizzle( +export async function swizzle( siteDir: string, themeNameParam: string | undefined, componentNameParam: string | undefined, diff --git a/packages/docusaurus/src/commands/writeHeadingIds.ts b/packages/docusaurus/src/commands/writeHeadingIds.ts index 7c8aed4d3c59..1fa8ca558b46 100644 --- a/packages/docusaurus/src/commands/writeHeadingIds.ts +++ b/packages/docusaurus/src/commands/writeHeadingIds.ts @@ -11,8 +11,8 @@ import { writeMarkdownHeadingId, type WriteHeadingIDOptions, } from '@docusaurus/utils'; -import {loadContext, loadPluginConfigs} from '../server'; -import initPlugins from '../server/plugins/init'; +import {loadContext} from '../server'; +import {initPlugins} from '../server/plugins/init'; import {safeGlobby} from '../server/utils'; async function transformMarkdownFile( @@ -36,15 +36,11 @@ async function transformMarkdownFile( */ async function getPathsToWatch(siteDir: string): Promise<string[]> { const context = await loadContext(siteDir); - const pluginConfigs = await loadPluginConfigs(context); - const plugins = await initPlugins({ - pluginConfigs, - context, - }); + const plugins = await initPlugins(context); return plugins.flatMap((plugin) => plugin?.getPathsToWatch?.() ?? []); } -export default async function writeHeadingIds( +export async function writeHeadingIds( siteDir: string, files?: string[], options?: WriteHeadingIDOptions, diff --git a/packages/docusaurus/src/commands/writeTranslations.ts b/packages/docusaurus/src/commands/writeTranslations.ts index 2959d4527f8d..2c2ddd5b8742 100644 --- a/packages/docusaurus/src/commands/writeTranslations.ts +++ b/packages/docusaurus/src/commands/writeTranslations.ts @@ -7,8 +7,8 @@ import type {ConfigOptions, InitializedPlugin} from '@docusaurus/types'; import path from 'path'; -import {loadContext, loadPluginConfigs} from '../server'; -import initPlugins from '../server/plugins/init'; +import {loadContext} from '../server'; +import {initPlugins} from '../server/plugins/init'; import { writePluginTranslations, @@ -72,7 +72,7 @@ async function writePluginTranslationFiles({ } } -export default async function writeTranslations( +export async function writeTranslations( siteDir: string, options: WriteTranslationsOptions & ConfigOptions & {locale?: string}, ): Promise<void> { @@ -80,11 +80,7 @@ export default async function writeTranslations( customConfigFilePath: options.config, locale: options.locale, }); - const pluginConfigs = await loadPluginConfigs(context); - const plugins = await initPlugins({ - pluginConfigs, - context, - }); + const plugins = await initPlugins(context); const locale = options.locale ?? context.i18n.defaultLocale; diff --git a/packages/docusaurus/src/index.ts b/packages/docusaurus/src/index.ts index 3e08a40c4ea7..097eaad0e077 100644 --- a/packages/docusaurus/src/index.ts +++ b/packages/docusaurus/src/index.ts @@ -5,24 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import build from './commands/build'; -import clear from './commands/clear'; -import deploy from './commands/deploy'; -import externalCommand from './commands/external'; -import serve from './commands/serve'; -import start from './commands/start'; -import swizzle from './commands/swizzle'; -import writeHeadingIds from './commands/writeHeadingIds'; -import writeTranslations from './commands/writeTranslations'; - -export { - build, - clear, - deploy, - externalCommand, - serve, - start, - swizzle, - writeHeadingIds, - writeTranslations, -}; +export {build} from './commands/build'; +export {clear} from './commands/clear'; +export {deploy} from './commands/deploy'; +export {externalCommand} from './commands/external'; +export {serve} from './commands/serve'; +export {start} from './commands/start'; +export {swizzle} from './commands/swizzle'; +export {writeHeadingIds} from './commands/writeHeadingIds'; +export {writeTranslations} from './commands/writeTranslations'; diff --git a/packages/docusaurus/src/server/versions/__tests__/__fixtures__/dummy-plugin.js b/packages/docusaurus/src/server/__tests__/__fixtures__/siteMetadata/dummy-plugin.js similarity index 100% rename from packages/docusaurus/src/server/versions/__tests__/__fixtures__/dummy-plugin.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/siteMetadata/dummy-plugin.js diff --git a/packages/docusaurus/src/server/versions/__tests__/__fixtures__/package.json b/packages/docusaurus/src/server/__tests__/__fixtures__/siteMetadata/package.json similarity index 100% rename from packages/docusaurus/src/server/versions/__tests__/__fixtures__/package.json rename to packages/docusaurus/src/server/__tests__/__fixtures__/siteMetadata/package.json diff --git a/packages/docusaurus/src/server/__tests__/clientModules.test.ts b/packages/docusaurus/src/server/__tests__/clientModules.test.ts new file mode 100644 index 000000000000..c27ba51c1900 --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/clientModules.test.ts @@ -0,0 +1,107 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {loadClientModules} from '../clientModules'; +import type {LoadedPlugin} from '@docusaurus/types'; + +const pluginEmpty: LoadedPlugin = { + name: 'plugin-empty', + path: __dirname, +}; + +const pluginFooBar: LoadedPlugin = { + name: 'plugin-foo-bar', + path: __dirname, + getClientModules() { + return ['foo', 'bar']; + }, +}; + +const pluginHelloWorld: LoadedPlugin = { + plugin: 'plugin-hello-world', + path: __dirname, + getClientModules() { + return [ + // Absolute path + '/hello', + 'world', + ]; + }, +}; + +describe('loadClientModules', () => { + it('loads an empty plugin', () => { + const clientModules = loadClientModules([pluginEmpty]); + expect(clientModules).toMatchInlineSnapshot(`[]`); + }); + + it('loads a non-empty plugin', () => { + const clientModules = loadClientModules([pluginFooBar]); + expect(clientModules).toMatchInlineSnapshot(` + [ + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/foo", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/bar", + ] + `); + }); + + it('loads multiple non-empty plugins', () => { + const clientModules = loadClientModules([pluginFooBar, pluginHelloWorld]); + expect(clientModules).toMatchInlineSnapshot(` + [ + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/foo", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/bar", + "/hello", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/world", + ] + `); + }); + + it('loads multiple non-empty plugins in different order', () => { + const clientModules = loadClientModules([pluginHelloWorld, pluginFooBar]); + expect(clientModules).toMatchInlineSnapshot(` + [ + "/hello", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/world", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/foo", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/bar", + ] + `); + }); + + it('loads both empty and non-empty plugins', () => { + const clientModules = loadClientModules([ + pluginHelloWorld, + pluginEmpty, + pluginFooBar, + ]); + expect(clientModules).toMatchInlineSnapshot(` + [ + "/hello", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/world", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/foo", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/bar", + ] + `); + }); + + it('loads empty and non-empty in a different order', () => { + const clientModules = loadClientModules([ + pluginHelloWorld, + pluginFooBar, + pluginEmpty, + ]); + expect(clientModules).toMatchInlineSnapshot(` + [ + "/hello", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/world", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/foo", + "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/bar", + ] + `); + }); +}); diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 0b32cca4d1bf..71363931e68e 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -6,7 +6,7 @@ */ import path from 'path'; -import loadConfig from '../config'; +import {loadConfig} from '../config'; describe('loadConfig', () => { it('website with valid siteConfig', async () => { diff --git a/packages/docusaurus/src/server/__tests__/htmlTags.test.ts b/packages/docusaurus/src/server/__tests__/htmlTags.test.ts new file mode 100644 index 000000000000..6f7172df2aab --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/htmlTags.test.ts @@ -0,0 +1,224 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {loadHtmlTags} from '../htmlTags'; +import type {LoadedPlugin} from '@docusaurus/types'; + +const pluginEmpty: LoadedPlugin = { + name: 'plugin-empty', +}; + +const pluginPreBodyTags: LoadedPlugin = { + name: 'plugin-preBodyTags', + injectHtmlTags() { + return { + preBodyTags: { + tagName: 'script', + attributes: { + type: 'text/javascript', + async: false, + }, + innerHTML: 'window.foo = null;', + }, + }; + }, +}; + +const pluginHeadTags: LoadedPlugin = { + name: 'plugin-headTags-only', + injectHtmlTags() { + return { + headTags: [ + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'www.google-analytics.com', + }, + }, + { + tagName: 'meta', + attributes: { + name: 'generator', + content: 'Docusaurus', + }, + }, + { + tagName: 'script', + attributes: { + type: 'text/javascript', + src: 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js', + async: true, + 'data-options': '{"prop":true}', + }, + }, + ], + }; + }, +}; + +const pluginPostBodyTags: LoadedPlugin = { + name: 'plugin-postBody-tags', + injectHtmlTags() { + return { + postBodyTags: [ + { + tagName: 'div', + innerHTML: 'Test content', + }, + '<script>window.alert(1);</script>', + ], + }; + }, +}; + +const pluginMaybeInjectHeadTags: LoadedPlugin = { + name: 'plugin-postBody-tags', + injectHtmlTags() { + return undefined; + }, +}; + +describe('loadHtmlTags', () => { + it('works for an empty plugin', () => { + const htmlTags = loadHtmlTags([pluginEmpty]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "", + "postBodyTags": "", + "preBodyTags": "", + } + `); + }); + + it('only injects headTags', () => { + const htmlTags = loadHtmlTags([pluginHeadTags]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> + <meta name=\\"generator\\" content=\\"Docusaurus\\"> + <script type=\\"text/javascript\\" src=\\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\" async data-options=\\"{"prop":true}\\"></script>", + "postBodyTags": "", + "preBodyTags": "", + } + `); + }); + + it('only injects preBodyTags', () => { + const htmlTags = loadHtmlTags([pluginPreBodyTags]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "", + "postBodyTags": "", + "preBodyTags": "<script type=\\"text/javascript\\">window.foo = null;</script>", + } + `); + }); + + it('only injects postBodyTags', () => { + const htmlTags = loadHtmlTags([pluginPostBodyTags]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "", + "postBodyTags": "<div>Test content</div> + <script>window.alert(1);</script>", + "preBodyTags": "", + } + `); + }); + + it('allows multiple plugins that inject different part of html tags', () => { + const htmlTags = loadHtmlTags([ + pluginHeadTags, + pluginPostBodyTags, + pluginPreBodyTags, + ]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> + <meta name=\\"generator\\" content=\\"Docusaurus\\"> + <script type=\\"text/javascript\\" src=\\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\" async data-options=\\"{"prop":true}\\"></script>", + "postBodyTags": "<div>Test content</div> + <script>window.alert(1);</script>", + "preBodyTags": "<script type=\\"text/javascript\\">window.foo = null;</script>", + } + `); + }); + + it('allows multiple plugins that might/might not inject html tags', () => { + const htmlTags = loadHtmlTags([ + pluginEmpty, + pluginHeadTags, + pluginPostBodyTags, + pluginMaybeInjectHeadTags, + ]); + expect(htmlTags).toMatchInlineSnapshot(` + { + "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> + <meta name=\\"generator\\" content=\\"Docusaurus\\"> + <script type=\\"text/javascript\\" src=\\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\" async data-options=\\"{"prop":true}\\"></script>", + "postBodyTags": "<div>Test content</div> + <script>window.alert(1);</script>", + "preBodyTags": "", + } + `); + }); + it('throws for invalid tag', () => { + expect(() => + loadHtmlTags([ + { + injectHtmlTags() { + return { + headTags: { + tagName: 'endiliey', + attributes: { + this: 'is invalid', + }, + }, + }; + }, + }, + ]), + ).toThrowErrorMatchingInlineSnapshot( + `"Error loading {\\"tagName\\":\\"endiliey\\",\\"attributes\\":{\\"this\\":\\"is invalid\\"}}, \\"endiliey\\" is not a valid HTML tag."`, + ); + }); + + it('throws for invalid tagName', () => { + expect(() => + loadHtmlTags([ + { + injectHtmlTags() { + return { + headTags: { + tagName: true, + }, + }; + }, + }, + ]), + ).toThrowErrorMatchingInlineSnapshot( + `"{\\"tagName\\":true} is not a valid HTML tag object. \\"tagName\\" must be defined as a string."`, + ); + }); + + it('throws for invalid tag object', () => { + expect(() => + loadHtmlTags([ + { + injectHtmlTags() { + return { + headTags: 2, + }; + }, + }, + ]), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"2\\" is not a valid HTML tag object."`, + ); + }); +}); diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index 27fca3f2a89a..258adfbe7c65 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -6,9 +6,8 @@ */ import {jest} from '@jest/globals'; -import {loadI18n, localizePath, getDefaultLocaleConfig} from '../i18n'; +import {loadI18n, getDefaultLocaleConfig} from '../i18n'; import {DEFAULT_I18N_CONFIG} from '../configValidation'; -import path from 'path'; import type {I18nConfig} from '@docusaurus/types'; function testLocaleConfigsFor(locales: string[]) { @@ -166,85 +165,3 @@ describe('loadI18n', () => { ); }); }); - -describe('localizePath', () => { - it('localizes url path with current locale', () => { - expect( - localizePath({ - pathType: 'url', - path: '/baseUrl', - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - currentLocale: 'fr', - localeConfigs: {}, - }, - options: {localizePath: true}, - }), - ).toBe('/baseUrl/fr/'); - }); - - it('localizes fs path with current locale', () => { - expect( - localizePath({ - pathType: 'fs', - path: '/baseFsPath', - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - currentLocale: 'fr', - localeConfigs: {}, - }, - options: {localizePath: true}, - }), - ).toBe(`${path.sep}baseFsPath${path.sep}fr`); - }); - - it('localizes path for default locale, if requested', () => { - expect( - localizePath({ - pathType: 'url', - path: '/baseUrl/', - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - currentLocale: 'en', - localeConfigs: {}, - }, - options: {localizePath: true}, - }), - ).toBe('/baseUrl/en/'); - }); - - it('does not localize path for default locale by default', () => { - expect( - localizePath({ - pathType: 'url', - path: '/baseUrl/', - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - currentLocale: 'en', - localeConfigs: {}, - }, - // options: {localizePath: true}, - }), - ).toBe('/baseUrl/'); - }); - - it('localizes path for non-default locale by default', () => { - expect( - localizePath({ - pathType: 'url', - path: '/baseUrl/', - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - currentLocale: 'en', - localeConfigs: {}, - }, - // options: {localizePath: true}, - }), - ).toBe('/baseUrl/'); - }); -}); diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index 70d030981976..662ab03f9727 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import loadRoutes from '../routes'; +import {loadRoutes} from '../routes'; import type {RouteConfig} from '@docusaurus/types'; describe('loadRoutes', () => { diff --git a/packages/docusaurus/src/server/versions/__tests__/index.test.ts b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts similarity index 73% rename from packages/docusaurus/src/server/versions/__tests__/index.test.ts rename to packages/docusaurus/src/server/__tests__/siteMetadata.test.ts index bf8e15db6c9f..b12e0a7e172c 100644 --- a/packages/docusaurus/src/server/versions/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts @@ -5,14 +5,14 @@ * LICENSE file in the root directory of this source tree. */ -import {getPluginVersion} from '..'; +import {getPluginVersion} from '../siteMetadata'; import path from 'path'; describe('getPluginVersion', () => { it('detects external packages plugins versions', async () => { await expect( getPluginVersion( - path.join(__dirname, '__fixtures__/dummy-plugin.js'), + path.join(__dirname, '__fixtures__/siteMetadata/dummy-plugin.js'), // Make the plugin appear external. path.join(__dirname, '..', '..', '..', '..', '..', '..', 'website'), ), @@ -22,14 +22,14 @@ describe('getPluginVersion', () => { it('detects project plugins versions', async () => { await expect( getPluginVersion( - path.join(__dirname, '__fixtures__/dummy-plugin.js'), + path.join(__dirname, '__fixtures__/siteMetadata/dummy-plugin.js'), // Make the plugin appear project local. - path.join(__dirname, '__fixtures__'), + path.join(__dirname, '__fixtures__/siteMetadata'), ), ).resolves.toEqual({type: 'project'}); }); - it('detect local packages versions', async () => { + it('detects local packages versions', async () => { await expect(getPluginVersion('/', '/')).resolves.toEqual({type: 'local'}); }); }); diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js deleted file mode 100644 index def0cfe25df1..000000000000 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-empty.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-empty', - path: __dirname, - }; -}; diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js deleted file mode 100644 index 94276570052e..000000000000 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-foo-bar.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-foo-bar', - path: __dirname, - getClientModules() { - return ['foo', 'bar']; - }, - }; -}; diff --git a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js b/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js deleted file mode 100644 index 3047719c6d9e..000000000000 --- a/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/plugin-hello-world.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - plugin: 'plugin-hello-world', - path: __dirname, - getClientModules() { - return ['hello', 'world']; - }, - }; -}; diff --git a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts b/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts deleted file mode 100644 index 1eb43c28b933..000000000000 --- a/packages/docusaurus/src/server/client-modules/__tests__/index.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import loadClientModules from '../index'; - -import pluginEmpty from './__fixtures__/plugin-empty'; -import pluginFooBar from './__fixtures__/plugin-foo-bar'; -import pluginHelloWorld from './__fixtures__/plugin-hello-world'; - -describe('loadClientModules', () => { - it('empty', () => { - const clientModules = loadClientModules([pluginEmpty()]); - expect(clientModules).toMatchInlineSnapshot(`[]`); - }); - - it('non-empty', () => { - const clientModules = loadClientModules([pluginFooBar()]); - expect(clientModules).toMatchInlineSnapshot(` - [ - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", - ] - `); - }); - - it('multiple non-empty', () => { - const clientModules = loadClientModules([ - pluginFooBar(), - pluginHelloWorld(), - ]); - expect(clientModules).toMatchInlineSnapshot(` - [ - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", - ] - `); - }); - - it('multiple non-empty different order', () => { - const clientModules = loadClientModules([ - pluginHelloWorld(), - pluginFooBar(), - ]); - expect(clientModules).toMatchInlineSnapshot(` - [ - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", - ] - `); - }); - - it('empty and non-empty', () => { - const clientModules = loadClientModules([ - pluginHelloWorld(), - pluginEmpty(), - pluginFooBar(), - ]); - expect(clientModules).toMatchInlineSnapshot(` - [ - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", - ] - `); - }); - - it('empty and non-empty different order', () => { - const clientModules = loadClientModules([ - pluginHelloWorld(), - pluginFooBar(), - pluginEmpty(), - ]); - expect(clientModules).toMatchInlineSnapshot(` - [ - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/hello", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/world", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/foo", - "<PROJECT_ROOT>/packages/docusaurus/src/server/client-modules/__tests__/__fixtures__/bar", - ] - `); - }); -}); diff --git a/packages/docusaurus/src/server/client-modules/index.ts b/packages/docusaurus/src/server/clientModules.ts similarity index 81% rename from packages/docusaurus/src/server/client-modules/index.ts rename to packages/docusaurus/src/server/clientModules.ts index 6a51d751a5e6..697e4c25288a 100644 --- a/packages/docusaurus/src/server/client-modules/index.ts +++ b/packages/docusaurus/src/server/clientModules.ts @@ -8,9 +8,7 @@ import path from 'path'; import type {LoadedPlugin} from '@docusaurus/types'; -export default function loadClientModules( - plugins: LoadedPlugin<unknown>[], -): string[] { +export function loadClientModules(plugins: LoadedPlugin<unknown>[]): string[] { return plugins.flatMap( (plugin) => plugin.getClientModules?.().map((p) => path.resolve(plugin.path, p)) ?? diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 94e8656acfdc..05b3ad2e8bcd 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -10,7 +10,7 @@ import importFresh from 'import-fresh'; import type {DocusaurusConfig} from '@docusaurus/types'; import {validateConfig} from './configValidation'; -export default async function loadConfig( +export async function loadConfig( configPath: string, ): Promise<DocusaurusConfig> { if (!(await fs.pathExists(configPath))) { diff --git a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-empty.js b/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-empty.js deleted file mode 100644 index 6b8398c7d40e..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-empty.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-empty', - }; -}; diff --git a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-headTags.js b/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-headTags.js deleted file mode 100644 index 99b0d07b9ac2..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-headTags.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-headTags-only', - injectHtmlTags() { - return { - headTags: [ - { - tagName: 'link', - attributes: { - rel: 'preconnect', - href: 'www.google-analytics.com', - }, - }, - `<meta name="generator" content="docusaurus">`, - ], - }; - }, - }; -}; diff --git a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-postBodyTags.js b/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-postBodyTags.js deleted file mode 100644 index 6ce0398aed1c..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-postBodyTags.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-postBody-tags', - injectHtmlTags() { - return { - postBodyTags: [ - { - tagName: 'div', - innerHTML: 'Test content', - }, - ], - }; - }, - }; -}; diff --git a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-preBodyTags.js b/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-preBodyTags.js deleted file mode 100644 index db23f8c883d5..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/__fixtures__/plugin-preBodyTags.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -module.exports = function() { - return { - name: 'plugin-preBodyTags', - injectHtmlTags() { - return { - preBodyTags: { - tagName: 'script', - attributes: { - type: 'text/javascript', - }, - innerHTML: 'window.foo = null;', - }, - }; - }, - }; -}; diff --git a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts deleted file mode 100644 index 90d547952a50..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/htmlTags.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import htmlTagObjectToString from '../htmlTags'; - -describe('htmlTagObjectToString', () => { - it('valid html tag', () => { - expect( - htmlTagObjectToString({ - tagName: 'script', - attributes: { - type: 'text/javascript', - src: 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js', - async: true, - 'data-options': '{"prop":true}', - }, - }), - ).toMatchInlineSnapshot( - `"<script type=\\"text/javascript\\" src=\\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\" async data-options=\\"{"prop":true}\\"></script>"`, - ); - - expect( - htmlTagObjectToString({ - tagName: 'link', - attributes: { - rel: 'preconnect', - href: 'www.google-analytics.com', - }, - }), - ).toMatchInlineSnapshot( - `"<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\">"`, - ); - - expect( - htmlTagObjectToString({ - tagName: 'div', - attributes: { - style: 'background-color:lightblue', - }, - innerHTML: 'Lightblue color here', - }), - ).toMatchInlineSnapshot( - `"<div style=\\"background-color:lightblue\\">Lightblue color here</div>"`, - ); - - expect( - htmlTagObjectToString({ - tagName: 'div', - innerHTML: 'Test', - }), - ).toMatchInlineSnapshot(`"<div>Test</div>"`); - }); - - it('valid html void tag', () => { - expect( - htmlTagObjectToString({ - tagName: 'meta', - attributes: { - name: 'generator', - content: 'Docusaurus', - }, - }), - ).toMatchInlineSnapshot( - `"<meta name=\\"generator\\" content=\\"Docusaurus\\">"`, - ); - - expect( - htmlTagObjectToString({ - tagName: 'img', - attributes: { - src: '/img/docusaurus.png', - alt: 'Docusaurus logo', - height: '42', - width: '42', - }, - }), - ).toMatchInlineSnapshot( - `"<img src=\\"/img/docusaurus.png\\" alt=\\"Docusaurus logo\\" height=\\"42\\" width=\\"42\\">"`, - ); - }); - - it('invalid tag', () => { - expect(() => - htmlTagObjectToString({ - tagName: 'endiliey', - attributes: { - this: 'is invalid', - }, - }), - ).toThrowErrorMatchingInlineSnapshot( - `"Error loading {\\"tagName\\":\\"endiliey\\",\\"attributes\\":{\\"this\\":\\"is invalid\\"}}, \\"endiliey\\" is not a valid HTML tags."`, - ); - }); - - it('invalid tagName', () => { - expect(() => - htmlTagObjectToString({ - tagName: true, - }), - ).toThrowErrorMatchingInlineSnapshot( - `"{\\"tagName\\":true} is not a valid HTML tag object. \\"tagName\\" must be defined as a string."`, - ); - }); - - it('invalid html tag object', () => { - expect(() => - htmlTagObjectToString('foo'), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"foo\\" is not a valid HTML tag object."`, - ); - - expect(() => - htmlTagObjectToString(null), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"null\\" is not a valid HTML tag object."`, - ); - }); -}); diff --git a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts b/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts deleted file mode 100644 index 19786fbea4e0..000000000000 --- a/packages/docusaurus/src/server/html-tags/__tests__/index.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {loadHtmlTags} from '../index'; - -import pluginEmpty from './__fixtures__/plugin-empty'; -import pluginPreBodyTags from './__fixtures__/plugin-preBodyTags'; -import pluginHeadTags from './__fixtures__/plugin-headTags'; -import pluginPostBodyTags from './__fixtures__/plugin-postBodyTags'; - -describe('loadHtmlTags', () => { - it('empty plugin', () => { - const htmlTags = loadHtmlTags([pluginEmpty()]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "", - "postBodyTags": "", - "preBodyTags": "", - } - `); - }); - - it('only inject headTags', () => { - const htmlTags = loadHtmlTags([pluginHeadTags()]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> - <meta name=\\"generator\\" content=\\"docusaurus\\">", - "postBodyTags": "", - "preBodyTags": "", - } - `); - }); - - it('only inject preBodyTags', () => { - const htmlTags = loadHtmlTags([pluginPreBodyTags()]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "", - "postBodyTags": "", - "preBodyTags": "<script type=\\"text/javascript\\">window.foo = null;</script>", - } - `); - }); - - it('only inject postBodyTags', () => { - const htmlTags = loadHtmlTags([pluginPostBodyTags()]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "", - "postBodyTags": "<div>Test content</div>", - "preBodyTags": "", - } - `); - }); - - it('multiple plugins that inject different part of html tags', () => { - const htmlTags = loadHtmlTags([ - pluginHeadTags(), - pluginPostBodyTags(), - pluginPreBodyTags(), - ]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> - <meta name=\\"generator\\" content=\\"docusaurus\\">", - "postBodyTags": "<div>Test content</div>", - "preBodyTags": "<script type=\\"text/javascript\\">window.foo = null;</script>", - } - `); - }); - - it('multiple plugins that might/might not inject html tags', () => { - const htmlTags = loadHtmlTags([ - pluginEmpty(), - pluginHeadTags(), - pluginPostBodyTags(), - ]); - expect(htmlTags).toMatchInlineSnapshot(` - { - "headTags": "<link rel=\\"preconnect\\" href=\\"www.google-analytics.com\\"> - <meta name=\\"generator\\" content=\\"docusaurus\\">", - "postBodyTags": "<div>Test content</div>", - "preBodyTags": "", - } - `); - }); -}); diff --git a/packages/docusaurus/src/server/html-tags/htmlTags.ts b/packages/docusaurus/src/server/html-tags/htmlTags.ts deleted file mode 100644 index 83946c197858..000000000000 --- a/packages/docusaurus/src/server/html-tags/htmlTags.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {HtmlTagObject} from '@docusaurus/types'; -import htmlTags from 'html-tags'; -import voidHtmlTags from 'html-tags/void'; -import escapeHTML from 'escape-html'; - -function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject { - if (typeof val !== 'object' || !val) { - throw new Error(`"${val}" is not a valid HTML tag object.`); - } - if (typeof (val as HtmlTagObject).tagName !== 'string') { - throw new Error( - `${JSON.stringify( - val, - )} is not a valid HTML tag object. "tagName" must be defined as a string.`, - ); - } -} - -export default function htmlTagObjectToString(tagDefinition: unknown): string { - assertIsHtmlTagObject(tagDefinition); - if (htmlTags.indexOf(tagDefinition.tagName) === -1) { - throw new Error( - `Error loading ${JSON.stringify(tagDefinition)}, "${ - tagDefinition.tagName - }" is not a valid HTML tags.`, - ); - } - const isVoidTag = voidHtmlTags.indexOf(tagDefinition.tagName) !== -1; - const tagAttributes = tagDefinition.attributes ?? {}; - const attributes = Object.keys(tagAttributes) - .filter((attributeName) => tagAttributes[attributeName] !== false) - .map((attributeName) => { - if (tagAttributes[attributeName] === true) { - return attributeName; - } - return `${attributeName}="${escapeHTML( - tagAttributes[attributeName] as string, - )}"`; - }); - return `<${[tagDefinition.tagName].concat(attributes).join(' ')}>${ - (!isVoidTag && tagDefinition.innerHTML) || '' - }${isVoidTag ? '' : `</${tagDefinition.tagName}>`}`; -} diff --git a/packages/docusaurus/src/server/html-tags/index.ts b/packages/docusaurus/src/server/html-tags/index.ts deleted file mode 100644 index c32d008e12d6..000000000000 --- a/packages/docusaurus/src/server/html-tags/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import htmlTagObjectToString from './htmlTags'; -import type { - InjectedHtmlTags, - HtmlTagObject, - HtmlTags, - LoadedPlugin, -} from '@docusaurus/types'; - -function toString(val: string | HtmlTagObject): string { - return typeof val === 'string' ? val : htmlTagObjectToString(val); -} - -function createHtmlTagsString(tags: HtmlTags): string { - return Array.isArray(tags) ? tags.map(toString).join('\n') : toString(tags); -} - -export function loadHtmlTags(plugins: LoadedPlugin[]): InjectedHtmlTags { - const htmlTags = plugins.reduce( - (acc, plugin) => { - if (!plugin.injectHtmlTags) { - return acc; - } - const {headTags, preBodyTags, postBodyTags} = - plugin.injectHtmlTags({content: plugin.content}) ?? {}; - return { - headTags: headTags - ? `${acc.headTags}\n${createHtmlTagsString(headTags)}` - : acc.headTags, - preBodyTags: preBodyTags - ? `${acc.preBodyTags}\n${createHtmlTagsString(preBodyTags)}` - : acc.preBodyTags, - postBodyTags: postBodyTags - ? `${acc.postBodyTags}\n${createHtmlTagsString(postBodyTags)}` - : acc.postBodyTags, - }; - }, - {headTags: '', preBodyTags: '', postBodyTags: ''}, - ); - - return { - headTags: htmlTags.headTags.trim(), - preBodyTags: htmlTags.preBodyTags.trim(), - postBodyTags: htmlTags.postBodyTags.trim(), - }; -} diff --git a/packages/docusaurus/src/server/htmlTags.ts b/packages/docusaurus/src/server/htmlTags.ts new file mode 100644 index 000000000000..28e04cec80d1 --- /dev/null +++ b/packages/docusaurus/src/server/htmlTags.ts @@ -0,0 +1,81 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import htmlTags from 'html-tags'; +import voidHtmlTags from 'html-tags/void'; +import escapeHTML from 'escape-html'; +import _ from 'lodash'; +import type { + InjectedHtmlTags, + HtmlTagObject, + HtmlTags, + LoadedPlugin, +} from '@docusaurus/types'; + +function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject { + if (typeof val !== 'object' || !val) { + throw new Error(`"${val}" is not a valid HTML tag object.`); + } + if (typeof (val as HtmlTagObject).tagName !== 'string') { + throw new Error( + `${JSON.stringify( + val, + )} is not a valid HTML tag object. "tagName" must be defined as a string.`, + ); + } + if (!htmlTags.includes((val as HtmlTagObject).tagName)) { + throw new Error( + `Error loading ${JSON.stringify(val)}, "${ + (val as HtmlTagObject).tagName + }" is not a valid HTML tag.`, + ); + } +} + +function htmlTagObjectToString(tag: unknown): string { + assertIsHtmlTagObject(tag); + const isVoidTag = voidHtmlTags.includes(tag.tagName); + const tagAttributes = tag.attributes ?? {}; + const attributes = Object.keys(tagAttributes) + .map((attr) => { + const value = tagAttributes[attr]!; + if (typeof value === 'boolean') { + return value ? attr : undefined; + } + return `${attr}="${escapeHTML(value)}"`; + }) + .filter((str): str is string => Boolean(str)); + const openingTag = `<${[tag.tagName].concat(attributes).join(' ')}>`; + const innerHTML = (!isVoidTag && tag.innerHTML) || ''; + const closingTag = isVoidTag ? '' : `</${tag.tagName}>`; + return openingTag + innerHTML + closingTag; +} + +function createHtmlTagsString(tags: HtmlTags | undefined): string { + return (Array.isArray(tags) ? tags : [tags]) + .filter(Boolean) + .map((val) => (typeof val === 'string' ? val : htmlTagObjectToString(val))) + .join('\n'); +} + +export function loadHtmlTags(plugins: LoadedPlugin[]): InjectedHtmlTags { + const pluginHtmlTags = plugins.map( + (plugin) => plugin.injectHtmlTags?.({content: plugin.content}) ?? {}, + ); + const tagTypes = ['headTags', 'preBodyTags', 'postBodyTags'] as const; + return Object.fromEntries( + _.zip( + tagTypes, + tagTypes.map((type) => + pluginHtmlTags + .map((tags) => createHtmlTagsString(tags[type])) + .join('\n') + .trim(), + ), + ), + ); +} diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts index 713a347459cd..42b363be7de3 100644 --- a/packages/docusaurus/src/server/i18n.ts +++ b/packages/docusaurus/src/server/i18n.ts @@ -5,11 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types'; -import path from 'path'; -import {normalizeUrl} from '@docusaurus/utils'; import {getLangDir} from 'rtl-detect'; import logger from '@docusaurus/logger'; +import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types'; function getDefaultLocaleLabel(locale: string) { const languageName = new Intl.DisplayNames(locale, {type: 'language'}).of( @@ -64,29 +62,3 @@ Note: Docusaurus only support running one locale at a time.`; localeConfigs, }; } - -export function localizePath({ - pathType, - path: originalPath, - i18n, - options = {}, -}: { - pathType: 'fs' | 'url'; - path: string; - i18n: I18n; - options?: {localizePath?: boolean}; -}): string { - const shouldLocalizePath: boolean = - // By default, we don't localize the path of defaultLocale - options.localizePath ?? i18n.currentLocale !== i18n.defaultLocale; - - if (!shouldLocalizePath) { - return originalPath; - } - // FS paths need special care, for Windows support - if (pathType === 'fs') { - return path.join(originalPath, i18n.currentLocale); - } - // Url paths; add a trailing slash so it's a valid base URL - return normalizeUrl([originalPath, i18n.currentLocale, '/']); -} diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index ae4c371c1f7b..fc4c3afbeac4 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -8,40 +8,27 @@ import { generate, escapePath, + localizePath, DEFAULT_BUILD_DIR_NAME, DEFAULT_CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME, } from '@docusaurus/utils'; +import _ from 'lodash'; import path from 'path'; -import logger from '@docusaurus/logger'; import ssrDefaultTemplate from '../webpack/templates/ssr.html.template'; -import loadClientModules from './client-modules'; -import loadConfig from './config'; +import {loadClientModules} from './clientModules'; +import {loadConfig} from './config'; import {loadPlugins} from './plugins'; -import loadPresets from './presets'; -import loadRoutes from './routes'; -import type { - DocusaurusConfig, - DocusaurusSiteMetadata, - HtmlTagObject, - LoadContext, - LoadedPlugin, - PluginConfig, - Props, -} from '@docusaurus/types'; -import {loadHtmlTags} from './html-tags'; -import {getPackageJsonVersion} from './versions'; +import {loadRoutes} from './routes'; +import {loadHtmlTags} from './htmlTags'; +import {loadSiteMetadata} from './siteMetadata'; import {handleDuplicateRoutes} from './duplicateRoutes'; -import {loadI18n, localizePath} from './i18n'; +import {loadI18n} from './i18n'; import { readCodeTranslationFileContent, getPluginsDefaultCodeTranslationMessages, } from './translations/translations'; -import _ from 'lodash'; -import type {RuleSetRule} from 'webpack'; -import admonitions from 'remark-admonitions'; -import {createRequire} from 'module'; -import {resolveModuleName} from './moduleShorthand'; +import type {DocusaurusConfig, LoadContext, Props} from '@docusaurus/types'; export type LoadContextOptions = { customOutDir?: string; @@ -126,171 +113,6 @@ export async function loadContext( }; } -export async function loadPluginConfigs( - context: LoadContext, -): Promise<PluginConfig[]> { - let {plugins: presetPlugins, themes: presetThemes} = await loadPresets( - context, - ); - const {siteConfig, siteConfigPath} = context; - const require = createRequire(siteConfigPath); - function normalizeShorthand( - pluginConfig: PluginConfig, - pluginType: 'plugin' | 'theme', - ): PluginConfig { - if (typeof pluginConfig === 'string') { - return resolveModuleName(pluginConfig, require, pluginType); - } else if ( - Array.isArray(pluginConfig) && - typeof pluginConfig[0] === 'string' - ) { - return [ - resolveModuleName(pluginConfig[0], require, pluginType), - pluginConfig[1] ?? {}, - ]; - } - return pluginConfig; - } - presetPlugins = presetPlugins.map((plugin) => - normalizeShorthand(plugin, 'plugin'), - ); - presetThemes = presetThemes.map((theme) => - normalizeShorthand(theme, 'theme'), - ); - const standalonePlugins = siteConfig.plugins.map((plugin) => - normalizeShorthand(plugin, 'plugin'), - ); - const standaloneThemes = siteConfig.themes.map((theme) => - normalizeShorthand(theme, 'theme'), - ); - return [ - ...presetPlugins, - ...presetThemes, - // Site config should be the highest priority. - ...standalonePlugins, - ...standaloneThemes, - ]; -} - -// Make a fake plugin to: -// - Resolve aliased theme components -// - Inject scripts/stylesheets -function createBootstrapPlugin({ - siteDir, - siteConfig, -}: { - siteDir: string; - siteConfig: DocusaurusConfig; -}): LoadedPlugin { - const { - stylesheets, - scripts, - clientModules: siteConfigClientModules, - } = siteConfig; - return { - name: 'docusaurus-bootstrap-plugin', - content: null, - options: { - id: 'default', - }, - version: {type: 'synthetic'}, - path: siteDir, - getClientModules() { - return siteConfigClientModules; - }, - injectHtmlTags: () => { - const stylesheetsTags = stylesheets.map((source) => - typeof source === 'string' - ? `<link rel="stylesheet" href="${source}">` - : ({ - tagName: 'link', - attributes: { - rel: 'stylesheet', - ...source, - }, - } as HtmlTagObject), - ); - const scriptsTags = scripts.map((source) => - typeof source === 'string' - ? `<script src="${source}"></script>` - : ({ - tagName: 'script', - attributes: { - ...source, - }, - } as HtmlTagObject), - ); - return { - headTags: [...stylesheetsTags, ...scriptsTags], - }; - }, - }; -} - -/** - * Configure Webpack fallback mdx loader for md/mdx files out of content-plugin - * folders. Adds a "fallback" mdx loader for mdx files that are not processed by - * content plugins. This allows to do things such as importing repo/README.md as - * a partial from another doc. Not ideal solution, but good enough for now - */ -function createMDXFallbackPlugin({ - siteDir, - siteConfig, -}: { - siteDir: string; - siteConfig: DocusaurusConfig; -}): LoadedPlugin { - return { - name: 'docusaurus-mdx-fallback-plugin', - content: null, - options: { - id: 'default', - }, - version: {type: 'synthetic'}, - // Synthetic, the path doesn't matter much - path: '.', - configureWebpack(config, isServer, {getJSLoader}) { - // We need the mdx fallback loader to exclude files that were already - // processed by content plugins mdx loaders. This works, but a bit - // hacky... Not sure there's a way to handle that differently in webpack - function getMDXFallbackExcludedPaths(): string[] { - const rules: RuleSetRule[] = config?.module?.rules as RuleSetRule[]; - return rules.flatMap((rule) => { - const isMDXRule = - rule.test instanceof RegExp && rule.test.test('x.mdx'); - return isMDXRule ? (rule.include as string[]) : []; - }); - } - - return { - module: { - rules: [ - { - test: /\.mdx?$/i, - exclude: getMDXFallbackExcludedPaths(), - use: [ - getJSLoader({isServer}), - { - loader: require.resolve('@docusaurus/mdx-loader'), - options: { - staticDirs: siteConfig.staticDirectories.map((dir) => - path.resolve(siteDir, dir), - ), - siteDir, - isMDXPartial: () => true, // External mdx files are always meant to be imported as partials - isMDXPartialFrontMatterWarningDisabled: true, // External mdx files might have front matter, let's just disable the warning - remarkPlugins: [admonitions], - }, - }, - ], - }, - ], - }, - }; - }, - }; -} - export async function load( siteDir: string, options: LoadContextOptions = {}, @@ -308,9 +130,8 @@ export async function load( codeTranslations, } = context; // Plugins. - const pluginConfigs: PluginConfig[] = await loadPluginConfigs(context); const {plugins, pluginsRouteConfigs, globalData, themeConfigTranslated} = - await loadPlugins({pluginConfigs, context}); + await loadPlugins(context); // Side-effect to replace the untranslated themeConfig by the translated one context.siteConfig.themeConfig = themeConfigTranslated; @@ -341,11 +162,6 @@ export default ${JSON.stringify(siteConfig, null, 2)}; `, ); - plugins.push( - createBootstrapPlugin({siteDir, siteConfig}), - createMDXFallbackPlugin({siteDir, siteConfig}), - ); - // Load client modules. const clientModules = loadClientModules(plugins); const genClientModules = generate( @@ -416,21 +232,7 @@ ${Object.entries(registry) ); // Version metadata. - const siteMetadata: DocusaurusSiteMetadata = { - docusaurusVersion: (await getPackageJsonVersion( - path.join(__dirname, '../../package.json'), - ))!, - siteVersion: await getPackageJsonVersion( - path.join(siteDir, 'package.json'), - ), - pluginVersions: {}, - }; - plugins - .filter(({version: {type}}) => type !== 'synthetic') - .forEach(({name, version}) => { - siteMetadata.pluginVersions[name] = version; - }); - checkDocusaurusPackagesVersion(siteMetadata); + const siteMetadata = await loadSiteMetadata({plugins, siteDir}); const genSiteMetadata = generate( generatedFilesDir, 'site-metadata.json', @@ -471,26 +273,3 @@ ${Object.entries(registry) return props; } - -// We want all @docusaurus/* packages to have the exact same version! -// See https://github.com/facebook/docusaurus/issues/3371 -// See https://github.com/facebook/docusaurus/pull/3386 -function checkDocusaurusPackagesVersion(siteMetadata: DocusaurusSiteMetadata) { - const {docusaurusVersion} = siteMetadata; - Object.entries(siteMetadata.pluginVersions).forEach( - ([plugin, versionInfo]) => { - if ( - versionInfo.type === 'package' && - versionInfo.name?.startsWith('@docusaurus/') && - versionInfo.version && - versionInfo.version !== docusaurusVersion - ) { - // should we throw instead? - // It still could work with different versions - logger.error`Invalid name=${plugin} version number=${versionInfo.version}. -All official @docusaurus/* packages should have the exact same version as @docusaurus/core (number=${docusaurusVersion}). -Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`; - } - }, - ); -} diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-mixed.js b/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-mixed.js rename to packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-plugins.js b/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-plugins.js similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-plugins.js rename to packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-plugins.js diff --git a/packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-themes.js b/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-themes.js similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__fixtures__/preset-themes.js rename to packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-themes.js diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap index 7435ca95c597..0a16be1b45b0 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap @@ -37,112 +37,33 @@ exports[`loadPlugins loads plugins 1`] = ` "type": "local", }, }, - ], - "pluginsRouteConfigs": [], - "themeConfigTranslated": {}, -} -`; - -exports[`sortConfig sorts route config correctly 1`] = ` -[ - { - "component": "", - "path": "/community", - }, - { - "component": "", - "path": "/some-page", - }, - { - "component": "", - "path": "/docs", - "routes": [ - { - "component": "", - "path": "/docs/someDoc", - }, - { - "component": "", - "path": "/docs/someOtherDoc", - }, - ], - }, - { - "component": "", - "path": "/", - }, - { - "component": "", - "path": "/", - "routes": [ - { - "component": "", - "path": "/someDoc", - }, - { - "component": "", - "path": "/someOtherDoc", - }, - ], - }, - { - "component": "", - "path": "/", - "routes": [ - { - "component": "", - "path": "/subroute", - }, - ], - }, -] -`; - -exports[`sortConfig sorts route config given a baseURL 1`] = ` -[ - { - "component": "", - "path": "/latest/community", - }, - { - "component": "", - "path": "/latest/example", - }, - { - "component": "", - "path": "/latest/some-page", - }, - { - "component": "", - "path": "/latest/docs", - "routes": [ - { - "component": "", - "path": "/latest/docs/someDoc", + { + "content": undefined, + "getClientModules": [Function], + "injectHtmlTags": [Function], + "name": "docusaurus-bootstrap-plugin", + "options": { + "id": "default", }, - { - "component": "", - "path": "/latest/docs/someOtherDoc", + "path": "<PROJECT_ROOT>/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/site-with-plugin", + "version": { + "type": "synthetic", }, - ], - }, - { - "component": "", - "path": "/latest/", - }, - { - "component": "", - "path": "/latest/", - "routes": [ - { - "component": "", - "path": "/latest/someDoc", + }, + { + "configureWebpack": [Function], + "content": undefined, + "name": "docusaurus-mdx-fallback-plugin", + "options": { + "id": "default", }, - { - "component": "", - "path": "/latest/someOtherDoc", + "path": ".", + "version": { + "type": "synthetic", }, - ], - }, -] + }, + ], + "pluginsRouteConfigs": [], + "themeConfigTranslated": {}, +} `; diff --git a/packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap similarity index 100% rename from packages/docusaurus/src/server/presets/__tests__/__snapshots__/index.test.ts.snap rename to packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap new file mode 100644 index 000000000000..e38931b90952 --- /dev/null +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/routeConfig.test.ts.snap @@ -0,0 +1,105 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`sortConfig sorts route config correctly 1`] = ` +[ + { + "component": "", + "path": "/community", + }, + { + "component": "", + "path": "/some-page", + }, + { + "component": "", + "path": "/docs", + "routes": [ + { + "component": "", + "path": "/docs/someDoc", + }, + { + "component": "", + "path": "/docs/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/", + }, + { + "component": "", + "path": "/", + "routes": [ + { + "component": "", + "path": "/someDoc", + }, + { + "component": "", + "path": "/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/", + "routes": [ + { + "component": "", + "path": "/subroute", + }, + ], + }, +] +`; + +exports[`sortConfig sorts route config given a baseURL 1`] = ` +[ + { + "component": "", + "path": "/latest/community", + }, + { + "component": "", + "path": "/latest/example", + }, + { + "component": "", + "path": "/latest/some-page", + }, + { + "component": "", + "path": "/latest/docs", + "routes": [ + { + "component": "", + "path": "/latest/docs/someDoc", + }, + { + "component": "", + "path": "/latest/docs/someOtherDoc", + }, + ], + }, + { + "component": "", + "path": "/latest/", + }, + { + "component": "", + "path": "/latest/", + "routes": [ + { + "component": "", + "path": "/latest/someDoc", + }, + { + "component": "", + "path": "/latest/someOtherDoc", + }, + ], + }, +] +`; diff --git a/packages/docusaurus/src/server/plugins/__tests__/index.test.ts b/packages/docusaurus/src/server/plugins/__tests__/index.test.ts index 757c68d71d11..d585d644c4af 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/index.test.ts @@ -6,134 +6,46 @@ */ import path from 'path'; -import {loadPlugins, sortConfig} from '..'; -import type {RouteConfig} from '@docusaurus/types'; +import {loadPlugins} from '..'; describe('loadPlugins', () => { it('loads plugins', async () => { const siteDir = path.join(__dirname, '__fixtures__/site-with-plugin'); await expect( loadPlugins({ - pluginConfigs: [ - () => ({ - name: 'test1', - prop: 'a', - async loadContent() { - // Testing that plugin lifecycle is bound to the plugin instance - return this.prop; - }, - async contentLoaded({content, actions}) { - actions.setGlobalData({content, prop: this.prop}); - }, - }), - () => ({ - name: 'test2', - configureWebpack() { - return {}; - }, - }), - ], - - context: { - siteDir, - generatedFilesDir: path.join(siteDir, '.docusaurus'), - outDir: path.join(siteDir, 'build'), - // @ts-expect-error: good enough - siteConfig: { - baseUrl: '/', - trailingSlash: true, - themeConfig: {}, - }, - - siteConfigPath: path.join(siteDir, 'docusaurus.config.js'), + siteDir, + generatedFilesDir: path.join(siteDir, '.docusaurus'), + outDir: path.join(siteDir, 'build'), + // @ts-expect-error: good enough + siteConfig: { + baseUrl: '/', + trailingSlash: true, + themeConfig: {}, + presets: [], + plugins: [ + () => ({ + name: 'test1', + prop: 'a', + async loadContent() { + // Testing that plugin lifecycle is bound to the plugin instance + return this.prop; + }, + async contentLoaded({content, actions}) { + actions.setGlobalData({content, prop: this.prop}); + }, + }), + ], + themes: [ + () => ({ + name: 'test2', + configureWebpack() { + return {}; + }, + }), + ], }, + siteConfigPath: path.join(siteDir, 'docusaurus.config.js'), }), ).resolves.toMatchSnapshot(); }); }); - -describe('sortConfig', () => { - it('sorts route config correctly', () => { - const routes: RouteConfig[] = [ - { - path: '/', - component: '', - routes: [ - {path: '/someDoc', component: ''}, - {path: '/someOtherDoc', component: ''}, - ], - }, - { - path: '/', - component: '', - }, - { - path: '/', - component: '', - routes: [{path: '/subroute', component: ''}], - }, - { - path: '/docs', - component: '', - routes: [ - {path: '/docs/someDoc', component: ''}, - {path: '/docs/someOtherDoc', component: ''}, - ], - }, - { - path: '/community', - component: '', - }, - { - path: '/some-page', - component: '', - }, - ]; - - sortConfig(routes); - - expect(routes).toMatchSnapshot(); - }); - - it('sorts route config given a baseURL', () => { - const baseURL = '/latest/'; - const routes: RouteConfig[] = [ - { - path: baseURL, - component: '', - routes: [ - {path: `${baseURL}someDoc`, component: ''}, - {path: `${baseURL}someOtherDoc`, component: ''}, - ], - }, - { - path: `${baseURL}example`, - component: '', - }, - { - path: `${baseURL}docs`, - component: '', - routes: [ - {path: `${baseURL}docs/someDoc`, component: ''}, - {path: `${baseURL}docs/someOtherDoc`, component: ''}, - ], - }, - { - path: `${baseURL}community`, - component: '', - }, - { - path: `${baseURL}some-page`, - component: '', - }, - { - path: `${baseURL}`, - component: '', - }, - ]; - - sortConfig(routes, baseURL); - - expect(routes).toMatchSnapshot(); - }); -}); diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index 87a553cb9247..3155775b5266 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -7,22 +7,14 @@ import path from 'path'; -import { - loadContext, - loadPluginConfigs, - type LoadContextOptions, -} from '../../index'; -import initPlugins from '../init'; +import {loadContext, type LoadContextOptions} from '../../index'; +import {initPlugins} from '../init'; describe('initPlugins', () => { async function loadSite(options: LoadContextOptions = {}) { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-plugin'); const context = await loadContext(siteDir, options); - const pluginConfigs = await loadPluginConfigs(context); - const plugins = await initPlugins({ - pluginConfigs, - context, - }); + const plugins = await initPlugins(context); return {siteDir, context, plugins}; } diff --git a/packages/docusaurus/src/server/presets/__tests__/index.test.ts b/packages/docusaurus/src/server/plugins/__tests__/presets.test.ts similarity index 73% rename from packages/docusaurus/src/server/presets/__tests__/index.test.ts rename to packages/docusaurus/src/server/plugins/__tests__/presets.test.ts index c3ce1f8b0685..a50117e371c6 100644 --- a/packages/docusaurus/src/server/presets/__tests__/index.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/presets.test.ts @@ -7,7 +7,7 @@ import path from 'path'; -import loadPresets from '../index'; +import {loadPresets} from '../presets'; import type {LoadContext} from '@docusaurus/types'; describe('loadPresets', () => { @@ -31,7 +31,9 @@ describe('loadPresets', () => { const context = { siteConfigPath: __dirname, siteConfig: { - presets: [path.join(__dirname, '__fixtures__/preset-plugins.js')], + presets: [ + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), + ], }, } as LoadContext; const presets = await loadPresets(context); @@ -43,8 +45,8 @@ describe('loadPresets', () => { siteConfigPath: __dirname, siteConfig: { presets: [ - path.join(__dirname, '__fixtures__/preset-plugins.js'), - path.join(__dirname, '__fixtures__/preset-themes.js'), + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), + path.join(__dirname, '__fixtures__/presets/preset-themes.js'), ], }, } as LoadContext; @@ -56,7 +58,9 @@ describe('loadPresets', () => { const context = { siteConfigPath: __dirname, siteConfig: { - presets: [[path.join(__dirname, '__fixtures__/preset-plugins.js')]], + presets: [ + [path.join(__dirname, '__fixtures__/presets/preset-plugins.js')], + ], }, } as Partial<LoadContext>; const presets = await loadPresets(context); @@ -69,7 +73,7 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-plugins.js'), + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), {docs: {path: '../'}}, ], ], @@ -85,11 +89,11 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-plugins.js'), + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), {docs: {path: '../'}}, ], [ - path.join(__dirname, '__fixtures__/preset-themes.js'), + path.join(__dirname, '__fixtures__/presets/preset-themes.js'), {algolia: {trackingID: 'foo'}}, ], ], @@ -105,10 +109,10 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-plugins.js'), + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), {docs: {path: '../'}}, ], - path.join(__dirname, '__fixtures__/preset-themes.js'), + path.join(__dirname, '__fixtures__/presets/preset-themes.js'), ], }, } as LoadContext; @@ -122,11 +126,11 @@ describe('loadPresets', () => { siteConfig: { presets: [ [ - path.join(__dirname, '__fixtures__/preset-plugins.js'), + path.join(__dirname, '__fixtures__/presets/preset-plugins.js'), {docs: {path: '../'}}, ], - path.join(__dirname, '__fixtures__/preset-themes.js'), - path.join(__dirname, '__fixtures__/preset-mixed.js'), + path.join(__dirname, '__fixtures__/presets/preset-themes.js'), + path.join(__dirname, '__fixtures__/presets/preset-mixed.js'), ], }, } as LoadContext; diff --git a/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts b/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts similarity index 71% rename from packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts rename to packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts index de21791fc82f..3d0e6a5a8ec7 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/applyRouteTrailingSlash.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/routeConfig.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import applyRouteTrailingSlash from '../applyRouteTrailingSlash'; +import {applyRouteTrailingSlash, sortConfig} from '../routeConfig'; import type {RouteConfig} from '@docusaurus/types'; import type {ApplyTrailingSlashParams} from '@docusaurus/utils-common'; @@ -163,3 +163,89 @@ describe('applyRouteTrailingSlash', () => { ).toEqual(route('/abc/?search#anchor', ['/abc/1?search', '/abc/2#anchor'])); }); }); + +describe('sortConfig', () => { + it('sorts route config correctly', () => { + const routes: RouteConfig[] = [ + { + path: '/', + component: '', + routes: [ + {path: '/someDoc', component: ''}, + {path: '/someOtherDoc', component: ''}, + ], + }, + { + path: '/', + component: '', + }, + { + path: '/', + component: '', + routes: [{path: '/subroute', component: ''}], + }, + { + path: '/docs', + component: '', + routes: [ + {path: '/docs/someDoc', component: ''}, + {path: '/docs/someOtherDoc', component: ''}, + ], + }, + { + path: '/community', + component: '', + }, + { + path: '/some-page', + component: '', + }, + ]; + + sortConfig(routes); + + expect(routes).toMatchSnapshot(); + }); + + it('sorts route config given a baseURL', () => { + const baseURL = '/latest/'; + const routes: RouteConfig[] = [ + { + path: baseURL, + component: '', + routes: [ + {path: `${baseURL}someDoc`, component: ''}, + {path: `${baseURL}someOtherDoc`, component: ''}, + ], + }, + { + path: `${baseURL}example`, + component: '', + }, + { + path: `${baseURL}docs`, + component: '', + routes: [ + {path: `${baseURL}docs/someDoc`, component: ''}, + {path: `${baseURL}docs/someOtherDoc`, component: ''}, + ], + }, + { + path: `${baseURL}community`, + component: '', + }, + { + path: `${baseURL}some-page`, + component: '', + }, + { + path: `${baseURL}`, + component: '', + }, + ]; + + sortConfig(routes, baseURL); + + expect(routes).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus/src/server/plugins/applyRouteTrailingSlash.ts b/packages/docusaurus/src/server/plugins/applyRouteTrailingSlash.ts deleted file mode 100644 index d81123d03b3a..000000000000 --- a/packages/docusaurus/src/server/plugins/applyRouteTrailingSlash.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {RouteConfig} from '@docusaurus/types'; -import { - applyTrailingSlash, - type ApplyTrailingSlashParams, -} from '@docusaurus/utils-common'; - -export default function applyRouteTrailingSlash( - route: RouteConfig, - params: ApplyTrailingSlashParams, -): RouteConfig { - return { - ...route, - path: applyTrailingSlash(route.path, params), - ...(route.routes && { - routes: route.routes.map((subroute) => - applyRouteTrailingSlash(subroute, params), - ), - }), - }; -} diff --git a/packages/docusaurus/src/server/plugins/configs.ts b/packages/docusaurus/src/server/plugins/configs.ts new file mode 100644 index 000000000000..94ca87424d3c --- /dev/null +++ b/packages/docusaurus/src/server/plugins/configs.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {createRequire} from 'module'; +import {loadPresets} from './presets'; +import {resolveModuleName} from '../moduleShorthand'; +import type {LoadContext, PluginConfig} from '@docusaurus/types'; + +export async function loadPluginConfigs( + context: LoadContext, +): Promise<PluginConfig[]> { + const preset = await loadPresets(context); + const {siteConfig, siteConfigPath} = context; + const require = createRequire(siteConfigPath); + function normalizeShorthand( + pluginConfig: PluginConfig, + pluginType: 'plugin' | 'theme', + ): PluginConfig { + if (typeof pluginConfig === 'string') { + return resolveModuleName(pluginConfig, require, pluginType); + } else if ( + Array.isArray(pluginConfig) && + typeof pluginConfig[0] === 'string' + ) { + return [ + resolveModuleName(pluginConfig[0], require, pluginType), + pluginConfig[1] ?? {}, + ]; + } + return pluginConfig; + } + preset.plugins = preset.plugins.map((plugin) => + normalizeShorthand(plugin, 'plugin'), + ); + preset.themes = preset.themes.map((theme) => + normalizeShorthand(theme, 'theme'), + ); + const standalonePlugins = siteConfig.plugins.map((plugin) => + normalizeShorthand(plugin, 'plugin'), + ); + const standaloneThemes = siteConfig.themes.map((theme) => + normalizeShorthand(theme, 'theme'), + ); + return [ + ...preset.plugins, + ...preset.themes, + // Site config should be the highest priority. + ...standalonePlugins, + ...standaloneThemes, + ]; +} diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 169bd81115d2..08002e8db72c 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -10,7 +10,6 @@ import fs from 'fs-extra'; import path from 'path'; import type { LoadContext, - PluginConfig, PluginContentLoadedActions, RouteConfig, AllContent, @@ -21,69 +20,26 @@ import type { InitializedPlugin, PluginRouteContext, } from '@docusaurus/types'; -import initPlugins from './init'; +import {initPlugins} from './init'; +import {createBootstrapPlugin, createMDXFallbackPlugin} from './synthetic'; import logger from '@docusaurus/logger'; import _ from 'lodash'; import {localizePluginTranslationFile} from '../translations/translations'; -import applyRouteTrailingSlash from './applyRouteTrailingSlash'; +import {applyRouteTrailingSlash, sortConfig} from './routeConfig'; -export function sortConfig( - routeConfigs: RouteConfig[], - baseUrl: string = '/', -): void { - // Sort the route config. This ensures that route with nested - // routes is always placed last. - routeConfigs.sort((a, b) => { - // Root route should get placed last. - if (a.path === baseUrl && b.path !== baseUrl) { - return 1; - } - if (a.path !== baseUrl && b.path === baseUrl) { - return -1; - } - - if (a.routes && !b.routes) { - return 1; - } - if (!a.routes && b.routes) { - return -1; - } - // Higher priority get placed first. - if (a.priority || b.priority) { - const priorityA = a.priority || 0; - const priorityB = b.priority || 0; - const score = priorityB - priorityA; - - if (score !== 0) { - return score; - } - } - - return a.path.localeCompare(b.path); - }); - - routeConfigs.forEach((routeConfig) => { - routeConfig.routes?.sort((a, b) => a.path.localeCompare(b.path)); - }); -} - -export async function loadPlugins({ - pluginConfigs, - context, -}: { - pluginConfigs: PluginConfig[]; - context: LoadContext; -}): Promise<{ +export async function loadPlugins(context: LoadContext): Promise<{ plugins: LoadedPlugin[]; pluginsRouteConfigs: RouteConfig[]; globalData: GlobalData; themeConfigTranslated: ThemeConfig; }> { // 1. Plugin Lifecycle - Initialization/Constructor. - const plugins: InitializedPlugin[] = await initPlugins({ - pluginConfigs, - context, - }); + const plugins: InitializedPlugin[] = await initPlugins(context); + + plugins.push( + createBootstrapPlugin(context), + createMDXFallbackPlugin(context), + ); // 2. Plugin Lifecycle - loadContent. // Currently plugins run lifecycle methods in parallel and are not diff --git a/packages/docusaurus/src/server/plugins/init.ts b/packages/docusaurus/src/server/plugins/init.ts index 410eb96f7ca6..326d041e8da2 100644 --- a/packages/docusaurus/src/server/plugins/init.ts +++ b/packages/docusaurus/src/server/plugins/init.ts @@ -18,12 +18,13 @@ import type { InitializedPlugin, } from '@docusaurus/types'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; -import {getPluginVersion} from '../versions'; +import {getPluginVersion} from '../siteMetadata'; import {ensureUniquePluginInstanceIds} from './pluginIds'; import { normalizePluginOptions, normalizeThemeConfig, } from '@docusaurus/utils-validation'; +import {loadPluginConfigs} from './configs'; export type NormalizedPluginConfig = { plugin: PluginModule; @@ -134,16 +135,13 @@ function getThemeValidationFunction( return normalizedPluginConfig.plugin.validateThemeConfig; } -export default async function initPlugins({ - pluginConfigs, - context, -}: { - pluginConfigs: PluginConfig[]; - context: LoadContext; -}): Promise<InitializedPlugin[]> { +export async function initPlugins( + context: LoadContext, +): Promise<InitializedPlugin[]> { // We need to resolve plugins from the perspective of the siteDir, since the // siteDir's package.json declares the dependency on these plugins. const pluginRequire = createRequire(context.siteConfigPath); + const pluginConfigs = await loadPluginConfigs(context); const pluginConfigsNormalized = await normalizePluginConfigs( pluginConfigs, context.siteConfigPath, diff --git a/packages/docusaurus/src/server/presets/index.ts b/packages/docusaurus/src/server/plugins/presets.ts similarity index 95% rename from packages/docusaurus/src/server/presets/index.ts rename to packages/docusaurus/src/server/plugins/presets.ts index e32290f510a0..d920ea2e59bd 100644 --- a/packages/docusaurus/src/server/presets/index.ts +++ b/packages/docusaurus/src/server/plugins/presets.ts @@ -14,7 +14,7 @@ import type { } from '@docusaurus/types'; import {resolveModuleName} from '../moduleShorthand'; -export default async function loadPresets(context: LoadContext): Promise<{ +export async function loadPresets(context: LoadContext): Promise<{ plugins: PluginConfig[]; themes: PluginConfig[]; }> { diff --git a/packages/docusaurus/src/server/plugins/routeConfig.ts b/packages/docusaurus/src/server/plugins/routeConfig.ts new file mode 100644 index 000000000000..63fad7cd52f6 --- /dev/null +++ b/packages/docusaurus/src/server/plugins/routeConfig.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {RouteConfig} from '@docusaurus/types'; +import { + applyTrailingSlash, + type ApplyTrailingSlashParams, +} from '@docusaurus/utils-common'; + +export function applyRouteTrailingSlash( + route: RouteConfig, + params: ApplyTrailingSlashParams, +): RouteConfig { + return { + ...route, + path: applyTrailingSlash(route.path, params), + ...(route.routes && { + routes: route.routes.map((subroute) => + applyRouteTrailingSlash(subroute, params), + ), + }), + }; +} + +export function sortConfig( + routeConfigs: RouteConfig[], + baseUrl: string = '/', +): void { + // Sort the route config. This ensures that route with nested + // routes is always placed last. + routeConfigs.sort((a, b) => { + // Root route should get placed last. + if (a.path === baseUrl && b.path !== baseUrl) { + return 1; + } + if (a.path !== baseUrl && b.path === baseUrl) { + return -1; + } + + if (a.routes && !b.routes) { + return 1; + } + if (!a.routes && b.routes) { + return -1; + } + // Higher priority get placed first. + if (a.priority || b.priority) { + const priorityA = a.priority || 0; + const priorityB = b.priority || 0; + const score = priorityB - priorityA; + + if (score !== 0) { + return score; + } + } + + return a.path.localeCompare(b.path); + }); + + routeConfigs.forEach((routeConfig) => { + routeConfig.routes?.sort((a, b) => a.path.localeCompare(b.path)); + }); +} diff --git a/packages/docusaurus/src/server/plugins/synthetic.ts b/packages/docusaurus/src/server/plugins/synthetic.ts new file mode 100644 index 000000000000..f44fad1eb3d8 --- /dev/null +++ b/packages/docusaurus/src/server/plugins/synthetic.ts @@ -0,0 +1,129 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import admonitions from 'remark-admonitions'; +import type {RuleSetRule} from 'webpack'; +import type {HtmlTagObject, LoadedPlugin, LoadContext} from '@docusaurus/types'; + +/** + * Make a synthetic plugin to: + * - Inject site client modules + * - Inject scripts/stylesheets + */ +export function createBootstrapPlugin({ + siteDir, + siteConfig, +}: LoadContext): LoadedPlugin { + const { + stylesheets, + scripts, + clientModules: siteConfigClientModules, + } = siteConfig; + return { + name: 'docusaurus-bootstrap-plugin', + content: null, + options: { + id: 'default', + }, + version: {type: 'synthetic'}, + path: siteDir, + getClientModules() { + return siteConfigClientModules; + }, + injectHtmlTags: () => { + const stylesheetsTags = stylesheets.map((source) => + typeof source === 'string' + ? `<link rel="stylesheet" href="${source}">` + : ({ + tagName: 'link', + attributes: { + rel: 'stylesheet', + ...source, + }, + } as HtmlTagObject), + ); + const scriptsTags = scripts.map((source) => + typeof source === 'string' + ? `<script src="${source}"></script>` + : ({ + tagName: 'script', + attributes: { + ...source, + }, + } as HtmlTagObject), + ); + return { + headTags: [...stylesheetsTags, ...scriptsTags], + }; + }, + }; +} + +/** + * Configure Webpack fallback mdx loader for md/mdx files out of content-plugin + * folders. Adds a "fallback" mdx loader for mdx files that are not processed by + * content plugins. This allows to do things such as importing repo/README.md as + * a partial from another doc. Not ideal solution, but good enough for now + */ +export function createMDXFallbackPlugin({ + siteDir, + siteConfig, +}: LoadContext): LoadedPlugin { + return { + name: 'docusaurus-mdx-fallback-plugin', + content: null, + options: { + id: 'default', + }, + version: {type: 'synthetic'}, + // Synthetic, the path doesn't matter much + path: '.', + configureWebpack(config, isServer, {getJSLoader}) { + // We need the mdx fallback loader to exclude files that were already + // processed by content plugins mdx loaders. This works, but a bit + // hacky... Not sure there's a way to handle that differently in webpack + function getMDXFallbackExcludedPaths(): string[] { + const rules: RuleSetRule[] = config?.module?.rules as RuleSetRule[]; + return rules.flatMap((rule) => { + const isMDXRule = + rule.test instanceof RegExp && rule.test.test('x.mdx'); + return isMDXRule ? (rule.include as string[]) : []; + }); + } + const mdxLoaderOptions = { + staticDirs: siteConfig.staticDirectories.map((dir) => + path.resolve(siteDir, dir), + ), + siteDir, + // External MDX files are always meant to be imported as partials + isMDXPartial: () => true, + // External MDX files might have front matter, just disable the warning + isMDXPartialFrontMatterWarningDisabled: true, + remarkPlugins: [admonitions], + }; + + return { + module: { + rules: [ + { + test: /\.mdx?$/i, + exclude: getMDXFallbackExcludedPaths(), + use: [ + getJSLoader({isServer}), + { + loader: require.resolve('@docusaurus/mdx-loader'), + options: mdxLoaderOptions, + }, + ], + }, + ], + }, + }; + }, + }; +} diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index b6221ec4b277..3bf9f8b37a08 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -119,7 +119,7 @@ function getModulePath(target: Module): string { return `${target.path}${queryStr}`; } -export default async function loadRoutes( +export async function loadRoutes( pluginsRouteConfigs: RouteConfig[], baseUrl: string, ): Promise<{ diff --git a/packages/docusaurus/src/server/versions/index.ts b/packages/docusaurus/src/server/siteMetadata.ts similarity index 50% rename from packages/docusaurus/src/server/versions/index.ts rename to packages/docusaurus/src/server/siteMetadata.ts index 54a3777fd1d3..996244a94102 100644 --- a/packages/docusaurus/src/server/versions/index.ts +++ b/packages/docusaurus/src/server/siteMetadata.ts @@ -5,11 +5,16 @@ * LICENSE file in the root directory of this source tree. */ -import type {PluginVersionInformation} from '@docusaurus/types'; +import type { + LoadedPlugin, + PluginVersionInformation, + DocusaurusSiteMetadata, +} from '@docusaurus/types'; import fs from 'fs-extra'; import path from 'path'; +import logger from '@docusaurus/logger'; -export async function getPackageJsonVersion( +async function getPackageJsonVersion( packageJsonPath: string, ): Promise<string | undefined> { if (await fs.pathExists(packageJsonPath)) { @@ -59,3 +64,52 @@ export async function getPluginVersion( // package.json (e.g. inline plugin), we can only classify it as local. return {type: 'local'}; } + +/** + * We want all `@docusaurus/*` packages to have the exact same version! + * @see https://github.com/facebook/docusaurus/issues/3371 + * @see https://github.com/facebook/docusaurus/pull/3386 + */ +function checkDocusaurusPackagesVersion(siteMetadata: DocusaurusSiteMetadata) { + const {docusaurusVersion} = siteMetadata; + Object.entries(siteMetadata.pluginVersions).forEach( + ([plugin, versionInfo]) => { + if ( + versionInfo.type === 'package' && + versionInfo.name?.startsWith('@docusaurus/') && + versionInfo.version && + versionInfo.version !== docusaurusVersion + ) { + // should we throw instead? + // It still could work with different versions + logger.error`Invalid name=${plugin} version number=${versionInfo.version}. +All official @docusaurus/* packages should have the exact same version as @docusaurus/core (number=${docusaurusVersion}). +Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`; + } + }, + ); +} + +export async function loadSiteMetadata({ + plugins, + siteDir, +}: { + plugins: LoadedPlugin[]; + siteDir: string; +}): Promise<DocusaurusSiteMetadata> { + const siteMetadata: DocusaurusSiteMetadata = { + docusaurusVersion: (await getPackageJsonVersion( + path.join(__dirname, '../../package.json'), + ))!, + siteVersion: await getPackageJsonVersion( + path.join(siteDir, 'package.json'), + ), + pluginVersions: Object.fromEntries( + plugins + .filter(({version: {type}}) => type !== 'synthetic') + .map(({name, version}) => [name, version]), + ), + }; + checkDocusaurusPackagesVersion(siteMetadata); + return siteMetadata; +} diff --git a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts index b0a22e9c158c..72ed3945152c 100644 --- a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts +++ b/packages/docusaurus/src/server/themes/__tests__/alias.test.ts @@ -7,7 +7,7 @@ import path from 'path'; import fs from 'fs-extra'; -import themeAlias, {sortAliases} from '../alias'; +import {themeAlias, sortAliases} from '../alias'; describe('sortAliases', () => { // https://github.com/facebook/docusaurus/issues/6878 diff --git a/packages/docusaurus/src/server/themes/alias.ts b/packages/docusaurus/src/server/themes/alias.ts index 0a63d80a832d..c5ee69aa0545 100644 --- a/packages/docusaurus/src/server/themes/alias.ts +++ b/packages/docusaurus/src/server/themes/alias.ts @@ -26,7 +26,7 @@ export function sortAliases(aliases: ThemeAliases): ThemeAliases { return Object.fromEntries(entries); } -export default async function themeAlias( +export async function themeAlias( themePath: string, addOriginalAlias: boolean, ): Promise<ThemeAliases> { diff --git a/packages/docusaurus/src/server/themes/index.ts b/packages/docusaurus/src/server/themes/index.ts index 071acd007a40..dbb8ca34e196 100644 --- a/packages/docusaurus/src/server/themes/index.ts +++ b/packages/docusaurus/src/server/themes/index.ts @@ -5,10 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import type {ThemeAliases, LoadedPlugin} from '@docusaurus/types'; import path from 'path'; import {THEME_PATH} from '@docusaurus/utils'; -import themeAlias, {sortAliases} from './alias'; +import {themeAlias, sortAliases} from './alias'; +import type {ThemeAliases, LoadedPlugin} from '@docusaurus/types'; const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback'); diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index ba749f0aeff5..a989378a0ccb 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -8,12 +8,6 @@ import path from 'path'; import fs from 'fs-extra'; import _ from 'lodash'; -import type { - TranslationFileContent, - TranslationFile, - TranslationMessage, - InitializedPlugin, -} from '@docusaurus/types'; import { getPluginI18nPath, toMessageRelativeFilePath, @@ -22,6 +16,12 @@ import { } from '@docusaurus/utils'; import {Joi} from '@docusaurus/utils-validation'; import logger from '@docusaurus/logger'; +import type { + TranslationFileContent, + TranslationFile, + TranslationMessage, + InitializedPlugin, +} from '@docusaurus/types'; export type WriteTranslationsOptions = { override?: boolean; From 5fb09a2946ca6afcafdb2e96c0b08ba90afc65fc Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 28 Mar 2022 21:49:37 +0800 Subject: [PATCH 093/405] refactor(core): reorganize files (#7042) * refactor(core): reorganize files * fix types --- .../src/index.d.ts | 4 +- .../src/translations.ts | 6 +- .../src/__tests__/docs.test.ts | 5 +- .../src/__tests__/index.test.ts | 28 +- .../src/translations.ts | 7 +- .../src/__tests__/index.test.ts | 4 +- packages/docusaurus-types/src/index.d.ts | 208 +++++++------ packages/docusaurus/package.json | 1 - packages/docusaurus/src/commands/build.ts | 6 +- .../docusaurus/src/commands/commandUtils.ts | 2 +- packages/docusaurus/src/commands/deploy.ts | 3 +- packages/docusaurus/src/commands/external.ts | 2 +- packages/docusaurus/src/commands/serve.ts | 2 +- packages/docusaurus/src/commands/start.ts | 3 +- .../docusaurus/src/commands/swizzle/common.ts | 2 +- .../src/commands/swizzle/context.ts | 11 +- .../src/commands/writeHeadingIds.ts | 2 +- .../src/commands/writeTranslations.ts | 3 +- .../__snapshots__/config.test.ts.snap | 273 +++++++++--------- .../duplicateRoutes.test.ts.snap | 10 - .../__snapshots__/routes.test.ts.snap | 9 + .../src/server/__tests__/config.test.ts | 94 +++--- .../server/__tests__/duplicateRoutes.test.ts | 53 ---- .../src/server/__tests__/routes.test.ts | 61 +++- .../src/server/__tests__/testUtils.ts | 4 +- .../docusaurus/src/{ => server}/choosePort.ts | 19 +- .../docusaurus/src/server/clientModules.ts | 6 +- packages/docusaurus/src/server/config.ts | 32 +- .../docusaurus/src/server/duplicateRoutes.ts | 51 ---- packages/docusaurus/src/server/htmlTags.ts | 10 +- packages/docusaurus/src/server/i18n.ts | 3 +- packages/docusaurus/src/server/index.ts | 112 ++++--- .../src/server/plugins/__tests__/init.test.ts | 4 +- .../__tests__/moduleShorthand.test.ts | 0 .../docusaurus/src/server/plugins/configs.ts | 92 +++++- .../docusaurus/src/server/plugins/index.ts | 88 +++--- .../docusaurus/src/server/plugins/init.ts | 101 +------ .../server/{ => plugins}/moduleShorthand.ts | 0 .../src/server/plugins/pluginIds.ts | 6 +- .../docusaurus/src/server/plugins/presets.ts | 18 +- packages/docusaurus/src/server/routes.ts | 155 ++++++---- .../docusaurus/src/server/siteMetadata.ts | 11 +- .../src/server/themes/__tests__/index.test.ts | 61 ---- .../docusaurus/src/server/themes/alias.ts | 62 ---- .../docusaurus/src/server/themes/index.ts | 61 ---- .../src/server/translations/translations.ts | 5 +- .../__tests__/__snapshots__/base.test.ts.snap | 23 -- .../src/webpack/__tests__/base.test.ts | 18 +- .../__fixtures__/theme-1/Footer/index.js | 0 .../__tests__/__fixtures__/theme-1/Layout.js | 0 .../__fixtures__/theme-2/Layout/index.js | 0 .../__tests__/__fixtures__/theme-2/Navbar.js | 0 .../NavbarItem/NestedNavbarItem/index.js | 0 .../theme-2/NavbarItem/SiblingNavbarItem.js | 0 .../__fixtures__/theme-2/NavbarItem/index.js | 0 .../__fixtures__/theme-2/NavbarItem/zzz.js | 0 .../__snapshots__/index.test.ts.snap | 129 +++++++++ .../aliases/__tests__/index.test.ts} | 64 ++-- .../docusaurus/src/webpack/aliases/index.ts | 149 ++++++++++ packages/docusaurus/src/webpack/base.ts | 32 +- website/docs/docusaurus-core.md | 4 +- 61 files changed, 1090 insertions(+), 1029 deletions(-) delete mode 100644 packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap delete mode 100644 packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts rename packages/docusaurus/src/{ => server}/choosePort.ts (88%) delete mode 100644 packages/docusaurus/src/server/duplicateRoutes.ts rename packages/docusaurus/src/server/{ => plugins}/__tests__/moduleShorthand.test.ts (100%) rename packages/docusaurus/src/server/{ => plugins}/moduleShorthand.ts (100%) delete mode 100644 packages/docusaurus/src/server/themes/__tests__/index.test.ts delete mode 100644 packages/docusaurus/src/server/themes/alias.ts delete mode 100644 packages/docusaurus/src/server/themes/index.ts rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-1/Footer/index.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-1/Layout.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/Layout/index.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/Navbar.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/NavbarItem/index.js (100%) rename packages/docusaurus/src/{server/themes => webpack/aliases}/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js (100%) create mode 100644 packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap rename packages/docusaurus/src/{server/themes/__tests__/alias.test.ts => webpack/aliases/__tests__/index.test.ts} (72%) create mode 100644 packages/docusaurus/src/webpack/aliases/index.ts diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 3e5d0bc0663b..c069c7cb7adb 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -20,9 +20,9 @@ declare module '@generated/docusaurus.config' { } declare module '@generated/site-metadata' { - import type {DocusaurusSiteMetadata} from '@docusaurus/types'; + import type {SiteMetadata} from '@docusaurus/types'; - const siteMetadata: DocusaurusSiteMetadata; + const siteMetadata: SiteMetadata; export = siteMetadata; } diff --git a/packages/docusaurus-plugin-content-blog/src/translations.ts b/packages/docusaurus-plugin-content-blog/src/translations.ts index 460e24a62480..28c233dd99c8 100644 --- a/packages/docusaurus-plugin-content-blog/src/translations.ts +++ b/packages/docusaurus-plugin-content-blog/src/translations.ts @@ -6,7 +6,7 @@ */ import type {BlogContent, BlogPaginated} from './types'; -import type {TranslationFileContent, TranslationFiles} from '@docusaurus/types'; +import type {TranslationFileContent, TranslationFile} from '@docusaurus/types'; import type {PluginOptions} from '@docusaurus/plugin-content-blog'; function translateListPage( @@ -27,7 +27,7 @@ function translateListPage( }); } -export function getTranslationFiles(options: PluginOptions): TranslationFiles { +export function getTranslationFiles(options: PluginOptions): TranslationFile[] { return [ { path: 'options', @@ -51,7 +51,7 @@ export function getTranslationFiles(options: PluginOptions): TranslationFiles { export function translateContent( content: BlogContent, - translationFiles: TranslationFiles, + translationFiles: TranslationFile[], ): BlogContent { const {content: optionsTranslations} = translationFiles[0]!; return { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index b7aa5cfe178b..0623a345cc2f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -168,7 +168,7 @@ describe('simple site', () => { loadSiteOptions: {options: Partial<PluginOptions>} = {options: {}}, ) { const siteDir = path.join(fixtureDir, 'simple-site'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const options = { id: DEFAULT_PLUGIN_ID, ...DEFAULT_OPTIONS, @@ -523,7 +523,8 @@ describe('versioned site', () => { }, ) { const siteDir = path.join(fixtureDir, 'versioned-site'); - const context = await loadContext(siteDir, { + const context = await loadContext({ + siteDir, locale: loadSiteOptions.locale, }); const options = { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 8093071f166e..926bcfb8f96f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -115,7 +115,7 @@ Entries created: describe('sidebar', () => { it('site with wrong sidebar content', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'wrong-sidebars.json'); const plugin = await pluginContentDocs( context, @@ -131,7 +131,7 @@ describe('sidebar', () => { it('site with wrong sidebar file path', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); await expect(async () => { const plugin = await pluginContentDocs( @@ -155,7 +155,7 @@ describe('sidebar', () => { it('site with undefined sidebar', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ @@ -173,7 +173,7 @@ describe('sidebar', () => { it('site with disabled sidebar', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ @@ -194,7 +194,7 @@ describe('empty/no docs website', () => { const siteDir = path.join(__dirname, '__fixtures__', 'empty-site'); it('no files in docs folder', async () => { - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); await fs.ensureDir(path.join(siteDir, 'docs')); const plugin = await pluginContentDocs( context, @@ -208,7 +208,7 @@ describe('empty/no docs website', () => { }); it('docs folder does not exist', async () => { - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); await expect( pluginContentDocs( context, @@ -228,7 +228,7 @@ describe('empty/no docs website', () => { describe('simple website', () => { async function loadSite() { const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'sidebars.json'); const plugin = await pluginContentDocs( context, @@ -341,7 +341,7 @@ describe('simple website', () => { describe('versioned website', () => { async function loadSite() { const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'sidebars.json'); const routeBasePath = 'docs'; const plugin = await pluginContentDocs( @@ -470,7 +470,7 @@ describe('versioned website', () => { describe('versioned website (community)', () => { async function loadSite() { const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'community_sidebars.json'); const routeBasePath = 'community'; const pluginId = 'community'; @@ -578,7 +578,7 @@ describe('versioned website (community)', () => { describe('site with doc label', () => { async function loadSite() { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-doc-label'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'sidebars.json'); const plugin = await pluginContentDocs( context, @@ -620,7 +620,7 @@ describe('site with full autogenerated sidebar', () => { '__fixtures__', 'site-with-autogenerated-sidebar', ); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ @@ -675,7 +675,7 @@ describe('site with partial autogenerated sidebars', () => { '__fixtures__', 'site-with-autogenerated-sidebar', ); - const context = await loadContext(siteDir, {}); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ @@ -731,7 +731,7 @@ describe('site with partial autogenerated sidebars 2 (fix #4638)', () => { '__fixtures__', 'site-with-autogenerated-sidebar', ); - const context = await loadContext(siteDir, {}); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ @@ -768,7 +768,7 @@ describe('site with custom sidebar items generator', () => { '__fixtures__', 'site-with-autogenerated-sidebar', ); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentDocs( context, validateOptions({ diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index cc43d6b3f061..4289f3579adf 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -22,7 +22,6 @@ import { import type { TranslationFileContent, TranslationFile, - TranslationFiles, TranslationMessage, } from '@docusaurus/types'; import {mergeTranslations} from '@docusaurus/utils'; @@ -242,7 +241,7 @@ function translateSidebars( ); } -function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles { +function getVersionTranslationFiles(version: LoadedVersion): TranslationFile[] { const versionTranslations: TranslationFileContent = { 'version.label': { message: version.label, @@ -283,7 +282,7 @@ function translateVersion( function getVersionsTranslationFiles( versions: LoadedVersion[], -): TranslationFiles { +): TranslationFile[] { return versions.flatMap(getVersionTranslationFiles); } function translateVersions( @@ -295,7 +294,7 @@ function translateVersions( export function getLoadedContentTranslationFiles( loadedContent: LoadedContent, -): TranslationFiles { +): TranslationFile[] { return getVersionsTranslationFiles(loadedContent.loadedVersions); } export function translateLoadedContent( diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts index 7e3df9c7d129..89221c819bc8 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/index.test.ts @@ -15,7 +15,7 @@ import {normalizePluginOptions} from '@docusaurus/utils-validation'; describe('docusaurus-plugin-content-pages', () => { it('loads simple pages', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentPages( context, validateOptions({ @@ -32,7 +32,7 @@ describe('docusaurus-plugin-content-pages', () => { it('loads simple pages with french translations', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugin = await pluginContentPages( { ...context, diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 4b8ec2208704..0d0db0682136 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -10,7 +10,11 @@ import type {CustomizeRuleString} from 'webpack-merge/dist/types'; import type {CommanderStatic} from 'commander'; import type {ParsedUrlQueryInput} from 'querystring'; import type Joi from 'joi'; -import type {Overwrite, DeepPartial, DeepRequired} from 'utility-types'; +import type { + Required as RequireKeys, + DeepPartial, + DeepRequired, +} from 'utility-types'; import type {Location} from 'history'; import type Loadable from 'react-loadable'; @@ -20,16 +24,23 @@ export type ThemeConfig = { [key: string]: unknown; }; -// Docusaurus config, after validation/normalization -export interface DocusaurusConfig { +/** + * Docusaurus config, after validation/normalization. + */ +export type DocusaurusConfig = { + /** + * Always has both leading and trailing slash (`/base/`). May be localized. + */ baseUrl: string; baseUrlIssueBanner: boolean; favicon?: string; tagline: string; title: string; url: string; - // trailingSlash undefined = legacy retrocompatible behavior - // /file => /file/index.html + /** + * `undefined` = legacy retrocompatible behavior. Usually it means `/file` => + * `/file/index.html`. + */ trailingSlash: boolean | undefined; i18n: I18nConfig; onBrokenLinks: ReportingSeverity; @@ -69,19 +80,16 @@ export interface DocusaurusConfig { webpack?: { jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule); }; -} - -// Docusaurus config, as provided by the user (partial/unnormalized) -// This type is used to provide type-safety / IDE auto-complete on the config -// file. See https://docusaurus.io/docs/typescript-support -export type Config = Overwrite< - Partial<DocusaurusConfig>, - { - title: Required<DocusaurusConfig['title']>; - url: Required<DocusaurusConfig['url']>; - baseUrl: Required<DocusaurusConfig['baseUrl']>; - i18n?: DeepPartial<DocusaurusConfig['i18n']>; - } +}; + +/** + * Docusaurus config, as provided by the user (partial/unnormalized). This type + * is used to provide type-safety / IDE auto-complete on the config file. + * @see https://docusaurus.io/docs/typescript-support + */ +export type Config = RequireKeys< + DeepPartial<DocusaurusConfig>, + 'title' | 'url' | 'baseUrl' >; /** @@ -101,11 +109,11 @@ export type PluginVersionInformation = | {readonly type: 'local'} | {readonly type: 'synthetic'}; -export interface DocusaurusSiteMetadata { +export type SiteMetadata = { readonly docusaurusVersion: string; readonly siteVersion?: string; readonly pluginVersions: {[pluginName: string]: PluginVersionInformation}; -} +}; // Inspired by Chrome JSON, because it's a widely supported i18n format // https://developer.chrome.com/apps/i18n-messages @@ -116,7 +124,6 @@ export interface DocusaurusSiteMetadata { export type TranslationMessage = {message: string; description?: string}; export type TranslationFileContent = {[key: string]: TranslationMessage}; export type TranslationFile = {path: string; content: TranslationFileContent}; -export type TranslationFiles = TranslationFile[]; export type I18nLocaleConfig = { label: string; @@ -134,9 +141,9 @@ export type I18n = DeepRequired<I18nConfig> & {currentLocale: string}; export type GlobalData = {[pluginName: string]: {[pluginId: string]: unknown}}; -export interface DocusaurusContext { +export type DocusaurusContext = { siteConfig: DocusaurusConfig; - siteMetadata: DocusaurusSiteMetadata; + siteMetadata: SiteMetadata; globalData: GlobalData; i18n: I18n; codeTranslations: {[msgId: string]: string}; @@ -144,12 +151,12 @@ export interface DocusaurusContext { // Don't put mutable values here, to avoid triggering re-renders // We could reconsider that choice if context selectors are implemented // isBrowser: boolean; // Not here on purpose! -} +}; -export interface Preset { +export type Preset = { plugins?: PluginConfig[]; themes?: PluginConfig[]; -} +}; export type PresetModule = { <T>(context: LoadContext, presetOptions: T): Preset; @@ -195,38 +202,40 @@ export type BuildCLIOptions = BuildOptions & { locale?: string; }; -export interface LoadContext { +export type LoadContext = { siteDir: string; generatedFilesDir: string; siteConfig: DocusaurusConfig; siteConfigPath: string; outDir: string; - baseUrl: string; // TODO to remove: useless, there's already siteConfig.baseUrl! + /** + * Duplicated from `siteConfig.baseUrl`, but probably worth keeping. We mutate + * `siteConfig` to make `baseUrl` there localized as well, but that's mostly + * for client-side. `context.baseUrl` is still more convenient for plugins. + */ + baseUrl: string; i18n: I18n; ssrTemplate: string; codeTranslations: {[msgId: string]: string}; -} - -export interface InjectedHtmlTags { - headTags: string; - preBodyTags: string; - postBodyTags: string; -} +}; export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[]; -export interface Props extends LoadContext, InjectedHtmlTags { - readonly siteMetadata: DocusaurusSiteMetadata; +export type Props = LoadContext & { + readonly headTags: string; + readonly preBodyTags: string; + readonly postBodyTags: string; + readonly siteMetadata: SiteMetadata; readonly routes: RouteConfig[]; readonly routesPaths: string[]; readonly plugins: LoadedPlugin[]; -} +}; -export interface PluginContentLoadedActions { +export type PluginContentLoadedActions = { addRoute: (config: RouteConfig) => void; createData: (name: string, data: string) => Promise<string>; setGlobalData: (data: unknown) => void; -} +}; export type AllContent = { [pluginName: string]: { @@ -237,7 +246,7 @@ export type AllContent = { // TODO improve type (not exposed by postcss-loader) export type PostCssOptions = {[key: string]: unknown} & {plugins: unknown[]}; -export interface Plugin<Content = unknown> { +export type Plugin<Content = unknown> = { name: string; loadContent?: () => Promise<Content>; contentLoaded?: (args: { @@ -273,19 +282,56 @@ export interface Plugin<Content = unknown> { // TODO before/afterDevServer implementation // translations - getTranslationFiles?: (args: {content: Content}) => Promise<TranslationFiles>; + getTranslationFiles?: (args: { + content: Content; + }) => Promise<TranslationFile[]>; getDefaultCodeTranslationMessages?: () => Promise<{[id: string]: string}>; translateContent?: (args: { - content: Content; // the content loaded by this plugin instance - translationFiles: TranslationFiles; + /** The content loaded by this plugin instance. */ + content: Content; + translationFiles: TranslationFile[]; }) => Content; translateThemeConfig?: (args: { themeConfig: ThemeConfig; - translationFiles: TranslationFiles; + translationFiles: TranslationFile[]; }) => ThemeConfig; -} +}; + +export type NormalizedPluginConfig = { + /** + * The default export of the plugin module, or alternatively, what's provided + * in the config file as inline plugins. Note that if a file is like: + * + * ```ts + * export default plugin() {...} + * export validateOptions() {...} + * ``` + * + * Then the static methods may not exist here. `pluginModule.module` will + * always take priority. + */ + plugin: PluginModule; + /** Options as they are provided in the config, not validated yet. */ + options: PluginOptions; + /** Only available when a string is provided in config. */ + pluginModule?: { + /** + * Raw module name as provided in the config. Shorthands have been resolved, + * so at least it's directly `require.resolve`able. + */ + path: string; + /** Whatever gets imported with `require`. */ + module: ImportedPluginModule; + }; + /** + * Different from `pluginModule.path`, this one is always an absolute path, + * used to resolve relative paths returned from lifecycles. If it's an inline + * plugin, it will be path to the config file. + */ + entryPath: string; +}; -export type InitializedPlugin<Content = unknown> = Plugin<Content> & { +export type InitializedPlugin = Plugin & { readonly options: Required<PluginOptions>; readonly version: PluginVersionInformation; /** @@ -294,8 +340,8 @@ export type InitializedPlugin<Content = unknown> = Plugin<Content> & { readonly path: string; }; -export type LoadedPlugin<Content = unknown> = InitializedPlugin<Content> & { - readonly content: Content; +export type LoadedPlugin = InitializedPlugin & { + readonly content: unknown; }; export type SwizzleAction = 'eject' | 'wrap'; @@ -314,9 +360,7 @@ export type SwizzleConfig = { }; export type PluginModule = { - <Options, Content>(context: LoadContext, options: Options): - | Plugin<Content> - | Promise<Plugin<Content>>; + (context: LoadContext, options: unknown): Plugin | Promise<Plugin>; validateOptions?: <T, U>(data: OptionValidationContext<T, U>) => U; validateThemeConfig?: <T>(data: ThemeConfigValidationContext<T>) => T; @@ -328,11 +372,11 @@ export type ImportedPluginModule = PluginModule & { default?: PluginModule; }; -export type ConfigureWebpackFn = Plugin<unknown>['configureWebpack']; +export type ConfigureWebpackFn = Plugin['configureWebpack']; export type ConfigureWebpackFnMergeStrategy = { [key: string]: CustomizeRuleString; }; -export type ConfigurePostCssFn = Plugin<unknown>['configurePostCss']; +export type ConfigurePostCssFn = Plugin['configurePostCss']; export type PluginOptions = {id?: string} & {[key: string]: unknown}; @@ -342,10 +386,10 @@ export type PluginConfig = | [PluginModule, PluginOptions] | PluginModule; -export interface ChunkRegistry { +export type ChunkRegistry = { loader: string; modulePath: string; -} +}; export type Module = | { @@ -355,15 +399,15 @@ export type Module = } | string; -export interface RouteModule { +export type RouteModule = { [module: string]: Module | RouteModule | RouteModule[]; -} +}; -export interface ChunkNames { +export type ChunkNames = { [name: string]: string | null | ChunkNames | ChunkNames[]; -} +}; -export interface RouteConfig { +export type RouteConfig = { path: string; component: string; modules?: RouteModule; @@ -371,25 +415,25 @@ export interface RouteConfig { exact?: boolean; priority?: number; [propName: string]: unknown; -} +}; -export interface RouteContext { +export type RouteContext = { /** * Plugin-specific context data. */ data?: object | undefined; -} +}; /** * Top-level plugin routes automatically add some context data to the route. * This permits us to know which plugin is handling the current route. */ -export interface PluginRouteContext extends RouteContext { +export type PluginRouteContext = RouteContext & { plugin: { id: string; name: string; }; -} +}; export type Route = { readonly path: string; @@ -398,12 +442,14 @@ export type Route = { readonly routes?: Route[]; }; -// Aliases used for Webpack resolution (when using docusaurus swizzle) -export interface ThemeAliases { +/** + * Aliases used for Webpack resolution (useful for implementing swizzling) + */ +export type ThemeAliases = { [alias: string]: string; -} +}; -export interface ConfigureWebpackUtils { +export type ConfigureWebpackUtils = { getStyleLoaders: ( isServer: boolean, cssOptions: { @@ -414,23 +460,19 @@ export interface ConfigureWebpackUtils { isServer: boolean; babelOptions?: {[key: string]: unknown}; }) => RuleSetRule; -} +}; -interface HtmlTagObject { +type HtmlTagObject = { /** - * Attributes of the html tag - * E.g. `{'disabled': true, 'value': 'demo', 'rel': 'preconnect'}` + * Attributes of the html tag. + * E.g. `{ disabled: true, value: "demo", rel: "preconnect" }` */ attributes?: Partial<{[key: string]: string | boolean}>; - /** - * The tag name e.g. `div`, `script`, `link`, `meta` - */ + /** The tag name, e.g. `div`, `script`, `link`, `meta` */ tagName: string; - /** - * The inner HTML - */ + /** The inner HTML */ innerHTML?: string; -} +}; export type ValidationSchema<T> = Joi.ObjectSchema<T>; @@ -444,10 +486,10 @@ export type OptionValidationContext<T, U> = { options: T; }; -export interface ThemeConfigValidationContext<T> { +export type ThemeConfigValidationContext<T> = { validate: Validate<T, T>; themeConfig: Partial<T>; -} +}; export type TOCItem = { readonly value: string; diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index e4776f9e4895..544e9a85e7b1 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -74,7 +74,6 @@ "html-tags": "^3.1.0", "html-webpack-plugin": "^5.5.0", "import-fresh": "^3.3.0", - "is-root": "^2.1.0", "leven": "^3.1.0", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.6.0", diff --git a/packages/docusaurus/src/commands/build.ts b/packages/docusaurus/src/commands/build.ts index ef8df767c6e7..252c797d6a09 100644 --- a/packages/docusaurus/src/commands/build.ts +++ b/packages/docusaurus/src/commands/build.ts @@ -61,7 +61,8 @@ export async function build( throw err; } } - const context = await loadContext(siteDir, { + const context = await loadContext({ + siteDir, customOutDir: cliOptions.outDir, customConfigFilePath: cliOptions.config, locale: cliOptions.locale, @@ -109,7 +110,8 @@ async function buildLocale({ process.env.NODE_ENV = 'production'; logger.info`name=${`[${locale}]`} Creating an optimized production build...`; - const props: Props = await load(siteDir, { + const props: Props = await load({ + siteDir, customOutDir: cliOptions.outDir, customConfigFilePath: cliOptions.config, locale, diff --git a/packages/docusaurus/src/commands/commandUtils.ts b/packages/docusaurus/src/commands/commandUtils.ts index cfa5f7e920c1..d14d5b8977ad 100644 --- a/packages/docusaurus/src/commands/commandUtils.ts +++ b/packages/docusaurus/src/commands/commandUtils.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import choosePort from '../choosePort'; +import {choosePort} from '../server/choosePort'; import type {HostPortCLIOptions} from '@docusaurus/types'; import {DEFAULT_PORT} from '@docusaurus/utils'; diff --git a/packages/docusaurus/src/commands/deploy.ts b/packages/docusaurus/src/commands/deploy.ts index ac7400f349d4..2de40addb16e 100644 --- a/packages/docusaurus/src/commands/deploy.ts +++ b/packages/docusaurus/src/commands/deploy.ts @@ -38,7 +38,8 @@ export async function deploy( siteDir: string, cliOptions: Partial<BuildCLIOptions> = {}, ): Promise<void> { - const {outDir, siteConfig, siteConfigPath} = await loadContext(siteDir, { + const {outDir, siteConfig, siteConfigPath} = await loadContext({ + siteDir, customConfigFilePath: cliOptions.config, customOutDir: cliOptions.outDir, }); diff --git a/packages/docusaurus/src/commands/external.ts b/packages/docusaurus/src/commands/external.ts index 52d06b6f336f..eb8c1b94f26b 100644 --- a/packages/docusaurus/src/commands/external.ts +++ b/packages/docusaurus/src/commands/external.ts @@ -13,7 +13,7 @@ export async function externalCommand( cli: CommanderStatic, siteDir: string, ): Promise<void> { - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugins = await initPlugins(context); // Plugin Lifecycle - extendCli. diff --git a/packages/docusaurus/src/commands/serve.ts b/packages/docusaurus/src/commands/serve.ts index 039e477422e1..c1ef7e9e6e00 100644 --- a/packages/docusaurus/src/commands/serve.ts +++ b/packages/docusaurus/src/commands/serve.ts @@ -9,7 +9,7 @@ import http from 'http'; import serveHandler from 'serve-handler'; import logger from '@docusaurus/logger'; import path from 'path'; -import {loadSiteConfig} from '../server'; +import {loadSiteConfig} from '../server/config'; import {build} from './build'; import {getCLIOptionHost, getCLIOptionPort} from './commandUtils'; import type {ServeCLIOptions} from '@docusaurus/types'; diff --git a/packages/docusaurus/src/commands/start.ts b/packages/docusaurus/src/commands/start.ts index 81f2314c91b9..39da01713433 100644 --- a/packages/docusaurus/src/commands/start.ts +++ b/packages/docusaurus/src/commands/start.ts @@ -37,7 +37,8 @@ export async function start( logger.info('Starting the development server...'); function loadSite() { - return load(siteDir, { + return load({ + siteDir, customConfigFilePath: cliOptions.config, locale: cliOptions.locale, localizePath: undefined, // should this be configurable? diff --git a/packages/docusaurus/src/commands/swizzle/common.ts b/packages/docusaurus/src/commands/swizzle/common.ts index 1dfdb04cf3ae..2d399b60a731 100644 --- a/packages/docusaurus/src/commands/swizzle/common.ts +++ b/packages/docusaurus/src/commands/swizzle/common.ts @@ -12,8 +12,8 @@ import type { InitializedPlugin, SwizzleAction, SwizzleActionStatus, + NormalizedPluginConfig, } from '@docusaurus/types'; -import type {NormalizedPluginConfig} from '../../server/plugins/init'; export const SwizzleActions: SwizzleAction[] = ['wrap', 'eject']; diff --git a/packages/docusaurus/src/commands/swizzle/context.ts b/packages/docusaurus/src/commands/swizzle/context.ts index d14bce6407ee..721bedca758a 100644 --- a/packages/docusaurus/src/commands/swizzle/context.ts +++ b/packages/docusaurus/src/commands/swizzle/context.ts @@ -6,25 +6,20 @@ */ import {loadContext} from '../../server'; -import {initPlugins, normalizePluginConfigs} from '../../server/plugins/init'; +import {initPlugins} from '../../server/plugins/init'; import {loadPluginConfigs} from '../../server/plugins/configs'; import type {SwizzleContext} from './common'; export async function initSwizzleContext( siteDir: string, ): Promise<SwizzleContext> { - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugins = await initPlugins(context); const pluginConfigs = await loadPluginConfigs(context); - const pluginsNormalized = await normalizePluginConfigs( - pluginConfigs, - context.siteConfigPath, - ); - return { plugins: plugins.map((plugin, pluginIndex) => ({ - plugin: pluginsNormalized[pluginIndex]!, + plugin: pluginConfigs[pluginIndex]!, instance: plugin, })), }; diff --git a/packages/docusaurus/src/commands/writeHeadingIds.ts b/packages/docusaurus/src/commands/writeHeadingIds.ts index 1fa8ca558b46..83481a8f0708 100644 --- a/packages/docusaurus/src/commands/writeHeadingIds.ts +++ b/packages/docusaurus/src/commands/writeHeadingIds.ts @@ -35,7 +35,7 @@ async function transformMarkdownFile( * transformed */ async function getPathsToWatch(siteDir: string): Promise<string[]> { - const context = await loadContext(siteDir); + const context = await loadContext({siteDir}); const plugins = await initPlugins(context); return plugins.flatMap((plugin) => plugin?.getPathsToWatch?.() ?? []); } diff --git a/packages/docusaurus/src/commands/writeTranslations.ts b/packages/docusaurus/src/commands/writeTranslations.ts index 2c2ddd5b8742..1e8a7f13637e 100644 --- a/packages/docusaurus/src/commands/writeTranslations.ts +++ b/packages/docusaurus/src/commands/writeTranslations.ts @@ -76,7 +76,8 @@ export async function writeTranslations( siteDir: string, options: WriteTranslationsOptions & ConfigOptions & {locale?: string}, ): Promise<void> { - const context = await loadContext(siteDir, { + const context = await loadContext({ + siteDir, customConfigFilePath: options.config, locale: options.locale, }); diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index 01a7674fb5c0..914b41fe1cdf 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -1,161 +1,162 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`loadConfig website with incomplete siteConfig 1`] = ` -"\\"url\\" is required -" -`; - -exports[`loadConfig website with useless field (wrong field) in siteConfig 1`] = ` -"These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js. -If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. -See https://docusaurus.io/docs/api/docusaurus-config/#customfields" -`; - -exports[`loadConfig website with valid async config 1`] = ` +exports[`loadSiteConfig website with valid async config 1`] = ` { - "baseUrl": "/", - "baseUrlIssueBanner": true, - "clientModules": [], - "customFields": {}, - "i18n": { - "defaultLocale": "en", - "localeConfigs": {}, - "locales": [ - "en", + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + }, + "noIndex": false, + "onBrokenLinks": "throw", + "onBrokenMarkdownLinks": "warn", + "onDuplicateRoutes": "warn", + "organizationName": "endiliey", + "plugins": [], + "presets": [], + "projectName": "hello", + "scripts": [], + "staticDirectories": [ + "static", ], + "stylesheets": [], + "tagline": "Hello World", + "themeConfig": {}, + "themes": [], + "title": "Hello", + "titleDelimiter": "|", + "url": "https://docusaurus.io", }, - "noIndex": false, - "onBrokenLinks": "throw", - "onBrokenMarkdownLinks": "warn", - "onDuplicateRoutes": "warn", - "organizationName": "endiliey", - "plugins": [], - "presets": [], - "projectName": "hello", - "scripts": [], - "staticDirectories": [ - "static", - ], - "stylesheets": [], - "tagline": "Hello World", - "themeConfig": {}, - "themes": [], - "title": "Hello", - "titleDelimiter": "|", - "url": "https://docusaurus.io", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js", } `; -exports[`loadConfig website with valid async config creator function 1`] = ` +exports[`loadSiteConfig website with valid async config creator function 1`] = ` { - "baseUrl": "/", - "baseUrlIssueBanner": true, - "clientModules": [], - "customFields": {}, - "i18n": { - "defaultLocale": "en", - "localeConfigs": {}, - "locales": [ - "en", + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + }, + "noIndex": false, + "onBrokenLinks": "throw", + "onBrokenMarkdownLinks": "warn", + "onDuplicateRoutes": "warn", + "organizationName": "endiliey", + "plugins": [], + "presets": [], + "projectName": "hello", + "scripts": [], + "staticDirectories": [ + "static", ], + "stylesheets": [], + "tagline": "Hello World", + "themeConfig": {}, + "themes": [], + "title": "Hello", + "titleDelimiter": "|", + "url": "https://docusaurus.io", }, - "noIndex": false, - "onBrokenLinks": "throw", - "onBrokenMarkdownLinks": "warn", - "onDuplicateRoutes": "warn", - "organizationName": "endiliey", - "plugins": [], - "presets": [], - "projectName": "hello", - "scripts": [], - "staticDirectories": [ - "static", - ], - "stylesheets": [], - "tagline": "Hello World", - "themeConfig": {}, - "themes": [], - "title": "Hello", - "titleDelimiter": "|", - "url": "https://docusaurus.io", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js", } `; -exports[`loadConfig website with valid config creator function 1`] = ` +exports[`loadSiteConfig website with valid config creator function 1`] = ` { - "baseUrl": "/", - "baseUrlIssueBanner": true, - "clientModules": [], - "customFields": {}, - "i18n": { - "defaultLocale": "en", - "localeConfigs": {}, - "locales": [ - "en", + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + }, + "noIndex": false, + "onBrokenLinks": "throw", + "onBrokenMarkdownLinks": "warn", + "onDuplicateRoutes": "warn", + "organizationName": "endiliey", + "plugins": [], + "presets": [], + "projectName": "hello", + "scripts": [], + "staticDirectories": [ + "static", ], + "stylesheets": [], + "tagline": "Hello World", + "themeConfig": {}, + "themes": [], + "title": "Hello", + "titleDelimiter": "|", + "url": "https://docusaurus.io", }, - "noIndex": false, - "onBrokenLinks": "throw", - "onBrokenMarkdownLinks": "warn", - "onDuplicateRoutes": "warn", - "organizationName": "endiliey", - "plugins": [], - "presets": [], - "projectName": "hello", - "scripts": [], - "staticDirectories": [ - "static", - ], - "stylesheets": [], - "tagline": "Hello World", - "themeConfig": {}, - "themes": [], - "title": "Hello", - "titleDelimiter": "|", - "url": "https://docusaurus.io", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js", } `; -exports[`loadConfig website with valid siteConfig 1`] = ` +exports[`loadSiteConfig website with valid siteConfig 1`] = ` { - "baseUrl": "/", - "baseUrlIssueBanner": true, - "clientModules": [], - "customFields": {}, - "favicon": "img/docusaurus.ico", - "i18n": { - "defaultLocale": "en", - "localeConfigs": {}, - "locales": [ - "en", + "siteConfig": { + "baseUrl": "/", + "baseUrlIssueBanner": true, + "clientModules": [], + "customFields": {}, + "favicon": "img/docusaurus.ico", + "i18n": { + "defaultLocale": "en", + "localeConfigs": {}, + "locales": [ + "en", + ], + }, + "noIndex": false, + "onBrokenLinks": "throw", + "onBrokenMarkdownLinks": "warn", + "onDuplicateRoutes": "warn", + "organizationName": "endiliey", + "plugins": [ + [ + "@docusaurus/plugin-content-docs", + { + "path": "../docs", + }, + ], + "@docusaurus/plugin-content-pages", ], - }, - "noIndex": false, - "onBrokenLinks": "throw", - "onBrokenMarkdownLinks": "warn", - "onDuplicateRoutes": "warn", - "organizationName": "endiliey", - "plugins": [ - [ - "@docusaurus/plugin-content-docs", - { - "path": "../docs", - }, + "presets": [], + "projectName": "hello", + "scripts": [], + "staticDirectories": [ + "static", ], - "@docusaurus/plugin-content-pages", - ], - "presets": [], - "projectName": "hello", - "scripts": [], - "staticDirectories": [ - "static", - ], - "stylesheets": [], - "tagline": "Hello World", - "themeConfig": {}, - "themes": [], - "title": "Hello", - "titleDelimiter": "|", - "url": "https://docusaurus.io", + "stylesheets": [], + "tagline": "Hello World", + "themeConfig": {}, + "themes": [], + "title": "Hello", + "titleDelimiter": "|", + "url": "https://docusaurus.io", + }, + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js", } `; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap deleted file mode 100644 index 77e5891b69d6..000000000000 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/duplicateRoutes.test.ts.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`handleDuplicateRoutes works 1`] = ` -"Duplicate routes found! -- Attempting to create page at /search, but a page already exists at this route. -- Attempting to create page at /sameDoc, but a page already exists at this route. -- Attempting to create page at /, but a page already exists at this route. -- Attempting to create page at /, but a page already exists at this route. -This could lead to non-deterministic routing behavior." -`; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index 31aa85debae3..7870bab42380 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -1,5 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`handleDuplicateRoutes works 1`] = ` +"Duplicate routes found! +- Attempting to create page at /search, but a page already exists at this route. +- Attempting to create page at /sameDoc, but a page already exists at this route. +- Attempting to create page at /, but a page already exists at this route. +- Attempting to create page at /, but a page already exists at this route. +This could lead to non-deterministic routing behavior." +`; + exports[`loadRoutes loads flat route config 1`] = ` { "registry": { diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 71363931e68e..7c3fb39b800b 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -6,86 +6,76 @@ */ import path from 'path'; -import {loadConfig} from '../config'; +import {loadSiteConfig} from '../config'; + +describe('loadSiteConfig', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'configs'); -describe('loadConfig', () => { it('website with valid siteConfig', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'simple-site', - 'docusaurus.config.js', - ); - const config = await loadConfig(siteDir); + const config = await loadSiteConfig({ + siteDir: path.join(__dirname, '__fixtures__', 'simple-site'), + }); expect(config).toMatchSnapshot(); expect(config).not.toEqual({}); }); it('website with valid config creator function', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'configs', - 'createConfig.config.js', - ); - const config = await loadConfig(siteDir); + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'createConfig.config.js', + }); expect(config).toMatchSnapshot(); expect(config).not.toEqual({}); }); it('website with valid async config', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'configs', - 'configAsync.config.js', - ); - const config = await loadConfig(siteDir); + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'configAsync.config.js', + }); expect(config).toMatchSnapshot(); expect(config).not.toEqual({}); }); it('website with valid async config creator function', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'configs', - 'createConfigAsync.config.js', - ); - const config = await loadConfig(siteDir); + const config = await loadSiteConfig({ + siteDir, + customConfigFilePath: 'createConfigAsync.config.js', + }); expect(config).toMatchSnapshot(); expect(config).not.toEqual({}); }); it('website with incomplete siteConfig', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'bad-site', - 'docusaurus.config.js', - ); - await expect(loadConfig(siteDir)).rejects.toThrowErrorMatchingSnapshot(); + await expect( + loadSiteConfig({ + siteDir: path.join(__dirname, '__fixtures__', 'bad-site'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "\\"url\\" is required + " + `); }); it('website with useless field (wrong field) in siteConfig', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'wrong-site', - 'docusaurus.config.js', - ); - await expect(loadConfig(siteDir)).rejects.toThrowErrorMatchingSnapshot(); + await expect( + loadSiteConfig({ + siteDir: path.join(__dirname, '__fixtures__', 'wrong-site'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + "These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js. + If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. + See https://docusaurus.io/docs/api/docusaurus-config/#customfields" + `); }); it('website with no siteConfig', async () => { - const siteDir = path.join( - __dirname, - '__fixtures__', - 'nonExisting', - 'docusaurus.config.js', - ); - await expect(loadConfig(siteDir)).rejects.toThrowError( - /Config file at ".*?__fixtures__[/\\]nonExisting[/\\]docusaurus.config.js" not found.$/, + await expect( + loadSiteConfig({ + siteDir: path.join(__dirname, '__fixtures__', 'nonExisting'), + }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Config file at \\"<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/nonExisting/docusaurus.config.js\\" not found."`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts b/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts deleted file mode 100644 index 055e59cef7aa..000000000000 --- a/packages/docusaurus/src/server/__tests__/duplicateRoutes.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import {jest} from '@jest/globals'; -import {handleDuplicateRoutes} from '../duplicateRoutes'; -import type {RouteConfig} from '@docusaurus/types'; - -const routes: RouteConfig[] = [ - { - path: '/', - component: '', - routes: [ - {path: '/search', component: ''}, - {path: '/sameDoc', component: ''}, - ], - }, - { - path: '/', - component: '', - routes: [ - {path: '/search', component: ''}, - {path: '/sameDoc', component: ''}, - {path: '/uniqueDoc', component: ''}, - ], - }, - { - path: '/', - component: '', - }, - { - path: '/', - component: '', - }, - { - path: '/', - component: '', - }, -]; - -describe('handleDuplicateRoutes', () => { - it('works', () => { - expect(() => { - handleDuplicateRoutes(routes, 'throw'); - }).toThrowErrorMatchingSnapshot(); - const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); - handleDuplicateRoutes(routes, 'ignore'); - expect(consoleMock).toBeCalledTimes(0); - }); -}); diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index 662ab03f9727..acac972d0f19 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -5,9 +5,52 @@ * LICENSE file in the root directory of this source tree. */ -import {loadRoutes} from '../routes'; +import {jest} from '@jest/globals'; +import {loadRoutes, handleDuplicateRoutes} from '../routes'; import type {RouteConfig} from '@docusaurus/types'; +describe('handleDuplicateRoutes', () => { + const routes: RouteConfig[] = [ + { + path: '/', + component: '', + routes: [ + {path: '/search', component: ''}, + {path: '/sameDoc', component: ''}, + ], + }, + { + path: '/', + component: '', + routes: [ + {path: '/search', component: ''}, + {path: '/sameDoc', component: ''}, + {path: '/uniqueDoc', component: ''}, + ], + }, + { + path: '/', + component: '', + }, + { + path: '/', + component: '', + }, + { + path: '/', + component: '', + }, + ]; + it('works', () => { + expect(() => { + handleDuplicateRoutes(routes, 'throw'); + }).toThrowErrorMatchingSnapshot(); + const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); + handleDuplicateRoutes(routes, 'ignore'); + expect(consoleMock).toBeCalledTimes(0); + }); +}); + describe('loadRoutes', () => { it('loads nested route config', async () => { const nestedRouteConfig: RouteConfig = { @@ -44,7 +87,7 @@ describe('loadRoutes', () => { ], }; await expect( - loadRoutes([nestedRouteConfig], '/'), + loadRoutes([nestedRouteConfig], '/', 'ignore'), ).resolves.toMatchSnapshot(); }); @@ -79,7 +122,9 @@ describe('loadRoutes', () => { ], }, }; - await expect(loadRoutes([flatRouteConfig], '/')).resolves.toMatchSnapshot(); + await expect( + loadRoutes([flatRouteConfig], '/', 'ignore'), + ).resolves.toMatchSnapshot(); }); it('rejects invalid route config', async () => { @@ -87,7 +132,7 @@ describe('loadRoutes', () => { component: 'hello/world.js', } as RouteConfig; - await expect(loadRoutes([routeConfigWithoutPath], '/')).rejects + await expect(loadRoutes([routeConfigWithoutPath], '/', 'ignore')).rejects .toThrowErrorMatchingInlineSnapshot(` "Invalid route config: path must be a string and component is required. {\\"component\\":\\"hello/world.js\\"}" @@ -97,8 +142,8 @@ describe('loadRoutes', () => { path: '/hello/world', } as RouteConfig; - await expect(loadRoutes([routeConfigWithoutComponent], '/')).rejects - .toThrowErrorMatchingInlineSnapshot(` + await expect(loadRoutes([routeConfigWithoutComponent], '/', 'ignore')) + .rejects.toThrowErrorMatchingInlineSnapshot(` "Invalid route config: path must be a string and component is required. {\\"path\\":\\"/hello/world\\"}" `); @@ -110,6 +155,8 @@ describe('loadRoutes', () => { component: 'hello/world.js', } as RouteConfig; - await expect(loadRoutes([routeConfig], '/')).resolves.toMatchSnapshot(); + await expect( + loadRoutes([routeConfig], '/', 'ignore'), + ).resolves.toMatchSnapshot(); }); }); diff --git a/packages/docusaurus/src/server/__tests__/testUtils.ts b/packages/docusaurus/src/server/__tests__/testUtils.ts index 06f29dbfc030..1d42d255f9e8 100644 --- a/packages/docusaurus/src/server/__tests__/testUtils.ts +++ b/packages/docusaurus/src/server/__tests__/testUtils.ts @@ -17,9 +17,9 @@ export default async function loadSetup(name: string): Promise<Props> { switch (name) { case 'custom': - return load(customSite); + return load({siteDir: customSite}); case 'simple': default: - return load(simpleSite); + return load({siteDir: simpleSite}); } } diff --git a/packages/docusaurus/src/choosePort.ts b/packages/docusaurus/src/server/choosePort.ts similarity index 88% rename from packages/docusaurus/src/choosePort.ts rename to packages/docusaurus/src/server/choosePort.ts index 8fec0ff0b9c8..11f06ea0c9e2 100644 --- a/packages/docusaurus/src/choosePort.ts +++ b/packages/docusaurus/src/server/choosePort.ts @@ -5,19 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -/** - * This feature was heavily inspired by create-react-app and - * uses many of the same utility functions to implement it. - */ - import {execSync} from 'child_process'; import detect from 'detect-port'; -import isRoot from 'is-root'; import logger from '@docusaurus/logger'; import prompts from 'prompts'; -const isInteractive = process.stdout.isTTY; - const execOptions = { encoding: 'utf8' as const, stdio: [ @@ -72,10 +64,11 @@ function getProcessForPort(port: number): string | null { } /** - * Detects if program is running on port and prompts user - * to choose another if port is already being used + * Detects if program is running on port, and prompts user to choose another if + * port is already being used. This feature was heavily inspired by + * create-react-app and uses many of the same utility functions to implement it. */ -export default async function choosePort( +export async function choosePort( host: string, defaultPort: number, ): Promise<number | null> { @@ -84,8 +77,10 @@ export default async function choosePort( if (port === defaultPort) { return port; } + const isRoot = process.getuid?.() === 0; + const isInteractive = process.stdout.isTTY; const message = - process.platform !== 'win32' && defaultPort < 1024 && !isRoot() + process.platform !== 'win32' && defaultPort < 1024 && !isRoot ? `Admin permissions are required to run a server on a port below 1024.` : `Something is already running on port ${defaultPort}.`; if (!isInteractive) { diff --git a/packages/docusaurus/src/server/clientModules.ts b/packages/docusaurus/src/server/clientModules.ts index 697e4c25288a..5a2057fe611c 100644 --- a/packages/docusaurus/src/server/clientModules.ts +++ b/packages/docusaurus/src/server/clientModules.ts @@ -8,7 +8,11 @@ import path from 'path'; import type {LoadedPlugin} from '@docusaurus/types'; -export function loadClientModules(plugins: LoadedPlugin<unknown>[]): string[] { +/** + * Runs the `getClientModules` lifecycle. The returned file paths are all + * absolute. + */ +export function loadClientModules(plugins: LoadedPlugin[]): string[] { return plugins.flatMap( (plugin) => plugin.getClientModules?.().map((p) => path.resolve(plugin.path, p)) ?? diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 05b3ad2e8bcd..84b4975f1249 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -5,28 +5,36 @@ * LICENSE file in the root directory of this source tree. */ +import path from 'path'; import fs from 'fs-extra'; import importFresh from 'import-fresh'; -import type {DocusaurusConfig} from '@docusaurus/types'; +import {DEFAULT_CONFIG_FILE_NAME} from '@docusaurus/utils'; +import type {LoadContext} from '@docusaurus/types'; import {validateConfig} from './configValidation'; -export async function loadConfig( - configPath: string, -): Promise<DocusaurusConfig> { - if (!(await fs.pathExists(configPath))) { - throw new Error(`Config file at "${configPath}" not found.`); +export async function loadSiteConfig({ + siteDir, + customConfigFilePath, +}: { + siteDir: string; + customConfigFilePath?: string; +}): Promise<Pick<LoadContext, 'siteConfig' | 'siteConfigPath'>> { + const siteConfigPath = path.resolve( + siteDir, + customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME, + ); + + if (!(await fs.pathExists(siteConfigPath))) { + throw new Error(`Config file at "${siteConfigPath}" not found.`); } - const importedConfig = importFresh(configPath) as - | Partial<DocusaurusConfig> - | Promise<Partial<DocusaurusConfig>> - | (() => Partial<DocusaurusConfig>) - | (() => Promise<Partial<DocusaurusConfig>>); + const importedConfig = importFresh(siteConfigPath); const loadedConfig = typeof importedConfig === 'function' ? await importedConfig() : await importedConfig; - return validateConfig(loadedConfig); + const siteConfig = validateConfig(loadedConfig); + return {siteConfig, siteConfigPath}; } diff --git a/packages/docusaurus/src/server/duplicateRoutes.ts b/packages/docusaurus/src/server/duplicateRoutes.ts deleted file mode 100644 index abe0aecfa7c5..000000000000 --- a/packages/docusaurus/src/server/duplicateRoutes.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {ReportingSeverity, RouteConfig} from '@docusaurus/types'; -import {reportMessage} from '@docusaurus/utils'; -import {getAllFinalRoutes} from './utils'; - -function getAllDuplicateRoutes(pluginsRouteConfigs: RouteConfig[]): string[] { - const allRoutes: string[] = getAllFinalRoutes(pluginsRouteConfigs).map( - (routeConfig) => routeConfig.path, - ); - const seenRoutes = new Set<string>(); - return allRoutes.filter((route) => { - if (seenRoutes.has(route)) { - return true; - } - seenRoutes.add(route); - return false; - }); -} - -function getDuplicateRoutesMessage(allDuplicateRoutes: string[]): string { - const message = allDuplicateRoutes - .map( - (duplicateRoute) => - `- Attempting to create page at ${duplicateRoute}, but a page already exists at this route.`, - ) - .join('\n'); - return message; -} - -export function handleDuplicateRoutes( - pluginsRouteConfigs: RouteConfig[], - onDuplicateRoutes: ReportingSeverity, -): void { - if (onDuplicateRoutes === 'ignore') { - return; - } - const duplicatePaths: string[] = getAllDuplicateRoutes(pluginsRouteConfigs); - const message: string = getDuplicateRoutesMessage(duplicatePaths); - if (message) { - const finalMessage = `Duplicate routes found! -${message} -This could lead to non-deterministic routing behavior.`; - reportMessage(finalMessage, onDuplicateRoutes); - } -} diff --git a/packages/docusaurus/src/server/htmlTags.ts b/packages/docusaurus/src/server/htmlTags.ts index 28e04cec80d1..66c497d8f1ce 100644 --- a/packages/docusaurus/src/server/htmlTags.ts +++ b/packages/docusaurus/src/server/htmlTags.ts @@ -10,7 +10,7 @@ import voidHtmlTags from 'html-tags/void'; import escapeHTML from 'escape-html'; import _ from 'lodash'; import type { - InjectedHtmlTags, + Props, HtmlTagObject, HtmlTags, LoadedPlugin, @@ -62,7 +62,13 @@ function createHtmlTagsString(tags: HtmlTags | undefined): string { .join('\n'); } -export function loadHtmlTags(plugins: LoadedPlugin[]): InjectedHtmlTags { +/** + * Runs the `injectHtmlTags` lifecycle, and aggregates all plugins' tags into + * directly render-able HTML markup. + */ +export function loadHtmlTags( + plugins: LoadedPlugin[], +): Pick<Props, 'headTags' | 'preBodyTags' | 'postBodyTags'> { const pluginHtmlTags = plugins.map( (plugin) => plugin.injectHtmlTags?.({content: plugin.content}) ?? {}, ); diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts index 42b363be7de3..e171b21f78aa 100644 --- a/packages/docusaurus/src/server/i18n.ts +++ b/packages/docusaurus/src/server/i18n.ts @@ -8,6 +8,7 @@ import {getLangDir} from 'rtl-detect'; import logger from '@docusaurus/logger'; import type {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types'; +import type {LoadContextOptions} from './index'; function getDefaultLocaleLabel(locale: string) { const languageName = new Intl.DisplayNames(locale, {type: 'language'}).of( @@ -28,7 +29,7 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig { export async function loadI18n( config: DocusaurusConfig, - options: {locale?: string}, + options: Pick<LoadContextOptions, 'locale'>, ): Promise<I18n> { const {i18n: i18nConfig} = config; diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index fc4c3afbeac4..bfdfc4f3c6d8 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -15,14 +15,13 @@ import { } from '@docusaurus/utils'; import _ from 'lodash'; import path from 'path'; +import {loadSiteConfig} from './config'; import ssrDefaultTemplate from '../webpack/templates/ssr.html.template'; import {loadClientModules} from './clientModules'; -import {loadConfig} from './config'; import {loadPlugins} from './plugins'; import {loadRoutes} from './routes'; import {loadHtmlTags} from './htmlTags'; import {loadSiteMetadata} from './siteMetadata'; -import {handleDuplicateRoutes} from './duplicateRoutes'; import {loadI18n} from './i18n'; import { readCodeTranslationFileContent, @@ -31,45 +30,39 @@ import { import type {DocusaurusConfig, LoadContext, Props} from '@docusaurus/types'; export type LoadContextOptions = { + /** Usually the CWD; can be overridden with command argument. */ + siteDir: string; + /** Can be customized with `--out-dir` option */ customOutDir?: string; + /** Can be customized with `--config` option */ customConfigFilePath?: string; + /** Default is `i18n.defaultLocale` */ locale?: string; - localizePath?: boolean; // undefined = only non-default locales paths are localized + /** + * `true` means the paths will have the locale prepended; `false` means they + * won't (useful for `yarn build -l zh-Hans` where the output should be + * emitted into `build/` instead of `build/zh-Hans/`); `undefined` is like the + * "smart" option where only non-default locale paths are localized + */ + localizePath?: boolean; }; -export async function loadSiteConfig({ - siteDir, - customConfigFilePath, -}: { - siteDir: string; - customConfigFilePath?: string; -}): Promise<{siteConfig: DocusaurusConfig; siteConfigPath: string}> { - const siteConfigPath = path.resolve( - siteDir, - customConfigFilePath ?? DEFAULT_CONFIG_FILE_NAME, - ); - - const siteConfig = await loadConfig(siteConfigPath); - return {siteConfig, siteConfigPath}; -} - +/** + * Loading context is the very first step in site building. Its options are + * directly acquired from CLI options. It mainly loads `siteConfig` and the i18n + * context (which includes code translations). The `LoadContext` will be passed + * to plugin constructors. + */ export async function loadContext( - siteDir: string, - options: LoadContextOptions = {}, + options: LoadContextOptions, ): Promise<LoadContext> { - const {customOutDir, locale, customConfigFilePath} = options; + const {siteDir, customOutDir, locale, customConfigFilePath} = options; const generatedFilesDir = path.resolve(siteDir, GENERATED_FILES_DIR_NAME); const {siteConfig: initialSiteConfig, siteConfigPath} = await loadSiteConfig({ siteDir, customConfigFilePath, }); - const {ssrTemplate} = initialSiteConfig; - - const baseOutDir = path.resolve( - siteDir, - customOutDir ?? DEFAULT_BUILD_DIR_NAME, - ); const i18n = await loadI18n(initialSiteConfig, {locale}); @@ -80,7 +73,7 @@ export async function loadContext( pathType: 'url', }); const outDir = localizePath({ - path: baseOutDir, + path: path.resolve(siteDir, customOutDir ?? DEFAULT_BUILD_DIR_NAME), i18n, options, pathType: 'fs', @@ -106,19 +99,22 @@ export async function loadContext( siteConfig, siteConfigPath, outDir, - baseUrl, // TODO to remove: useless, there's already siteConfig.baseUrl! (and yes, it's the same value, cf code above) + baseUrl, i18n, - ssrTemplate: ssrTemplate ?? ssrDefaultTemplate, + ssrTemplate: siteConfig.ssrTemplate ?? ssrDefaultTemplate, codeTranslations, }; } -export async function load( - siteDir: string, - options: LoadContextOptions = {}, -): Promise<Props> { - // Context. - const context: LoadContext = await loadContext(siteDir, options); +/** + * This is the crux of the Docusaurus server-side. It reads everything it needs— + * code translations, config file, plugin modules... Plugins then use their + * lifecycles to generate content and other data. It is side-effect-ful because + * it generates temp files in the `.docusaurus` folder for the bundler. + */ +export async function load(options: LoadContextOptions): Promise<Props> { + const {siteDir} = options; + const context = await loadContext(options); const { generatedFilesDir, siteConfig, @@ -127,16 +123,28 @@ export async function load( baseUrl, i18n, ssrTemplate, - codeTranslations, + codeTranslations: siteCodeTranslations, } = context; - // Plugins. const {plugins, pluginsRouteConfigs, globalData, themeConfigTranslated} = await loadPlugins(context); - // Side-effect to replace the untranslated themeConfig by the translated one context.siteConfig.themeConfig = themeConfigTranslated; + const clientModules = loadClientModules(plugins); + const {headTags, preBodyTags, postBodyTags} = loadHtmlTags(plugins); + const {registry, routesChunkNames, routesConfig, routesPaths} = + await loadRoutes( + pluginsRouteConfigs, + baseUrl, + siteConfig.onDuplicateRoutes, + ); + const codeTranslations: {[msgId: string]: string} = { + ...(await getPluginsDefaultCodeTranslationMessages(plugins)), + ...siteCodeTranslations, + }; + const siteMetadata = await loadSiteMetadata({plugins, siteDir}); + + // === Side-effects part === - handleDuplicateRoutes(pluginsRouteConfigs, siteConfig.onDuplicateRoutes); const genWarning = generate( generatedFilesDir, 'DONT-EDIT-THIS-FOLDER', @@ -162,8 +170,6 @@ export default ${JSON.stringify(siteConfig, null, 2)}; `, ); - // Load client modules. - const clientModules = loadClientModules(plugins); const genClientModules = generate( generatedFilesDir, 'client-modules.js', @@ -177,13 +183,6 @@ ${clientModules `, ); - // Load extra head & body html tags. - const {headTags, preBodyTags, postBodyTags} = loadHtmlTags(plugins); - - // Routing. - const {registry, routesChunkNames, routesConfig, routesPaths} = - await loadRoutes(pluginsRouteConfigs, baseUrl); - const genRegistry = generate( generatedFilesDir, 'registry.js', @@ -220,19 +219,12 @@ ${Object.entries(registry) JSON.stringify(i18n, null, 2), ); - const codeTranslationsWithFallbacks: {[msgId: string]: string} = { - ...(await getPluginsDefaultCodeTranslationMessages(plugins)), - ...codeTranslations, - }; - const genCodeTranslations = generate( generatedFilesDir, 'codeTranslations.json', - JSON.stringify(codeTranslationsWithFallbacks, null, 2), + JSON.stringify(codeTranslations, null, 2), ); - // Version metadata. - const siteMetadata = await loadSiteMetadata({plugins, siteDir}); const genSiteMetadata = generate( generatedFilesDir, 'site-metadata.json', @@ -252,7 +244,7 @@ ${Object.entries(registry) genCodeTranslations, ]); - const props: Props = { + return { siteConfig, siteConfigPath, siteMetadata, @@ -270,6 +262,4 @@ ${Object.entries(registry) ssrTemplate, codeTranslations, }; - - return props; } diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index 3155775b5266..3ecf57b0d860 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -11,9 +11,9 @@ import {loadContext, type LoadContextOptions} from '../../index'; import {initPlugins} from '../init'; describe('initPlugins', () => { - async function loadSite(options: LoadContextOptions = {}) { + async function loadSite(options: Omit<LoadContextOptions, 'siteDir'> = {}) { const siteDir = path.join(__dirname, '__fixtures__', 'site-with-plugin'); - const context = await loadContext(siteDir, options); + const context = await loadContext({...options, siteDir}); const plugins = await initPlugins(context); return {siteDir, context, plugins}; diff --git a/packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts b/packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts similarity index 100% rename from packages/docusaurus/src/server/__tests__/moduleShorthand.test.ts rename to packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts diff --git a/packages/docusaurus/src/server/plugins/configs.ts b/packages/docusaurus/src/server/plugins/configs.ts index 94ca87424d3c..2662ddc69b99 100644 --- a/packages/docusaurus/src/server/plugins/configs.ts +++ b/packages/docusaurus/src/server/plugins/configs.ts @@ -6,28 +6,97 @@ */ import {createRequire} from 'module'; +import importFresh from 'import-fresh'; import {loadPresets} from './presets'; -import {resolveModuleName} from '../moduleShorthand'; -import type {LoadContext, PluginConfig} from '@docusaurus/types'; +import {resolveModuleName} from './moduleShorthand'; +import type { + LoadContext, + PluginConfig, + ImportedPluginModule, + NormalizedPluginConfig, +} from '@docusaurus/types'; +async function normalizePluginConfig( + pluginConfig: PluginConfig, + configPath: string, + pluginRequire: NodeRequire, +): Promise<NormalizedPluginConfig> { + // plugins: ["./plugin"] + if (typeof pluginConfig === 'string') { + const pluginModuleImport = pluginConfig; + const pluginPath = pluginRequire.resolve(pluginModuleImport); + const pluginModule = importFresh<ImportedPluginModule>(pluginPath); + return { + plugin: pluginModule?.default ?? pluginModule, + options: {}, + pluginModule: { + path: pluginModuleImport, + module: pluginModule, + }, + entryPath: pluginPath, + }; + } + + // plugins: [() => {...}] + if (typeof pluginConfig === 'function') { + return { + plugin: pluginConfig, + options: {}, + entryPath: configPath, + }; + } + + // plugins: [ + // ["./plugin",options], + // ] + if (typeof pluginConfig[0] === 'string') { + const pluginModuleImport = pluginConfig[0]; + const pluginPath = pluginRequire.resolve(pluginModuleImport); + const pluginModule = importFresh<ImportedPluginModule>(pluginPath); + return { + plugin: pluginModule?.default ?? pluginModule, + options: pluginConfig[1], + pluginModule: { + path: pluginModuleImport, + module: pluginModule, + }, + entryPath: pluginPath, + }; + } + // plugins: [ + // [() => {...}, options], + // ] + return { + plugin: pluginConfig[0], + options: pluginConfig[1], + entryPath: configPath, + }; +} + +/** + * Reads the site config's `presets`, `themes`, and `plugins`, imports them, and + * normalizes the return value. Plugin configs are ordered, mostly for theme + * alias shadowing. Site themes have the highest priority, and preset plugins + * are the lowest. + */ export async function loadPluginConfigs( context: LoadContext, -): Promise<PluginConfig[]> { +): Promise<NormalizedPluginConfig[]> { const preset = await loadPresets(context); const {siteConfig, siteConfigPath} = context; - const require = createRequire(siteConfigPath); + const pluginRequire = createRequire(siteConfigPath); function normalizeShorthand( pluginConfig: PluginConfig, pluginType: 'plugin' | 'theme', ): PluginConfig { if (typeof pluginConfig === 'string') { - return resolveModuleName(pluginConfig, require, pluginType); + return resolveModuleName(pluginConfig, pluginRequire, pluginType); } else if ( Array.isArray(pluginConfig) && typeof pluginConfig[0] === 'string' ) { return [ - resolveModuleName(pluginConfig[0], require, pluginType), + resolveModuleName(pluginConfig[0], pluginRequire, pluginType), pluginConfig[1] ?? {}, ]; } @@ -45,11 +114,20 @@ export async function loadPluginConfigs( const standaloneThemes = siteConfig.themes.map((theme) => normalizeShorthand(theme, 'theme'), ); - return [ + const pluginConfigs = [ ...preset.plugins, ...preset.themes, // Site config should be the highest priority. ...standalonePlugins, ...standaloneThemes, ]; + return Promise.all( + pluginConfigs.map((pluginConfig) => + normalizePluginConfig( + pluginConfig, + context.siteConfigPath, + pluginRequire, + ), + ), + ); } diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 08002e8db72c..7484ae966669 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -14,7 +14,6 @@ import type { RouteConfig, AllContent, GlobalData, - TranslationFiles, ThemeConfig, LoadedPlugin, InitializedPlugin, @@ -27,6 +26,10 @@ import _ from 'lodash'; import {localizePluginTranslationFile} from '../translations/translations'; import {applyRouteTrailingSlash, sortConfig} from './routeConfig'; +/** + * Initializes the plugins, runs `loadContent`, `translateContent`, + * `contentLoaded`, and `translateThemeConfig`. + */ export async function loadPlugins(context: LoadContext): Promise<{ plugins: LoadedPlugin[]; pluginsRouteConfigs: RouteConfig[]; @@ -52,32 +55,28 @@ export async function loadPlugins(context: LoadContext): Promise<{ }), ); - type ContentLoadedTranslatedPlugin = LoadedPlugin & { - translationFiles: TranslationFiles; - }; - const contentLoadedTranslatedPlugins: ContentLoadedTranslatedPlugin[] = - await Promise.all( - loadedPlugins.map(async (contentLoadedPlugin) => { - const translationFiles = - (await contentLoadedPlugin?.getTranslationFiles?.({ - content: contentLoadedPlugin.content, - })) ?? []; - const localizedTranslationFiles = await Promise.all( - translationFiles.map((translationFile) => - localizePluginTranslationFile({ - locale: context.i18n.currentLocale, - siteDir: context.siteDir, - translationFile, - plugin: contentLoadedPlugin, - }), - ), - ); - return { - ...contentLoadedPlugin, - translationFiles: localizedTranslationFiles, - }; - }), - ); + const contentLoadedTranslatedPlugins = await Promise.all( + loadedPlugins.map(async (plugin) => { + const translationFiles = + (await plugin?.getTranslationFiles?.({ + content: plugin.content, + })) ?? []; + const localizedTranslationFiles = await Promise.all( + translationFiles.map((translationFile) => + localizePluginTranslationFile({ + locale: context.i18n.currentLocale, + siteDir: context.siteDir, + translationFile, + plugin, + }), + ), + ); + return { + ...plugin, + translationFiles: localizedTranslationFiles, + }; + }), + ); const allContent: AllContent = _.chain(loadedPlugins) .groupBy((item) => item.name) @@ -174,9 +173,6 @@ export async function loadPlugins(context: LoadContext): Promise<{ ); // 4. Plugin Lifecycle - routesLoaded. - // Currently plugins run lifecycle methods in parallel and are not - // order-dependent. We could change this in future if there are plugins which - // need to run in certain order or depend on others for data. await Promise.all( contentLoadedTranslatedPlugins.map(async (plugin) => { if (!plugin.routesLoaded) { @@ -197,28 +193,24 @@ export async function loadPlugins(context: LoadContext): Promise<{ sortConfig(pluginsRouteConfigs, context.siteConfig.baseUrl); // Apply each plugin one after the other to translate the theme config - function translateThemeConfig( - untranslatedThemeConfig: ThemeConfig, - ): ThemeConfig { - return contentLoadedTranslatedPlugins.reduce( - (currentThemeConfig, plugin) => { - const translatedThemeConfigSlice = plugin.translateThemeConfig?.({ - themeConfig: currentThemeConfig, - translationFiles: plugin.translationFiles, - }); - return { - ...currentThemeConfig, - ...translatedThemeConfigSlice, - }; - }, - untranslatedThemeConfig, - ); - } + const themeConfigTranslated = contentLoadedTranslatedPlugins.reduce( + (currentThemeConfig, plugin) => { + const translatedThemeConfigSlice = plugin.translateThemeConfig?.({ + themeConfig: currentThemeConfig, + translationFiles: plugin.translationFiles, + }); + return { + ...currentThemeConfig, + ...translatedThemeConfigSlice, + }; + }, + context.siteConfig.themeConfig, + ); return { plugins: loadedPlugins, pluginsRouteConfigs, globalData, - themeConfigTranslated: translateThemeConfig(context.siteConfig.themeConfig), + themeConfigTranslated, }; } diff --git a/packages/docusaurus/src/server/plugins/init.ts b/packages/docusaurus/src/server/plugins/init.ts index 326d041e8da2..14c01f2ace20 100644 --- a/packages/docusaurus/src/server/plugins/init.ts +++ b/packages/docusaurus/src/server/plugins/init.ts @@ -7,15 +7,13 @@ import {createRequire} from 'module'; import path from 'path'; -import importFresh from 'import-fresh'; import type { PluginVersionInformation, - ImportedPluginModule, LoadContext, PluginModule, - PluginConfig, PluginOptions, InitializedPlugin, + NormalizedPluginConfig, } from '@docusaurus/types'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import {getPluginVersion} from '../siteMetadata'; @@ -26,89 +24,6 @@ import { } from '@docusaurus/utils-validation'; import {loadPluginConfigs} from './configs'; -export type NormalizedPluginConfig = { - plugin: PluginModule; - options: PluginOptions; - // Only available when a string is provided in config - pluginModule?: { - path: string; - module: ImportedPluginModule; - }; - /** - * Different from pluginModule.path, this one is always an absolute path used - * to resolve relative paths returned from lifecycles - */ - entryPath: string; -}; - -async function normalizePluginConfig( - pluginConfig: PluginConfig, - configPath: string, -): Promise<NormalizedPluginConfig> { - const pluginRequire = createRequire(configPath); - // plugins: ['./plugin'] - if (typeof pluginConfig === 'string') { - const pluginModuleImport = pluginConfig; - const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = importFresh<ImportedPluginModule>(pluginPath); - return { - plugin: pluginModule?.default ?? pluginModule, - options: {}, - pluginModule: { - path: pluginModuleImport, - module: pluginModule, - }, - entryPath: pluginPath, - }; - } - - // plugins: [function plugin() { }] - if (typeof pluginConfig === 'function') { - return { - plugin: pluginConfig, - options: {}, - entryPath: configPath, - }; - } - - // plugins: [ - // ['./plugin',options], - // ] - if (typeof pluginConfig[0] === 'string') { - const pluginModuleImport = pluginConfig[0]; - const pluginPath = pluginRequire.resolve(pluginModuleImport); - const pluginModule = importFresh<ImportedPluginModule>(pluginPath); - return { - plugin: pluginModule?.default ?? pluginModule, - options: pluginConfig[1], - pluginModule: { - path: pluginModuleImport, - module: pluginModule, - }, - entryPath: pluginPath, - }; - } - // plugins: [ - // [function plugin() { },options], - // ] - return { - plugin: pluginConfig[0], - options: pluginConfig[1], - entryPath: configPath, - }; -} - -export async function normalizePluginConfigs( - pluginConfigs: PluginConfig[], - configPath: string, -): Promise<NormalizedPluginConfig[]> { - return Promise.all( - pluginConfigs.map((pluginConfig) => - normalizePluginConfig(pluginConfig, configPath), - ), - ); -} - function getOptionValidationFunction( normalizedPluginConfig: NormalizedPluginConfig, ): PluginModule['validateOptions'] { @@ -135,17 +50,17 @@ function getThemeValidationFunction( return normalizedPluginConfig.plugin.validateThemeConfig; } +/** + * Runs the plugin constructors and returns their return values. It would load + * plugin configs from `plugins`, `themes`, and `presets`. + */ export async function initPlugins( context: LoadContext, ): Promise<InitializedPlugin[]> { - // We need to resolve plugins from the perspective of the siteDir, since the - // siteDir's package.json declares the dependency on these plugins. + // We need to resolve plugins from the perspective of the site config, as if + // we are using `require.resolve` on those module names. const pluginRequire = createRequire(context.siteConfigPath); const pluginConfigs = await loadPluginConfigs(context); - const pluginConfigsNormalized = await normalizePluginConfigs( - pluginConfigs, - context.siteConfigPath, - ); async function doGetPluginVersion( normalizedPluginConfig: NormalizedPluginConfig, @@ -221,7 +136,7 @@ export async function initPlugins( } const plugins: InitializedPlugin[] = await Promise.all( - pluginConfigsNormalized.map(initializePlugin), + pluginConfigs.map(initializePlugin), ); ensureUniquePluginInstanceIds(plugins); diff --git a/packages/docusaurus/src/server/moduleShorthand.ts b/packages/docusaurus/src/server/plugins/moduleShorthand.ts similarity index 100% rename from packages/docusaurus/src/server/moduleShorthand.ts rename to packages/docusaurus/src/server/plugins/moduleShorthand.ts diff --git a/packages/docusaurus/src/server/plugins/pluginIds.ts b/packages/docusaurus/src/server/plugins/pluginIds.ts index bd0635e19c80..86e3eb5d9f97 100644 --- a/packages/docusaurus/src/server/plugins/pluginIds.ts +++ b/packages/docusaurus/src/server/plugins/pluginIds.ts @@ -9,8 +9,10 @@ import _ from 'lodash'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import type {InitializedPlugin} from '@docusaurus/types'; -// It is forbidden to have 2 plugins of the same name sharing the same id -// this is required to support multi-instance plugins without conflict +/** + * It is forbidden to have 2 plugins of the same name sharing the same ID. + * This is required to support multi-instance plugins without conflict. + */ export function ensureUniquePluginInstanceIds( plugins: InitializedPlugin[], ): void { diff --git a/packages/docusaurus/src/server/plugins/presets.ts b/packages/docusaurus/src/server/plugins/presets.ts index d920ea2e59bd..877150cc6703 100644 --- a/packages/docusaurus/src/server/plugins/presets.ts +++ b/packages/docusaurus/src/server/plugins/presets.ts @@ -11,15 +11,19 @@ import type { LoadContext, PluginConfig, ImportedPresetModule, + DocusaurusConfig, } from '@docusaurus/types'; -import {resolveModuleName} from '../moduleShorthand'; +import {resolveModuleName} from './moduleShorthand'; -export async function loadPresets(context: LoadContext): Promise<{ - plugins: PluginConfig[]; - themes: PluginConfig[]; -}> { - // We need to resolve presets from the perspective of the siteDir, since the - // siteDir's package.json declares the dependency on these presets. +/** + * Calls preset functions, aggregates each of their return values, and returns + * the plugin and theme configs. + */ +export async function loadPresets( + context: LoadContext, +): Promise<Pick<DocusaurusConfig, 'plugins' | 'themes'>> { + // We need to resolve plugins from the perspective of the site config, as if + // we are using `require.resolve` on those module names. const presetRequire = createRequire(context.siteConfigPath); const {presets} = context.siteConfig; diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index 3bf9f8b37a08..39affe45a31d 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -11,14 +11,17 @@ import { removeSuffix, simpleHash, escapePath, + reportMessage, } from '@docusaurus/utils'; import {stringify} from 'querystring'; +import {getAllFinalRoutes} from './utils'; import type { ChunkRegistry, Module, RouteConfig, RouteModule, ChunkNames, + ReportingSeverity, } from '@docusaurus/types'; type RegistryMap = { @@ -119,15 +122,107 @@ function getModulePath(target: Module): string { return `${target.path}${queryStr}`; } +function genRouteChunkNames( + registry: RegistryMap, + value: Module, + prefix?: string, + name?: string, +): string; +function genRouteChunkNames( + registry: RegistryMap, + value: RouteModule, + prefix?: string, + name?: string, +): ChunkNames; +function genRouteChunkNames( + registry: RegistryMap, + value: RouteModule[], + prefix?: string, + name?: string, +): ChunkNames[]; +function genRouteChunkNames( + registry: RegistryMap, + value: RouteModule | RouteModule[] | Module, + prefix?: string, + name?: string, +): ChunkNames | ChunkNames[] | string; +function genRouteChunkNames( + // TODO instead of passing a mutating the registry, return a registry slice? + registry: RegistryMap, + value: RouteModule | RouteModule[] | Module | null | undefined, + prefix?: string, + name?: string, +): null | string | ChunkNames | ChunkNames[] { + if (!value) { + return null; + } + + if (Array.isArray(value)) { + return value.map((val, index) => + genRouteChunkNames(registry, val, `${index}`, name), + ); + } + + if (isModule(value)) { + const modulePath = getModulePath(value); + const chunkName = genChunkName(modulePath, prefix, name); + const loader = `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath( + modulePath, + )}')`; + + registry[chunkName] = {loader, modulePath}; + return chunkName; + } + + const newValue: ChunkNames = {}; + Object.entries(value).forEach(([key, v]) => { + newValue[key] = genRouteChunkNames(registry, v, key, name); + }); + return newValue; +} + +export function handleDuplicateRoutes( + pluginsRouteConfigs: RouteConfig[], + onDuplicateRoutes: ReportingSeverity, +): void { + if (onDuplicateRoutes === 'ignore') { + return; + } + const allRoutes: string[] = getAllFinalRoutes(pluginsRouteConfigs).map( + (routeConfig) => routeConfig.path, + ); + const seenRoutes = new Set<string>(); + const duplicatePaths = allRoutes.filter((route) => { + if (seenRoutes.has(route)) { + return true; + } + seenRoutes.add(route); + return false; + }); + if (duplicatePaths.length > 0) { + const finalMessage = `Duplicate routes found! +${duplicatePaths + .map( + (duplicateRoute) => + `- Attempting to create page at ${duplicateRoute}, but a page already exists at this route.`, + ) + .join('\n')} +This could lead to non-deterministic routing behavior.`; + reportMessage(finalMessage, onDuplicateRoutes); + } +} + export async function loadRoutes( pluginsRouteConfigs: RouteConfig[], baseUrl: string, + onDuplicateRoutes: ReportingSeverity, ): Promise<{ registry: {[chunkName: string]: ChunkRegistry}; routesConfig: string; routesChunkNames: {[routePath: string]: ChunkNames}; routesPaths: string[]; }> { + handleDuplicateRoutes(pluginsRouteConfigs, onDuplicateRoutes); const registry: {[chunkName: string]: ChunkRegistry} = {}; const routesPaths: string[] = [normalizeUrl([baseUrl, '404.html'])]; const routesChunkNames: {[routePath: string]: ChunkNames} = {}; @@ -194,63 +289,3 @@ ${indent(NotFoundRouteCode)} routesPaths, }; } - -function genRouteChunkNames( - registry: RegistryMap, - value: Module, - prefix?: string, - name?: string, -): string; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule, - prefix?: string, - name?: string, -): ChunkNames; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule[], - prefix?: string, - name?: string, -): ChunkNames[]; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule | RouteModule[] | Module, - prefix?: string, - name?: string, -): ChunkNames | ChunkNames[] | string; - -function genRouteChunkNames( - // TODO instead of passing a mutating the registry, return a registry slice? - registry: RegistryMap, - value: RouteModule | RouteModule[] | Module | null | undefined, - prefix?: string, - name?: string, -): null | string | ChunkNames | ChunkNames[] { - if (!value) { - return null; - } - - if (Array.isArray(value)) { - return value.map((val, index) => - genRouteChunkNames(registry, val, `${index}`, name), - ); - } - - if (isModule(value)) { - const modulePath = getModulePath(value); - const chunkName = genChunkName(modulePath, prefix, name); - const loader = `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath( - modulePath, - )}')`; - - registry[chunkName] = {loader, modulePath}; - return chunkName; - } - - const newValue: ChunkNames = {}; - Object.entries(value).forEach(([key, v]) => { - newValue[key] = genRouteChunkNames(registry, v, key, name); - }); - return newValue; -} diff --git a/packages/docusaurus/src/server/siteMetadata.ts b/packages/docusaurus/src/server/siteMetadata.ts index 996244a94102..199dbc034a6b 100644 --- a/packages/docusaurus/src/server/siteMetadata.ts +++ b/packages/docusaurus/src/server/siteMetadata.ts @@ -8,7 +8,7 @@ import type { LoadedPlugin, PluginVersionInformation, - DocusaurusSiteMetadata, + SiteMetadata, } from '@docusaurus/types'; import fs from 'fs-extra'; import path from 'path'; @@ -61,7 +61,8 @@ export async function getPluginVersion( ); } // In the case where a plugin is a path where no parent directory contains - // package.json (e.g. inline plugin), we can only classify it as local. + // package.json, we can only classify it as local. Could happen if one puts a + // script in the parent directory of the site. return {type: 'local'}; } @@ -70,7 +71,7 @@ export async function getPluginVersion( * @see https://github.com/facebook/docusaurus/issues/3371 * @see https://github.com/facebook/docusaurus/pull/3386 */ -function checkDocusaurusPackagesVersion(siteMetadata: DocusaurusSiteMetadata) { +function checkDocusaurusPackagesVersion(siteMetadata: SiteMetadata) { const {docusaurusVersion} = siteMetadata; Object.entries(siteMetadata.pluginVersions).forEach( ([plugin, versionInfo]) => { @@ -96,8 +97,8 @@ export async function loadSiteMetadata({ }: { plugins: LoadedPlugin[]; siteDir: string; -}): Promise<DocusaurusSiteMetadata> { - const siteMetadata: DocusaurusSiteMetadata = { +}): Promise<SiteMetadata> { + const siteMetadata: SiteMetadata = { docusaurusVersion: (await getPackageJsonVersion( path.join(__dirname, '../../package.json'), ))!, diff --git a/packages/docusaurus/src/server/themes/__tests__/index.test.ts b/packages/docusaurus/src/server/themes/__tests__/index.test.ts deleted file mode 100644 index aa70330d661f..000000000000 --- a/packages/docusaurus/src/server/themes/__tests__/index.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import path from 'path'; -import {loadThemeAliases} from '../index'; - -describe('loadThemeAliases', () => { - it('next alias can override the previous alias', async () => { - const fixtures = path.join(__dirname, '__fixtures__'); - const theme1Path = path.join(fixtures, 'theme-1'); - const theme2Path = path.join(fixtures, 'theme-2'); - - const alias = await loadThemeAliases([theme1Path, theme2Path], []); - - // Testing entries, because order matters! - expect(Object.entries(alias)).toEqual( - Object.entries({ - '@theme-init/Layout': path.join(theme1Path, 'Layout.js'), - - '@theme-original/Footer': path.join(theme1Path, 'Footer/index.js'), - '@theme-original/Layout': path.join(theme2Path, 'Layout/index.js'), - '@theme-original/Navbar': path.join(theme2Path, 'Navbar.js'), - '@theme-original/NavbarItem/NestedNavbarItem': path.join( - theme2Path, - 'NavbarItem/NestedNavbarItem/index.js', - ), - '@theme-original/NavbarItem/SiblingNavbarItem': path.join( - theme2Path, - 'NavbarItem/SiblingNavbarItem.js', - ), - '@theme-original/NavbarItem/zzz': path.join( - theme2Path, - 'NavbarItem/zzz.js', - ), - '@theme-original/NavbarItem': path.join( - theme2Path, - 'NavbarItem/index.js', - ), - - '@theme/Footer': path.join(theme1Path, 'Footer/index.js'), - '@theme/Layout': path.join(theme2Path, 'Layout/index.js'), - '@theme/Navbar': path.join(theme2Path, 'Navbar.js'), - '@theme/NavbarItem/NestedNavbarItem': path.join( - theme2Path, - 'NavbarItem/NestedNavbarItem/index.js', - ), - '@theme/NavbarItem/SiblingNavbarItem': path.join( - theme2Path, - 'NavbarItem/SiblingNavbarItem.js', - ), - '@theme/NavbarItem/zzz': path.join(theme2Path, 'NavbarItem/zzz.js'), - '@theme/NavbarItem': path.join(theme2Path, 'NavbarItem/index.js'), - }), - ); - expect(alias).not.toEqual({}); - }); -}); diff --git a/packages/docusaurus/src/server/themes/alias.ts b/packages/docusaurus/src/server/themes/alias.ts deleted file mode 100644 index c5ee69aa0545..000000000000 --- a/packages/docusaurus/src/server/themes/alias.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import fs from 'fs-extra'; -import path from 'path'; -import {fileToPath, posixPath, normalizeUrl, Globby} from '@docusaurus/utils'; -import type {ThemeAliases} from '@docusaurus/types'; -import _ from 'lodash'; - -// Order of Webpack aliases is important because one alias can shadow another -// This ensure @theme/NavbarItem alias is after @theme/NavbarItem/LocaleDropdown -// See https://github.com/facebook/docusaurus/pull/3922 -// See https://github.com/facebook/docusaurus/issues/5382 -export function sortAliases(aliases: ThemeAliases): ThemeAliases { - // Alphabetical order by default - const entries = _.sortBy(Object.entries(aliases), ([alias]) => alias); - // @theme/NavbarItem should be after @theme/NavbarItem/LocaleDropdown - entries.sort(([alias1], [alias2]) => - // eslint-disable-next-line no-nested-ternary - alias1.includes(`${alias2}/`) ? -1 : alias2.includes(`${alias1}/`) ? 1 : 0, - ); - return Object.fromEntries(entries); -} - -export async function themeAlias( - themePath: string, - addOriginalAlias: boolean, -): Promise<ThemeAliases> { - if (!(await fs.pathExists(themePath))) { - return {}; - } - - const themeComponentFiles = await Globby(['**/*.{js,jsx,ts,tsx}'], { - cwd: themePath, - }); - - const aliases: ThemeAliases = {}; - - themeComponentFiles.forEach((relativeSource) => { - const filePath = path.join(themePath, relativeSource); - const fileName = fileToPath(relativeSource); - - const aliasName = posixPath( - normalizeUrl(['@theme', fileName]).replace(/\/$/, ''), - ); - aliases[aliasName] = filePath; - - if (addOriginalAlias) { - // For swizzled components to access the original. - const originalAliasName = posixPath( - normalizeUrl(['@theme-original', fileName]).replace(/\/$/, ''), - ); - aliases[originalAliasName] = filePath; - } - }); - - return sortAliases(aliases); -} diff --git a/packages/docusaurus/src/server/themes/index.ts b/packages/docusaurus/src/server/themes/index.ts deleted file mode 100644 index dbb8ca34e196..000000000000 --- a/packages/docusaurus/src/server/themes/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import path from 'path'; -import {THEME_PATH} from '@docusaurus/utils'; -import {themeAlias, sortAliases} from './alias'; -import type {ThemeAliases, LoadedPlugin} from '@docusaurus/types'; - -const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback'); - -export async function loadThemeAliases( - themePaths: string[], - userThemePaths: string[], -): Promise<ThemeAliases> { - const aliases: ThemeAliases = {}; - - for (const themePath of themePaths) { - const themeAliases = await themeAlias(themePath, true); - Object.entries(themeAliases).forEach(([aliasKey, alias]) => { - // If this alias shadows a previous one, use @theme-init to preserve the - // initial one. @theme-init is only applied once: to the initial theme - // that provided this component - if (aliasKey in aliases) { - const componentName = aliasKey.substring(aliasKey.indexOf('/') + 1); - const initAlias = `@theme-init/${componentName}`; - if (!(initAlias in aliases)) { - aliases[initAlias] = aliases[aliasKey]!; - } - } - aliases[aliasKey] = alias; - }); - } - - for (const themePath of userThemePaths) { - const userThemeAliases = await themeAlias(themePath, false); - Object.assign(aliases, userThemeAliases); - } - - return sortAliases(aliases); -} - -export function loadPluginsThemeAliases({ - siteDir, - plugins, -}: { - siteDir: string; - plugins: LoadedPlugin[]; -}): Promise<ThemeAliases> { - const pluginThemes: string[] = plugins - .map( - (plugin) => - plugin.getThemePath && path.resolve(plugin.path, plugin.getThemePath()), - ) - .filter((x): x is string => Boolean(x)); - const userTheme = path.resolve(siteDir, THEME_PATH); - return loadThemeAliases([ThemeFallbackDir, ...pluginThemes], [userTheme]); -} diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index a989378a0ccb..ae89e0308e20 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -144,13 +144,10 @@ Maybe you should remove them? ${unknownKeys}`; } // should we make this configurable? -function getTranslationsDirPath(context: TranslationContext): string { - return path.join(context.siteDir, I18N_DIR_NAME); -} export function getTranslationsLocaleDirPath( context: TranslationContext, ): string { - return path.join(getTranslationsDirPath(context), context.locale); + return path.join(context.siteDir, I18N_DIR_NAME, context.locale); } function getCodeTranslationsFilePath(context: TranslationContext): string { diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index cfad026638f5..6fdffc625968 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -47,26 +47,3 @@ exports[`base webpack config creates webpack aliases 1`] = ` "@theme/subfolder/UserThemeComponent2": "src/theme/subfolder/UserThemeComponent2.js", } `; - -exports[`getDocusaurusAliases() returns appropriate webpack aliases 1`] = ` -{ - "@docusaurus/BrowserOnly": "../../client/exports/BrowserOnly.tsx", - "@docusaurus/ComponentCreator": "../../client/exports/ComponentCreator.tsx", - "@docusaurus/ErrorBoundary": "../../client/exports/ErrorBoundary.tsx", - "@docusaurus/ExecutionEnvironment": "../../client/exports/ExecutionEnvironment.ts", - "@docusaurus/Head": "../../client/exports/Head.tsx", - "@docusaurus/Interpolate": "../../client/exports/Interpolate.tsx", - "@docusaurus/Link": "../../client/exports/Link.tsx", - "@docusaurus/Noop": "../../client/exports/Noop.ts", - "@docusaurus/Translate": "../../client/exports/Translate.tsx", - "@docusaurus/constants": "../../client/exports/constants.ts", - "@docusaurus/isInternalUrl": "../../client/exports/isInternalUrl.ts", - "@docusaurus/renderRoutes": "../../client/exports/renderRoutes.ts", - "@docusaurus/router": "../../client/exports/router.ts", - "@docusaurus/useBaseUrl": "../../client/exports/useBaseUrl.ts", - "@docusaurus/useDocusaurusContext": "../../client/exports/useDocusaurusContext.ts", - "@docusaurus/useGlobalData": "../../client/exports/useGlobalData.ts", - "@docusaurus/useIsBrowser": "../../client/exports/useIsBrowser.ts", - "@docusaurus/useRouteContext": "../../client/exports/useRouteContext.tsx", -} -`; diff --git a/packages/docusaurus/src/webpack/__tests__/base.test.ts b/packages/docusaurus/src/webpack/__tests__/base.test.ts index 55482b3c2ce3..d3aff2ab5456 100644 --- a/packages/docusaurus/src/webpack/__tests__/base.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/base.test.ts @@ -8,12 +8,7 @@ import {jest} from '@jest/globals'; import path from 'path'; -import { - excludeJS, - clientDir, - getDocusaurusAliases, - createBaseConfig, -} from '../base'; +import {excludeJS, clientDir, createBaseConfig} from '../base'; import * as utils from '@docusaurus/utils/lib/webpackUtils'; import {posixPath} from '@docusaurus/utils'; import _ from 'lodash'; @@ -68,17 +63,6 @@ describe('babel transpilation exclude logic', () => { }); }); -describe('getDocusaurusAliases()', () => { - it('returns appropriate webpack aliases', async () => { - // using relative paths makes tests work everywhere - const relativeDocusaurusAliases = _.mapValues( - await getDocusaurusAliases(), - (aliasValue) => posixPath(path.relative(__dirname, aliasValue)), - ); - expect(relativeDocusaurusAliases).toMatchSnapshot(); - }); -}); - describe('base webpack config', () => { const props: Props = { outDir: '', diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-1/Footer/index.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Footer/index.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-1/Footer/index.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Footer/index.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-1/Layout.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Layout.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-1/Layout.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Layout.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/Layout/index.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Layout/index.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/Layout/index.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Layout/index.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/Navbar.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Navbar.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/Navbar.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Navbar.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/index.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/index.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/index.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/index.js diff --git a/packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js b/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js similarity index 100% rename from packages/docusaurus/src/server/themes/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js rename to packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js diff --git a/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..38a22a306e14 --- /dev/null +++ b/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,129 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getDocusaurusAliases returns appropriate webpack aliases 1`] = ` +{ + "@docusaurus/BrowserOnly": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/BrowserOnly.tsx", + "@docusaurus/ComponentCreator": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/ComponentCreator.tsx", + "@docusaurus/ErrorBoundary": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/ErrorBoundary.tsx", + "@docusaurus/ExecutionEnvironment": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/ExecutionEnvironment.ts", + "@docusaurus/Head": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Head.tsx", + "@docusaurus/Interpolate": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Interpolate.tsx", + "@docusaurus/Link": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Link.tsx", + "@docusaurus/Noop": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Noop.ts", + "@docusaurus/Translate": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Translate.tsx", + "@docusaurus/constants": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/constants.ts", + "@docusaurus/isInternalUrl": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/isInternalUrl.ts", + "@docusaurus/renderRoutes": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/renderRoutes.ts", + "@docusaurus/router": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/router.ts", + "@docusaurus/useBaseUrl": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/useBaseUrl.ts", + "@docusaurus/useDocusaurusContext": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/useDocusaurusContext.ts", + "@docusaurus/useGlobalData": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/useGlobalData.ts", + "@docusaurus/useIsBrowser": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/useIsBrowser.ts", + "@docusaurus/useRouteContext": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/useRouteContext.tsx", +} +`; + +exports[`loadThemeAliases next alias can override the previous alias 1`] = ` +[ + [ + "@theme-init/Layout", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Layout/index.tsx", + ], + [ + "@theme-original/Error", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Error/index.tsx", + ], + [ + "@theme-original/Footer", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Footer/index.js", + ], + [ + "@theme-original/Layout", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Layout/index.js", + ], + [ + "@theme-original/Loading", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Loading/index.tsx", + ], + [ + "@theme-original/Navbar", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Navbar.js", + ], + [ + "@theme-original/NavbarItem/NestedNavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js", + ], + [ + "@theme-original/NavbarItem/SiblingNavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js", + ], + [ + "@theme-original/NavbarItem/zzz", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js", + ], + [ + "@theme-original/NavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/index.js", + ], + [ + "@theme-original/NotFound", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx", + ], + [ + "@theme-original/Root", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Root/index.tsx", + ], + [ + "@theme-original/SiteMetadata", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx", + ], + [ + "@theme/Error", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Error/index.tsx", + ], + [ + "@theme/Footer", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-1/Footer/index.js", + ], + [ + "@theme/Layout", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Layout/index.js", + ], + [ + "@theme/Loading", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Loading/index.tsx", + ], + [ + "@theme/Navbar", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/Navbar.js", + ], + [ + "@theme/NavbarItem/NestedNavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/NestedNavbarItem/index.js", + ], + [ + "@theme/NavbarItem/SiblingNavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/SiblingNavbarItem.js", + ], + [ + "@theme/NavbarItem/zzz", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/zzz.js", + ], + [ + "@theme/NavbarItem", + "<PROJECT_ROOT>/packages/docusaurus/src/webpack/aliases/__tests__/__fixtures__/theme-2/NavbarItem/index.js", + ], + [ + "@theme/NotFound", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/NotFound/index.tsx", + ], + [ + "@theme/Root", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/Root/index.tsx", + ], + [ + "@theme/SiteMetadata", + "<PROJECT_ROOT>/packages/docusaurus/src/client/theme-fallback/SiteMetadata/index.tsx", + ], +] +`; diff --git a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts b/packages/docusaurus/src/webpack/aliases/__tests__/index.test.ts similarity index 72% rename from packages/docusaurus/src/server/themes/__tests__/alias.test.ts rename to packages/docusaurus/src/webpack/aliases/__tests__/index.test.ts index 72ed3945152c..b2154a41f5db 100644 --- a/packages/docusaurus/src/server/themes/__tests__/alias.test.ts +++ b/packages/docusaurus/src/webpack/aliases/__tests__/index.test.ts @@ -5,9 +5,14 @@ * LICENSE file in the root directory of this source tree. */ -import path from 'path'; import fs from 'fs-extra'; -import {themeAlias, sortAliases} from '../alias'; +import path from 'path'; +import { + loadThemeAliases, + loadDocusaurusAliases, + sortAliases, + createAliasesForTheme, +} from '../index'; describe('sortAliases', () => { // https://github.com/facebook/docusaurus/issues/6878 @@ -53,11 +58,11 @@ describe('sortAliases', () => { }); }); -describe('themeAlias', () => { - it('valid themePath 1 with components', async () => { +describe('createAliasesForTheme', () => { + it('creates aliases for themePath 1 with components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-1'); - const alias = await themeAlias(themePath, true); + const alias = await createAliasesForTheme(themePath, true); // Testing entries, because order matters! expect(Object.entries(alias)).toEqual( Object.entries({ @@ -70,10 +75,10 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - it('valid themePath 1 with components without original', async () => { + it('creates aliases for themePath 1 with components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-1'); - const alias = await themeAlias(themePath, false); + const alias = await createAliasesForTheme(themePath, false); // Testing entries, because order matters! expect(Object.entries(alias)).toEqual( Object.entries({ @@ -84,10 +89,10 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - it('valid themePath 2 with components', async () => { + it('creates aliases for themePath 2 with components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-2'); - const alias = await themeAlias(themePath, true); + const alias = await createAliasesForTheme(themePath, true); // Testing entries, because order matters! expect(Object.entries(alias)).toEqual( Object.entries({ @@ -127,10 +132,10 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - it('valid themePath 2 with components without original', async () => { + it('creates aliases for themePath 2 with components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'theme-2'); - const alias = await themeAlias(themePath, false); + const alias = await createAliasesForTheme(themePath, false); // Testing entries, because order matters! expect(Object.entries(alias)).toEqual( Object.entries({ @@ -151,26 +156,51 @@ describe('themeAlias', () => { expect(alias).not.toEqual({}); }); - it('valid themePath with no components', async () => { + it('creates themePath with no components', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'empty-theme'); await fs.ensureDir(themePath); - const alias = await themeAlias(themePath, true); + const alias = await createAliasesForTheme(themePath, true); expect(alias).toEqual({}); }); - it('valid themePath with no components without original', async () => { + it('creates themePath with no components without original', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, 'empty-theme'); await fs.ensureDir(themePath); - const alias = await themeAlias(themePath, false); + const alias = await createAliasesForTheme(themePath, false); expect(alias).toEqual({}); }); - it('invalid themePath that does not exist', async () => { + it('creates nothing for invalid themePath that does not exist', async () => { const fixtures = path.join(__dirname, '__fixtures__'); const themePath = path.join(fixtures, '__noExist__'); - const alias = await themeAlias(themePath, true); + const alias = await createAliasesForTheme(themePath, true); expect(alias).toEqual({}); }); }); + +describe('getDocusaurusAliases', () => { + it('returns appropriate webpack aliases', async () => { + await expect(loadDocusaurusAliases()).resolves.toMatchSnapshot(); + }); +}); + +describe('loadThemeAliases', () => { + it('next alias can override the previous alias', async () => { + const fixtures = path.join(__dirname, '__fixtures__'); + const theme1Path = path.join(fixtures, 'theme-1'); + const theme2Path = path.join(fixtures, 'theme-2'); + + const alias = await loadThemeAliases({ + siteDir: fixtures, + plugins: [ + {getThemePath: () => theme1Path}, + {getThemePath: () => theme2Path}, + ], + }); + + // Testing entries, because order matters! + expect(Object.entries(alias)).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus/src/webpack/aliases/index.ts b/packages/docusaurus/src/webpack/aliases/index.ts new file mode 100644 index 000000000000..4f7e67a34ec8 --- /dev/null +++ b/packages/docusaurus/src/webpack/aliases/index.ts @@ -0,0 +1,149 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs-extra'; +import path from 'path'; +import { + THEME_PATH, + fileToPath, + posixPath, + normalizeUrl, + Globby, +} from '@docusaurus/utils'; +import _ from 'lodash'; +import type {ThemeAliases, LoadedPlugin} from '@docusaurus/types'; + +const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback'); + +/** + * Order of Webpack aliases is important because one alias can shadow another. + * This ensures `@theme/NavbarItem` alias is after + * `@theme/NavbarItem/LocaleDropdown`. + * + * @see https://github.com/facebook/docusaurus/pull/3922 + * @see https://github.com/facebook/docusaurus/issues/5382 + */ +export function sortAliases(aliases: ThemeAliases): ThemeAliases { + // Alphabetical order by default + const entries = _.sortBy(Object.entries(aliases), ([alias]) => alias); + // @theme/NavbarItem should be after @theme/NavbarItem/LocaleDropdown + entries.sort(([alias1], [alias2]) => + // eslint-disable-next-line no-nested-ternary + alias1.includes(`${alias2}/`) ? -1 : alias2.includes(`${alias1}/`) ? 1 : 0, + ); + return Object.fromEntries(entries); +} + +export async function createAliasesForTheme( + themePath: string, + addOriginalAlias: boolean, +): Promise<ThemeAliases> { + if (!(await fs.pathExists(themePath))) { + return {}; + } + + const themeComponentFiles = await Globby(['**/*.{js,jsx,ts,tsx}'], { + cwd: themePath, + }); + + const aliases: ThemeAliases = {}; + + themeComponentFiles.forEach((relativeSource) => { + const filePath = path.join(themePath, relativeSource); + const fileName = fileToPath(relativeSource); + + const aliasName = posixPath( + normalizeUrl(['@theme', fileName]).replace(/\/$/, ''), + ); + aliases[aliasName] = filePath; + + if (addOriginalAlias) { + // For swizzled components to access the original. + const originalAliasName = posixPath( + normalizeUrl(['@theme-original', fileName]).replace(/\/$/, ''), + ); + aliases[originalAliasName] = filePath; + } + }); + + return sortAliases(aliases); +} + +async function createThemeAliases( + themePaths: string[], + userThemePaths: string[], +): Promise<ThemeAliases> { + const aliases: ThemeAliases = {}; + + for (const themePath of themePaths) { + const themeAliases = await createAliasesForTheme(themePath, true); + Object.entries(themeAliases).forEach(([aliasKey, alias]) => { + // If this alias shadows a previous one, use @theme-init to preserve the + // initial one. @theme-init is only applied once: to the initial theme + // that provided this component + if (aliasKey in aliases) { + const componentName = aliasKey.substring(aliasKey.indexOf('/') + 1); + const initAlias = `@theme-init/${componentName}`; + if (!(initAlias in aliases)) { + aliases[initAlias] = aliases[aliasKey]!; + } + } + aliases[aliasKey] = alias; + }); + } + + for (const themePath of userThemePaths) { + const userThemeAliases = await createAliasesForTheme(themePath, false); + Object.assign(aliases, userThemeAliases); + } + + return sortAliases(aliases); +} + +export function loadThemeAliases({ + siteDir, + plugins, +}: { + siteDir: string; + plugins: LoadedPlugin[]; +}): Promise<ThemeAliases> { + const pluginThemes: string[] = plugins + .map( + (plugin) => + plugin.getThemePath && path.resolve(plugin.path, plugin.getThemePath()), + ) + .filter((x): x is string => Boolean(x)); + const userTheme = path.resolve(siteDir, THEME_PATH); + return createThemeAliases([ThemeFallbackDir, ...pluginThemes], [userTheme]); +} + +/** + * Note: a `@docusaurus` alias would also catch `@docusaurus/theme-common`, so + * instead of naively aliasing this to `client/exports`, we use fine-grained + * aliases instead. + */ +export async function loadDocusaurusAliases(): Promise<{ + [aliasName: string]: string; +}> { + const dirPath = path.resolve(__dirname, '../../client/exports'); + const extensions = ['.js', '.ts', '.tsx']; + + const aliases: {[key: string]: string} = {}; + + (await fs.readdir(dirPath)) + .filter((fileName) => extensions.includes(path.extname(fileName))) + .forEach((fileName) => { + const fileNameWithoutExtension = path.basename( + fileName, + path.extname(fileName), + ); + const aliasName = `@docusaurus/${fileNameWithoutExtension}`; + aliases[aliasName] = path.resolve(dirPath, fileName); + }); + + return aliases; +} diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 8754e70c9d3b..2c59b7d6a873 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -16,7 +16,7 @@ import { getCustomBabelConfigFilePath, getMinimizer, } from './utils'; -import {loadPluginsThemeAliases} from '../server/themes'; +import {loadThemeAliases, loadDocusaurusAliases} from './aliases'; import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils'; const CSS_REGEX = /\.css$/i; @@ -44,28 +44,6 @@ export function excludeJS(modulePath: string): boolean { ); } -export async function getDocusaurusAliases(): Promise<{ - [aliasName: string]: string; -}> { - const dirPath = path.resolve(__dirname, '../client/exports'); - const extensions = ['.js', '.ts', '.tsx']; - - const aliases: {[key: string]: string} = {}; - - (await fs.readdir(dirPath)) - .filter((fileName) => extensions.includes(path.extname(fileName))) - .forEach((fileName) => { - const fileNameWithoutExtension = path.basename( - fileName, - path.extname(fileName), - ); - const aliasName = `@docusaurus/${fileNameWithoutExtension}`; - aliases[aliasName] = path.resolve(dirPath, fileName); - }); - - return aliases; -} - export async function createBaseConfig( props: Props, isServer: boolean, @@ -92,7 +70,7 @@ export async function createBaseConfig( const name = isServer ? 'server' : 'client'; const mode = isProd ? 'production' : 'development'; - const themeAliases = await loadPluginsThemeAliases({siteDir, plugins}); + const themeAliases = await loadThemeAliases({siteDir, plugins}); return { mode, @@ -156,11 +134,7 @@ export async function createBaseConfig( alias: { '@site': siteDir, '@generated': generatedFilesDir, - - // Note: a @docusaurus alias would also catch @docusaurus/theme-common, - // so we use fine-grained aliases instead - // '@docusaurus': path.resolve(__dirname, '../client/exports'), - ...(await getDocusaurusAliases()), + ...(await loadDocusaurusAliases()), ...themeAliases, }, // This allows you to set a fallback for where Webpack should look for diff --git a/website/docs/docusaurus-core.md b/website/docs/docusaurus-core.md index 00a2848715c9..fcd35040dd0d 100644 --- a/website/docs/docusaurus-core.md +++ b/website/docs/docusaurus-core.md @@ -341,7 +341,7 @@ type PluginVersionInformation = | {readonly type: 'local'} | {readonly type: 'synthetic'}; -interface DocusaurusSiteMetadata { +interface SiteMetadata { readonly docusaurusVersion: string; readonly siteVersion?: string; readonly pluginVersions: Record<string, PluginVersionInformation>; @@ -361,7 +361,7 @@ interface I18n { interface DocusaurusContext { siteConfig: DocusaurusConfig; - siteMetadata: DocusaurusSiteMetadata; + siteMetadata: SiteMetadata; globalData: Record<string, unknown>; i18n: I18n; codeTranslations: Record<string, string>; From 4f4f503633581e24c442aa9ab34b803df6349bc3 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 28 Mar 2022 21:59:29 +0800 Subject: [PATCH 094/405] fix(utils): parse Markdown headings with CRLF line break (#7043) --- .../src/__tests__/markdownUtils.test.ts | 16 ++++++++++++++++ packages/docusaurus-utils/src/markdownUtils.ts | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts index f0a7ca3201c0..5d32b07f1702 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts @@ -253,6 +253,22 @@ Lorem Ipsum }); }); + it('parses markdown h1 title with CRLF break', () => { + const markdown = `# Markdown Title\r\n\r\nLorem Ipsum`; + expect(parseMarkdownContentTitle(markdown)).toEqual({ + content: markdown, + contentTitle: 'Markdown Title', + }); + }); + + it('parses markdown h1 setext title with CRLF break', () => { + const markdown = `Markdown Title\r\n=====\r\n\r\nLorem Ipsum`; + expect(parseMarkdownContentTitle(markdown)).toEqual({ + content: markdown, + contentTitle: 'Markdown Title', + }); + }); + it('parses markdown h1 title at the top (atx style with closing #)', () => { const markdown = dedent` diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index de92ce0f33b3..a902c6f58fa0 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -198,13 +198,13 @@ export function parseMarkdownContentTitle( // `import` nodes, as broken syntax can't render anyways. That means any block // that has `import` at the very beginning and surrounded by empty lines. const contentWithoutImport = content - .replace(/^(?:import\s(?:.|\n(?!\n))*\n{2,})*/, '') + .replace(/^(?:import\s(?:.|\r?\n(?!\r?\n))*(?:\r?\n){2,})*/, '') .trim(); - const regularTitleMatch = /^#[ \t]+(?<title>[^ \t].*)(?:\n|$)/.exec( + const regularTitleMatch = /^#[ \t]+(?<title>[^ \t].*)(?:\r?\n|$)/.exec( contentWithoutImport, ); - const alternateTitleMatch = /^(?<title>.*)\n=+(?:\n|$)/.exec( + const alternateTitleMatch = /^(?<title>.*)\r?\n=+(?:\r?\n|$)/.exec( contentWithoutImport, ); From 118ca63c72b6610b5d3330b2c397cddce244db03 Mon Sep 17 00:00:00 2001 From: deployn <54767886+deployn@users.noreply.github.com> Date: Mon, 28 Mar 2022 16:12:34 +0200 Subject: [PATCH 095/405] chore(theme-translations): complete German translations (#7031) * Update German locales * Update German locales * Update German locales * update locales --- .../locales/de/plugin-ideal-image.json | 10 +++---- .../locales/de/theme-common.json | 30 +++++++++---------- .../locales/de/theme-search-algolia.json | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/docusaurus-theme-translations/locales/de/plugin-ideal-image.json b/packages/docusaurus-theme-translations/locales/de/plugin-ideal-image.json index 3576b692c08d..eda06f750f11 100644 --- a/packages/docusaurus-theme-translations/locales/de/plugin-ideal-image.json +++ b/packages/docusaurus-theme-translations/locales/de/plugin-ideal-image.json @@ -1,7 +1,7 @@ { - "theme.IdealImageMessage.404error": "404. Image not found", - "theme.IdealImageMessage.error": "Error. Click to reload", - "theme.IdealImageMessage.load": "Click to load{sizeMessage}", - "theme.IdealImageMessage.loading": "Loading...", - "theme.IdealImageMessage.offline": "Your browser is offline. Image not loaded" + "theme.IdealImageMessage.404error": "404. Bild nicht gefunden.", + "theme.IdealImageMessage.error": "Fehler. Zum neu laden klicken", + "theme.IdealImageMessage.load": "Zum Laden klicken {sizeMessage}", + "theme.IdealImageMessage.loading": "Wird geladen...", + "theme.IdealImageMessage.offline": "Browser ist offline. Bild nicht geladen" } diff --git a/packages/docusaurus-theme-translations/locales/de/theme-common.json b/packages/docusaurus-theme-translations/locales/de/theme-common.json index 9be17350a486..54c567dedeec 100644 --- a/packages/docusaurus-theme-translations/locales/de/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/de/theme-common.json @@ -4,15 +4,15 @@ "theme.CodeBlock.copied": "Kopiert", "theme.CodeBlock.copy": "Kopieren", "theme.CodeBlock.copyButtonAriaLabel": "In die Zwischenablage kopieren", - "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'", - "theme.ErrorPageContent.title": "This page crashed.", - "theme.ErrorPageContent.tryAgain": "Try again", + "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Umschalten der Seitenleiste mit einklappbarer Kategorie '{label}'", + "theme.ErrorPageContent.title": "Die Seite ist abgestürzt.", + "theme.ErrorPageContent.tryAgain": "Nochmal versuchen", "theme.NotFound.p1": "Wir konnten nicht finden, wonach Sie gesucht haben.", "theme.NotFound.p2": "Bitte kontaktieren Sie den Besitzer der Seite, die Sie mit der ursprünglichen URL verlinkt hat, und teilen Sie ihm mit, dass der Link nicht mehr funktioniert.", "theme.NotFound.title": "Seite nicht gefunden", "theme.TOCCollapsible.toggleButtonLabel": "Auf dieser Seite", - "theme.blog.archive.description": "Archive", - "theme.blog.archive.title": "Archive", + "theme.blog.archive.description": "Archiv", + "theme.blog.archive.title": "Archiv", "theme.blog.paginator.navAriaLabel": "Navigation der Blog-Listenseite", "theme.blog.paginator.newerEntries": "Neuere Einträge", "theme.blog.paginator.olderEntries": "Ältere Einträge", @@ -21,17 +21,17 @@ "theme.blog.post.paginator.olderPost": "Älterer Post", "theme.blog.post.plurals": "Ein Post|{count} Posts", "theme.blog.post.readMore": "Mehr lesen", - "theme.blog.post.readMoreLabel": "Read more about {title}", + "theme.blog.post.readMoreLabel": "Mehr lesen über {title}", "theme.blog.post.readingTime.plurals": "Eine Minute Lesezeit|{readingTime} Minuten Lesezeit", - "theme.blog.sidebar.navAriaLabel": "Blog recent posts navigation", + "theme.blog.sidebar.navAriaLabel": "Navigation der letzten Beiträge im Blog", "theme.blog.tagTitle": "{nPosts} getaggt mit \"{tagName}\"", - "theme.colorToggle.ariaLabel": "Switch between dark and light mode (currently {mode})", - "theme.colorToggle.ariaLabel.mode.dark": "dark mode", - "theme.colorToggle.ariaLabel.mode.light": "light mode", + "theme.colorToggle.ariaLabel": "Umschalten zwischen dunkler und heller Ansicht (momentan {mode})", + "theme.colorToggle.ariaLabel.mode.dark": "dunkler Modus", + "theme.colorToggle.ariaLabel.mode.light": "heller Modus", "theme.common.editThisPage": "Diese Seite bearbeiten", "theme.common.headingLinkTitle": "Direkter Link zur Überschrift", "theme.common.skipToMainContent": "Zum Hauptinhalt springen", - "theme.docs.DocCard.categoryDescription": "{count} items", + "theme.docs.DocCard.categoryDescription": "{count} Einträge", "theme.docs.paginator.navAriaLabel": "Dokumentation Seiten Navigation", "theme.docs.paginator.next": "Weiter", "theme.docs.paginator.previous": "Zurück", @@ -39,8 +39,8 @@ "theme.docs.sidebar.collapseButtonTitle": "Seitenleiste einklappen", "theme.docs.sidebar.expandButtonAriaLabel": "Seitenleiste ausklappen", "theme.docs.sidebar.expandButtonTitle": "Seitenleiste ausklappen", - "theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"", - "theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged", + "theme.docs.tagDocListPageTitle": "{nDocsTagged} mit \"{tagName}\"", + "theme.docs.tagDocListPageTitle.nDocsTagged": "Ein doc getaggt|{count} docs getaggt", "theme.docs.versionBadge.label": "Version: {versionLabel}", "theme.docs.versions.latestVersionLinkLabel": "letzte Version", "theme.docs.versions.latestVersionSuggestionLabel": "Für die aktuellste Dokumentation bitte auf {latestVersionLink} ({versionLabel}) gehen.", @@ -49,9 +49,9 @@ "theme.lastUpdated.atDate": " am {date}", "theme.lastUpdated.byUser": " von {user}", "theme.lastUpdated.lastUpdatedAtBy": "Letztes Update{atDate}{byUser}", - "theme.navbar.mobileLanguageDropdown.label": "Languages", + "theme.navbar.mobileLanguageDropdown.label": "Sprachen", "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Zurück zum Hauptmenü", - "theme.navbar.mobileVersionsDropdown.label": "Versions", + "theme.navbar.mobileVersionsDropdown.label": "Versionen", "theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsPageLink": "Alle Tags anzeigen", "theme.tags.tagsPageTitle": "Tags" diff --git a/packages/docusaurus-theme-translations/locales/de/theme-search-algolia.json b/packages/docusaurus-theme-translations/locales/de/theme-search-algolia.json index f130478f8903..e0816abc0a81 100644 --- a/packages/docusaurus-theme-translations/locales/de/theme-search-algolia.json +++ b/packages/docusaurus-theme-translations/locales/de/theme-search-algolia.json @@ -1,6 +1,6 @@ { "theme.SearchBar.label": "Suche", - "theme.SearchBar.seeAll": "See all {count} results", + "theme.SearchBar.seeAll": "Alle {count} Ergebnisse anzeigen", "theme.SearchPage.algoliaLabel": "Suche von Algolia", "theme.SearchPage.documentsFound.plurals": "Ein Dokument gefunden|{count} Dokumente gefunden", "theme.SearchPage.emptyResultsTitle": "Suche in der Dokumentation", From 37a5dfacccbf7ab891ba02a21c3e459dc8cf4a44 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Tue, 29 Mar 2022 01:40:41 +0300 Subject: [PATCH 096/405] fix(theme-classic): add caret for dropdown on mobile (#7048) --- .../src/theme/NavbarItem/DropdownNavbarItem.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx index 0c5fc67c3d01..37dd48692452 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx @@ -157,7 +157,10 @@ function DropdownNavbarItemMobile({ })}> <NavbarNavLink role="button" - className={clsx('menu__link menu__link--sublist', className)} + className={clsx( + 'menu__link menu__link--sublist menu__link--sublist-caret', + className, + )} {...props} onClick={(e) => { e.preventDefault(); From b5fc9a6b6d8108f951977ed1483bb25bac56794a Mon Sep 17 00:00:00 2001 From: duanwilliam <38791932+duanwilliam@users.noreply.github.com> Date: Mon, 28 Mar 2022 18:23:03 -0700 Subject: [PATCH 097/405] fix(theme): add bash style to Markdown comment styles (#7049) * docs: fix code block line highlighting in md syntax highlighting * properly fix Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../docusaurus-theme-common/src/utils/codeBlockUtils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index dbc24112151c..cc28c5d21feb 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -15,7 +15,7 @@ const commentPatterns = { js: {start: '\\/\\/', end: ''}, jsBlock: {start: '\\/\\*', end: '\\*\\/'}, jsx: {start: '\\{\\s*\\/\\*', end: '\\*\\/\\s*\\}'}, - python: {start: '#', end: ''}, + bash: {start: '#', end: ''}, html: {start: '<!--', end: '-->'}, }; @@ -59,11 +59,13 @@ function getAllMagicCommentDirectiveStyles(lang: string) { case 'python': case 'py': - return getCommentPattern(['python']); + case 'bash': + return getCommentPattern(['bash']); case 'markdown': case 'md': - return getCommentPattern(['html', 'jsx']); + // Text uses HTML, front matter uses bash + return getCommentPattern(['html', 'jsx', 'bash']); default: // all comment types From e31e91ef478c5b2e5c7ed0a059a38e0e4f588046 Mon Sep 17 00:00:00 2001 From: Kayce Basques <kayce@basqu.es> Date: Mon, 28 Mar 2022 18:30:35 -0700 Subject: [PATCH 098/405] docs: add import React statement in JSX file example (#7050) --- .../docs/guides/markdown-features/markdown-features-react.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/guides/markdown-features/markdown-features-react.mdx b/website/docs/guides/markdown-features/markdown-features-react.mdx index 08530fd72efc..230d5888ef68 100644 --- a/website/docs/guides/markdown-features/markdown-features-react.mdx +++ b/website/docs/guides/markdown-features/markdown-features-react.mdx @@ -110,6 +110,8 @@ The `@site` alias points to your website's directory, usually where the `docusau While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate `.js` file when your component involves complex JS logic: ```jsx title="src/components/Highlight.js" +import React from 'react'; + export default function Highlight({children, color}) { return ( <span From 77662260f82a0d550f88846f2b70ad69a24841f1 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Tue, 29 Mar 2022 16:37:29 +0800 Subject: [PATCH 099/405] refactor(core): refactor routes generation logic (#7054) * refactor(core): refactor routes generation logic * fixes --- .../src/index.d.ts | 18 +- .../src/index.ts | 20 +- .../src/utils/__tests__/routesUtils.test.ts | 4 +- .../src/utils/routesUtils.ts | 14 +- packages/docusaurus-types/src/index.d.ts | 309 ++++++++++------ .../src/__tests__/emitUtils.test.ts | 51 +-- packages/docusaurus-utils/src/emitUtils.ts | 35 +- packages/docusaurus-utils/src/index.ts | 2 +- packages/docusaurus/src/client/docusaurus.ts | 16 +- .../src/client/exports/ComponentCreator.tsx | 21 +- packages/docusaurus/src/client/flat.ts | 21 +- .../__snapshots__/routes.test.ts.snap | 35 +- .../src/server/__tests__/routes.test.ts | 53 ++- .../docusaurus/src/server/plugins/index.ts | 84 ++--- .../src/server/plugins/routeConfig.ts | 1 + packages/docusaurus/src/server/routes.ts | 333 ++++++++++-------- .../src/webpack/__tests__/utils.test.ts | 15 +- packages/docusaurus/src/webpack/utils.ts | 7 +- .../docs/api/plugin-methods/lifecycle-apis.md | 6 +- 19 files changed, 545 insertions(+), 500 deletions(-) diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index c069c7cb7adb..e8a8655a1e79 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -27,24 +27,26 @@ declare module '@generated/site-metadata' { } declare module '@generated/registry' { - const registry: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - readonly [key: string]: [() => Promise<any>, string, string]; - }; + import type {Registry} from '@docusaurus/types'; + + const registry: Registry; export default registry; } declare module '@generated/routes' { - import type {Route} from '@docusaurus/types'; + import type {RouteConfig as RRRouteConfig} from 'react-router-config'; - const routes: Route[]; + type RouteConfig = RRRouteConfig & { + path: string; + }; + const routes: RouteConfig[]; export default routes; } declare module '@generated/routesChunkNames' { - import type {RouteChunksTree} from '@docusaurus/types'; + import type {RouteChunkNames} from '@docusaurus/types'; - const routesChunkNames: {[route: string]: RouteChunksTree}; + const routesChunkNames: RouteChunkNames; export = routesChunkNames; } diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 93cf975f8be3..c1b8d82089ef 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -292,19 +292,15 @@ export default async function pluginContentBlog( exact: true, modules: { sidebar: aliasedSource(sidebarProp), - items: items.map((postID) => - // To tell routes.js this is an import and not a nested object - // to recurse. - ({ - content: { - __import: true, - path: blogItemsToMetadata[postID]!.source, - query: { - truncated: true, - }, + items: items.map((postID) => ({ + content: { + __import: true, + path: blogItemsToMetadata[postID]!.source, + query: { + truncated: true, }, - }), - ), + }, + })), metadata: aliasedSource(pageMetadataPath), }, }); diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts index a36e447d72a5..a226c13f1156 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/routesUtils.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import type {Route} from '@docusaurus/types'; +import type {RouteConfig} from 'react-router-config'; import {findHomePageRoute, isSamePath} from '../routesUtils'; describe('isSamePath', () => { @@ -41,7 +41,7 @@ describe('isSamePath', () => { }); describe('findHomePageRoute', () => { - const homePage: Route = { + const homePage: RouteConfig = { path: '/', exact: true, }; diff --git a/packages/docusaurus-theme-common/src/utils/routesUtils.ts b/packages/docusaurus-theme-common/src/utils/routesUtils.ts index 2b48b8bccde2..4faa24b675a0 100644 --- a/packages/docusaurus-theme-common/src/utils/routesUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/routesUtils.ts @@ -8,7 +8,7 @@ import {useMemo} from 'react'; import generatedRoutes from '@generated/routes'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import type {Route} from '@docusaurus/types'; +import type {RouteConfig} from 'react-router-config'; /** * Compare the 2 paths, case insensitive and ignoring trailing slash @@ -34,18 +34,18 @@ export function findHomePageRoute({ baseUrl, routes: initialRoutes, }: { - routes: Route[]; + routes: RouteConfig[]; baseUrl: string; -}): Route | undefined { - function isHomePageRoute(route: Route): boolean { +}): RouteConfig | undefined { + function isHomePageRoute(route: RouteConfig): boolean { return route.path === baseUrl && route.exact === true; } - function isHomeParentRoute(route: Route): boolean { + function isHomeParentRoute(route: RouteConfig): boolean { return route.path === baseUrl && !route.exact; } - function doFindHomePageRoute(routes: Route[]): Route | undefined { + function doFindHomePageRoute(routes: RouteConfig[]): RouteConfig | undefined { if (routes.length === 0) { return undefined; } @@ -66,7 +66,7 @@ export function findHomePageRoute({ * Fetches the route that points to "/". Use this instead of the naive "/", * because the homepage may not exist. */ -export function useHomePageRoute(): Route | undefined { +export function useHomePageRoute(): RouteConfig | undefined { const {baseUrl} = useDocusaurusContext().siteConfig; return useMemo( () => findHomePageRoute({routes: generatedRoutes, baseUrl}), diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 0d0db0682136..2c33f1599a3e 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -11,19 +11,42 @@ import type {CommanderStatic} from 'commander'; import type {ParsedUrlQueryInput} from 'querystring'; import type Joi from 'joi'; import type { + DeepRequired, Required as RequireKeys, DeepPartial, - DeepRequired, } from 'utility-types'; import type {Location} from 'history'; -import type Loadable from 'react-loadable'; + +// === Configuration === export type ReportingSeverity = 'ignore' | 'log' | 'warn' | 'error' | 'throw'; +export type PluginOptions = {id?: string} & {[key: string]: unknown}; + +export type PluginConfig = + | string + | [string, PluginOptions] + | [PluginModule, PluginOptions] + | PluginModule; + +export type PresetConfig = string | [string, {[key: string]: unknown}]; + export type ThemeConfig = { [key: string]: unknown; }; +export type I18nLocaleConfig = { + label: string; + htmlLang: string; + direction: string; +}; + +export type I18nConfig = { + defaultLocale: string; + locales: [string, ...string[]]; + localeConfigs: {[locale: string]: Partial<I18nLocaleConfig>}; +}; + /** * Docusaurus config, after validation/normalization. */ @@ -92,6 +115,8 @@ export type Config = RequireKeys< 'title' | 'url' | 'baseUrl' >; +// === Data loading === + /** * - `type: 'package'`, plugin is in a different package. * - `type: 'project'`, plugin is in the same docusaurus project. @@ -115,26 +140,29 @@ export type SiteMetadata = { readonly pluginVersions: {[pluginName: string]: PluginVersionInformation}; }; -// Inspired by Chrome JSON, because it's a widely supported i18n format -// https://developer.chrome.com/apps/i18n-messages -// https://support.crowdin.com/file-formats/chrome-json/ -// https://www.applanga.com/docs/formats/chrome_i18n_json -// https://docs.transifex.com/formats/chrome-json -// https://help.phrase.com/help/chrome-json-messages +/** + * Inspired by Chrome JSON, because it's a widely supported i18n format + * @see https://developer.chrome.com/apps/i18n-messages + * @see https://support.crowdin.com/file-formats/chrome-json/ + * @see https://www.applanga.com/docs/formats/chrome_i18n_json + * @see https://docs.transifex.com/formats/chrome-json + * @see https://help.phrase.com/help/chrome-json-messages + */ export type TranslationMessage = {message: string; description?: string}; export type TranslationFileContent = {[key: string]: TranslationMessage}; -export type TranslationFile = {path: string; content: TranslationFileContent}; - -export type I18nLocaleConfig = { - label: string; - htmlLang: string; - direction: string; -}; - -export type I18nConfig = { - defaultLocale: string; - locales: [string, ...string[]]; - localeConfigs: {[locale: string]: Partial<I18nLocaleConfig>}; +/** + * An abstract representation of how a translation file exists on disk. The core + * would handle the file reading/writing; plugins just need to deal with + * translations in-memory. + */ +export type TranslationFile = { + /** + * Relative to the directory where it's expected to be found. For plugin + * files, it's relative to `i18n/<locale>/<pluginName>/<pluginId>`. Should NOT + * have any extension. + */ + path: string; + content: TranslationFileContent; }; export type I18n = DeepRequired<I18nConfig> & {currentLocale: string}; @@ -153,21 +181,6 @@ export type DocusaurusContext = { // isBrowser: boolean; // Not here on purpose! }; -export type Preset = { - plugins?: PluginConfig[]; - themes?: PluginConfig[]; -}; - -export type PresetModule = { - <T>(context: LoadContext, presetOptions: T): Preset; -}; - -export type ImportedPresetModule = PresetModule & { - default?: PresetModule; -}; - -export type PresetConfig = string | [string, {[key: string]: unknown}]; - export type HostPortCLIOptions = { host?: string; port?: string; @@ -191,14 +204,11 @@ export type ServeCLIOptions = HostPortCLIOptions & build: boolean; }; -export type BuildOptions = ConfigOptions & { +export type BuildCLIOptions = ConfigOptions & { bundleAnalyzer: boolean; outDir: string; minify: boolean; skipBuild: boolean; -}; - -export type BuildCLIOptions = BuildOptions & { locale?: string; }; @@ -219,8 +229,6 @@ export type LoadContext = { codeTranslations: {[msgId: string]: string}; }; -export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[]; - export type Props = LoadContext & { readonly headTags: string; readonly preBodyTags: string; @@ -231,12 +239,27 @@ export type Props = LoadContext & { readonly plugins: LoadedPlugin[]; }; +// === Plugin === + export type PluginContentLoadedActions = { addRoute: (config: RouteConfig) => void; createData: (name: string, data: string) => Promise<string>; setGlobalData: (data: unknown) => void; }; +export type ConfigureWebpackUtils = { + getStyleLoaders: ( + isServer: boolean, + cssOptions: { + [key: string]: unknown; + }, + ) => RuleSetRule[]; + getJSLoader: (options: { + isServer: boolean; + babelOptions?: {[key: string]: unknown}; + }) => RuleSetRule; +}; + export type AllContent = { [pluginName: string]: { [pluginID: string]: unknown; @@ -246,6 +269,37 @@ export type AllContent = { // TODO improve type (not exposed by postcss-loader) export type PostCssOptions = {[key: string]: unknown} & {plugins: unknown[]}; +type HtmlTagObject = { + /** + * Attributes of the html tag. + * E.g. `{ disabled: true, value: "demo", rel: "preconnect" }` + */ + attributes?: Partial<{[key: string]: string | boolean}>; + /** The tag name, e.g. `div`, `script`, `link`, `meta` */ + tagName: string; + /** The inner HTML */ + innerHTML?: string; +}; + +export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[]; + +export type ValidationSchema<T> = Joi.ObjectSchema<T>; + +export type Validate<T, U> = ( + validationSchema: ValidationSchema<U>, + options: T, +) => U; + +export type OptionValidationContext<T, U> = { + validate: Validate<T, U>; + options: T; +}; + +export type ThemeConfigValidationContext<T> = { + validate: Validate<T, T>; + themeConfig: Partial<T>; +}; + export type Plugin<Content = unknown> = { name: string; loadContent?: () => Promise<Content>; @@ -266,7 +320,9 @@ export type Plugin<Content = unknown> = { utils: ConfigureWebpackUtils, content: Content, ) => WebpackConfiguration & { - mergeStrategy?: ConfigureWebpackFnMergeStrategy; + mergeStrategy?: { + [key: string]: CustomizeRuleString; + }; }; configurePostCss?: (options: PostCssOptions) => PostCssOptions; getThemePath?: () => string; @@ -334,9 +390,7 @@ export type NormalizedPluginConfig = { export type InitializedPlugin = Plugin & { readonly options: Required<PluginOptions>; readonly version: PluginVersionInformation; - /** - * The absolute path to the folder containing the entry point file. - */ + /** The absolute path to the folder containing the entry point file. */ readonly path: string; }; @@ -372,48 +426,71 @@ export type ImportedPluginModule = PluginModule & { default?: PluginModule; }; -export type ConfigureWebpackFn = Plugin['configureWebpack']; -export type ConfigureWebpackFnMergeStrategy = { - [key: string]: CustomizeRuleString; +export type Preset = { + plugins?: PluginConfig[]; + themes?: PluginConfig[]; }; -export type ConfigurePostCssFn = Plugin['configurePostCss']; - -export type PluginOptions = {id?: string} & {[key: string]: unknown}; -export type PluginConfig = - | string - | [string, PluginOptions] - | [PluginModule, PluginOptions] - | PluginModule; +export type PresetModule = { + <T>(context: LoadContext, presetOptions: T): Preset; +}; -export type ChunkRegistry = { - loader: string; - modulePath: string; +export type ImportedPresetModule = PresetModule & { + default?: PresetModule; }; +// === Route registry === + +/** + * A "module" represents a unit of serialized data emitted from the plugin. It + * will be imported on client-side and passed as props, context, etc. + * + * If it's a string, it's a file path that Webpack can `require`; if it's + * an object, it can also contain `query` or other metadata. + */ export type Module = | { - path: string; + /** + * A marker that tells the route generator this is an import and not a + * nested object to recurse. + */ __import?: boolean; + path: string; query?: ParsedUrlQueryInput; } | string; -export type RouteModule = { - [module: string]: Module | RouteModule | RouteModule[]; -}; - -export type ChunkNames = { - [name: string]: string | null | ChunkNames | ChunkNames[]; +/** + * Represents the data attached to each route. Since the routes.js is a + * monolithic data file, any data (like props) should be serialized separately + * and registered here as file paths (a {@link Module}), so that we could + * code-split. + */ +export type RouteModules = { + [propName: string]: Module | RouteModules | RouteModules[]; }; +/** + * Represents a "slice" of the final route structure returned from the plugin + * `addRoute` action. + */ export type RouteConfig = { + /** With leading slash. Trailing slash will be normalized by config. */ path: string; + /** Component used to render this route, a path that Webpack can `require`. */ component: string; - modules?: RouteModule; + /** + * Props. Each entry should be `[propName]: pathToPropModule` (created with + * `createData`) + */ + modules?: RouteModules; + /** Nested routes config. */ routes?: RouteConfig[]; + /** React router config option: `exact` routes would not match subroutes. */ exact?: boolean; + /** Used to sort routes. Higher-priority routes will be placed first. */ priority?: number; + /** Extra props; will be copied to routes.js. */ [propName: string]: unknown; }; @@ -435,60 +512,64 @@ export type PluginRouteContext = RouteContext & { }; }; -export type Route = { - readonly path: string; - readonly component: ReturnType<typeof Loadable>; - readonly exact?: boolean; - readonly routes?: Route[]; -}; - /** - * Aliases used for Webpack resolution (useful for implementing swizzling) + * The shape would be isomorphic to {@link RouteModules}: + * {@link Module} -> `string`, `RouteModules[]` -> `ChunkNames[]`. + * + * Each `string` chunk name will correlate with one key in the {@link Registry}. */ -export type ThemeAliases = { - [alias: string]: string; -}; - -export type ConfigureWebpackUtils = { - getStyleLoaders: ( - isServer: boolean, - cssOptions: { - [key: string]: unknown; - }, - ) => RuleSetRule[]; - getJSLoader: (options: { - isServer: boolean; - babelOptions?: {[key: string]: unknown}; - }) => RuleSetRule; +export type ChunkNames = { + [propName: string]: string | ChunkNames | ChunkNames[]; }; -type HtmlTagObject = { - /** - * Attributes of the html tag. - * E.g. `{ disabled: true, value: "demo", rel: "preconnect" }` - */ - attributes?: Partial<{[key: string]: string | boolean}>; - /** The tag name, e.g. `div`, `script`, `link`, `meta` */ - tagName: string; - /** The inner HTML */ - innerHTML?: string; +/** + * A map from route paths (with a hash) to the chunk names of each module, which + * the bundler will collect. + * + * Chunk keys are routes with a hash, because 2 routes can conflict with each + * other if they have the same path, e.g.: parent=/docs, child=/docs + * + * @see https://github.com/facebook/docusaurus/issues/2917 + */ +export type RouteChunkNames = { + [routePathHashed: string]: ChunkNames; }; -export type ValidationSchema<T> = Joi.ObjectSchema<T>; - -export type Validate<T, U> = ( - validationSchema: ValidationSchema<U>, - options: T, -) => U; - -export type OptionValidationContext<T, U> = { - validate: Validate<T, U>; - options: T; +/** + * Each key is the chunk name, which you can get from `routeChunkNames` (see + * {@link RouteChunkNames}). The values are the opts data that react-loadable + * needs. For example: + * + * ```js + * const options = { + * optsLoader: { + * component: () => import('./Pages.js'), + * content.foo: () => import('./doc1.md'), + * }, + * optsModules: ['./Pages.js', './doc1.md'], + * optsWebpack: [ + * require.resolveWeak('./Pages.js'), + * require.resolveWeak('./doc1.md'), + * ], + * } + * ``` + * + * @see https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded + */ +export type Registry = { + readonly [chunkName: string]: [ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Loader: () => Promise<any>, + ModuleName: string, + ResolvedModuleName: string, + ]; }; -export type ThemeConfigValidationContext<T> = { - validate: Validate<T, T>; - themeConfig: Partial<T>; +/** + * Aliases used for Webpack resolution (useful for implementing swizzling) + */ +export type ThemeAliases = { + [alias: string]: string; }; export type TOCItem = { @@ -497,8 +578,6 @@ export type TOCItem = { readonly level: number; }; -export type RouteChunksTree = {[x: string | number]: string | RouteChunksTree}; - export type ClientModule = { onRouteUpdate?: (args: { previousLocation: Location | null; diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 2fe8cb7d34e3..e5f975abb9f0 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -6,59 +6,10 @@ */ import {jest} from '@jest/globals'; -import {genChunkName, readOutputHTMLFile, generate} from '../emitUtils'; +import {readOutputHTMLFile, generate} from '../emitUtils'; import path from 'path'; import fs from 'fs-extra'; -describe('genChunkName', () => { - it('works', () => { - const firstAssert: {[key: string]: string} = { - '/docs/adding-blog': 'docs-adding-blog-062', - '/docs/versioning': 'docs-versioning-8a8', - '/': 'index', - '/blog/2018/04/30/How-I-Converted-Profilo-To-Docusaurus': - 'blog-2018-04-30-how-i-converted-profilo-to-docusaurus-4f2', - '/youtube': 'youtube-429', - '/users/en/': 'users-en-f7a', - '/blog': 'blog-c06', - }; - Object.keys(firstAssert).forEach((str) => { - expect(genChunkName(str)).toBe(firstAssert[str]); - }); - }); - - it("doesn't allow different chunk name for same path", () => { - expect(genChunkName('path/is/similar', 'oldPrefix')).toEqual( - genChunkName('path/is/similar', 'newPrefix'), - ); - }); - - it('emits different chunk names for different paths even with same preferred name', () => { - const secondAssert: {[key: string]: string} = { - '/blog/1': 'blog-85-f-089', - '/blog/2': 'blog-353-489', - }; - Object.keys(secondAssert).forEach((str) => { - expect(genChunkName(str, undefined, 'blog')).toBe(secondAssert[str]); - }); - }); - - it('only generates short unique IDs', () => { - const thirdAssert: {[key: string]: string} = { - a: '0cc175b9', - b: '92eb5ffe', - c: '4a8a08f0', - d: '8277e091', - }; - Object.keys(thirdAssert).forEach((str) => { - expect(genChunkName(str, undefined, undefined, true)).toBe( - thirdAssert[str], - ); - }); - expect(genChunkName('d', undefined, undefined, true)).toBe('8277e091'); - }); -}); - describe('readOutputHTMLFile', () => { it('trailing slash undefined', async () => { await expect( diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index ba4e29de0832..89680f92ad08 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -8,7 +8,6 @@ import path from 'path'; import fs from 'fs-extra'; import {createHash} from 'crypto'; -import {simpleHash, docuHash} from './hashUtils'; import {findAsyncSequential} from './jsUtils'; const fileHash = new Map<string, string>(); @@ -18,7 +17,8 @@ const fileHash = new Map<string, string>(); * differs from cache (for hot reload performance). * * @param generatedFilesDir Absolute path. - * @param file Path relative to `generatedFilesDir`. + * @param file Path relative to `generatedFilesDir`. File will always be + * outputted; no need to ensure directory exists. * @param content String content to write. * @param skipCache If `true` (defaults as `true` for production), file is * force-rewritten, skipping cache. @@ -29,7 +29,7 @@ export async function generate( content: string, skipCache: boolean = process.env.NODE_ENV === 'production', ): Promise<void> { - const filepath = path.join(generatedFilesDir, file); + const filepath = path.resolve(generatedFilesDir, file); if (skipCache) { await fs.outputFile(filepath, content); @@ -62,35 +62,6 @@ export async function generate( } } -const chunkNameCache = new Map<string, string>(); - -/** - * Generate unique chunk name given a module path. - */ -export function genChunkName( - modulePath: string, - prefix?: string, - preferredName?: string, - shortId: boolean = process.env.NODE_ENV === 'production', -): string { - let chunkName = chunkNameCache.get(modulePath); - if (!chunkName) { - if (shortId) { - chunkName = simpleHash(modulePath, 8); - } else { - let str = modulePath; - if (preferredName) { - const shortHash = simpleHash(modulePath, 3); - str = `${preferredName}${shortHash}`; - } - const name = str === '/' ? 'index' : docuHash(str); - chunkName = prefix ? `${prefix}---${name}` : name; - } - chunkNameCache.set(modulePath, chunkName); - } - return chunkName; -} - /** * @param permalink The URL that the HTML file corresponds to, without base URL * @param outDir Full path to the output directory diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 999cc1928f08..7cd871a631e8 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -22,7 +22,7 @@ export { DEFAULT_PLUGIN_ID, WEBPACK_URL_LOADER_LIMIT, } from './constants'; -export {generate, genChunkName, readOutputHTMLFile} from './emitUtils'; +export {generate, readOutputHTMLFile} from './emitUtils'; export { getFileCommitDate, FileNotTrackedError, diff --git a/packages/docusaurus/src/client/docusaurus.ts b/packages/docusaurus/src/client/docusaurus.ts index 20923a84d48e..1ee1605b1a35 100644 --- a/packages/docusaurus/src/client/docusaurus.ts +++ b/packages/docusaurus/src/client/docusaurus.ts @@ -34,20 +34,16 @@ const canPrefetch = (routePath: string) => const canPreload = (routePath: string) => !isSlowConnection() && !loaded[routePath]; -// Remove the last part containing the route hash -// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9 -// output: /blog/2018/12/14/Happy-First-Birthday-Slash -const removeRouteNameHash = (str: string) => str.replace(/-[^-]+$/, ''); - const getChunkNamesToLoad = (path: string): string[] => Object.entries(routesChunkNames) .filter( - ([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path, + // Remove the last part containing the route hash + // input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9 + // output: /blog/2018/12/14/Happy-First-Birthday-Slash + ([routeNameWithHash]) => + routeNameWithHash.replace(/-[^-]+$/, '') === path, ) - .flatMap(([, routeChunks]) => - // flat() is useful for nested chunk names, it's not like array.flat() - Object.values(flat(routeChunks)), - ); + .flatMap(([, routeChunks]) => Object.values(flat(routeChunks))); const docusaurus = { prefetch: (routePath: string): boolean => { diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 9d59a19492be..86c52a213ed3 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -34,27 +34,12 @@ export default function ComponentCreator( }); } - const chunkNamesKey = `${path}-${hash}`; - const chunkNames = routesChunkNames[chunkNamesKey]!; - const optsModules: string[] = []; - const optsWebpack: string[] = []; + const chunkNames = routesChunkNames[`${path}-${hash}`]!; // eslint-disable-next-line @typescript-eslint/no-explicit-any const optsLoader: {[key: string]: () => Promise<any>} = {}; + const optsModules: string[] = []; + const optsWebpack: string[] = []; - /* Prepare opts data that react-loadable needs - https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded - Example: - - optsLoader: - { - component: () => import('./Pages.js'), - content.foo: () => import('./doc1.md'), - } - - optsModules: ['./Pages.js', './doc1.md'] - - optsWebpack: [ - require.resolveWeak('./Pages.js'), - require.resolveWeak('./doc1.md'), - ] - */ const flatChunkNames = flat(chunkNames); Object.entries(flatChunkNames).forEach(([key, chunkName]) => { const chunkRegistry = registry[chunkName]; diff --git a/packages/docusaurus/src/client/flat.ts b/packages/docusaurus/src/client/flat.ts index 76b2f57a378c..c015d106955d 100644 --- a/packages/docusaurus/src/client/flat.ts +++ b/packages/docusaurus/src/client/flat.ts @@ -5,18 +5,27 @@ * LICENSE file in the root directory of this source tree. */ -import type {RouteChunksTree} from '@docusaurus/types'; +import type {ChunkNames} from '@docusaurus/types'; -const isTree = (x: string | RouteChunksTree): x is RouteChunksTree => +type Chunk = ChunkNames[string]; +type Tree = Exclude<Chunk, string>; + +const isTree = (x: Chunk): x is Tree => typeof x === 'object' && !!x && Object.keys(x).length > 0; -export default function flat(target: RouteChunksTree): { - [keyPath: string]: string; -} { +/** + * Takes a tree, and flattens it into a map of keyPath -> value. + * + * ```js + * flat({ a: { b: 1 } }) === { "a.b": 1 }; + * flat({ a: [1, 2] }) === { "a.0": 1, "a.1": 2 }; + * ``` + */ +export default function flat(target: ChunkNames): {[keyPath: string]: string} { const delimiter = '.'; const output: {[keyPath: string]: string} = {}; - function step(object: RouteChunksTree, prefix?: string | number) { + function step(object: Tree, prefix?: string | number) { Object.entries(object).forEach(([key, value]) => { const newKey = prefix ? `${prefix}${delimiter}${key}` : key; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index 7870bab42380..a69dd7b18c1a 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -30,7 +30,7 @@ exports[`loadRoutes loads flat route config 1`] = ` }, }, "routesChunkNames": { - "/blog-1e7": { + "/blog-599": { "component": "component---theme-blog-list-pagea-6-a-7ba", "items": [ { @@ -39,29 +39,26 @@ exports[`loadRoutes loads flat route config 1`] = ` }, { "content": "content---blog-7-b-8-fd9", - "metadata": null, }, { "content": "content---blog-7-b-8-fd9", - "metadata": null, }, ], }, }, - "routesConfig": " -import React from 'react'; + "routesConfig": "import React from 'react'; import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/blog', - component: ComponentCreator('/blog','1e7'), + component: ComponentCreator('/blog', '599'), exact: true }, { path: '*', - component: ComponentCreator('*') - } + component: ComponentCreator('*'), + }, ]; ", "routesPaths": [ @@ -119,24 +116,23 @@ exports[`loadRoutes loads nested route config 1`] = ` "metadata": "metadata---docs-foo-baz-2-cf-fa7", }, }, - "routesConfig": " -import React from 'react'; + "routesConfig": "import React from 'react'; import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/docs:route', - component: ComponentCreator('/docs:route','52d'), + component: ComponentCreator('/docs:route', '52d'), routes: [ { path: '/docs/hello', - component: ComponentCreator('/docs/hello','44b'), + component: ComponentCreator('/docs/hello', '44b'), exact: true, sidebar: \\"main\\" }, { path: 'docs/foo/baz', - component: ComponentCreator('docs/foo/baz','070'), + component: ComponentCreator('docs/foo/baz', '070'), sidebar: \\"secondary\\", \\"key:a\\": \\"containing colon\\", \\"key'b\\": \\"containing quote\\", @@ -148,8 +144,8 @@ export default [ }, { path: '*', - component: ComponentCreator('*') - } + component: ComponentCreator('*'), + }, ]; ", "routesPaths": [ @@ -173,19 +169,18 @@ exports[`loadRoutes loads route config with empty (but valid) path string 1`] = "component": "component---hello-world-jse-0-f-b6c", }, }, - "routesConfig": " -import React from 'react'; + "routesConfig": "import React from 'react'; import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '', - component: ComponentCreator('','b2a') + component: ComponentCreator('', 'b2a') }, { path: '*', - component: ComponentCreator('*') - } + component: ComponentCreator('*'), + }, ]; ", "routesPaths": [ diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index acac972d0f19..faf37563fd94 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -6,9 +6,58 @@ */ import {jest} from '@jest/globals'; -import {loadRoutes, handleDuplicateRoutes} from '../routes'; +import {loadRoutes, handleDuplicateRoutes, genChunkName} from '../routes'; import type {RouteConfig} from '@docusaurus/types'; +describe('genChunkName', () => { + it('works', () => { + const firstAssert: {[key: string]: string} = { + '/docs/adding-blog': 'docs-adding-blog-062', + '/docs/versioning': 'docs-versioning-8a8', + '/': 'index', + '/blog/2018/04/30/How-I-Converted-Profilo-To-Docusaurus': + 'blog-2018-04-30-how-i-converted-profilo-to-docusaurus-4f2', + '/youtube': 'youtube-429', + '/users/en/': 'users-en-f7a', + '/blog': 'blog-c06', + }; + Object.keys(firstAssert).forEach((str) => { + expect(genChunkName(str)).toBe(firstAssert[str]); + }); + }); + + it("doesn't allow different chunk name for same path", () => { + expect(genChunkName('path/is/similar', 'oldPrefix')).toEqual( + genChunkName('path/is/similar', 'newPrefix'), + ); + }); + + it('emits different chunk names for different paths even with same preferred name', () => { + const secondAssert: {[key: string]: string} = { + '/blog/1': 'blog-85-f-089', + '/blog/2': 'blog-353-489', + }; + Object.keys(secondAssert).forEach((str) => { + expect(genChunkName(str, undefined, 'blog')).toBe(secondAssert[str]); + }); + }); + + it('only generates short unique IDs', () => { + const thirdAssert: {[key: string]: string} = { + a: '0cc175b9', + b: '92eb5ffe', + c: '4a8a08f0', + d: '8277e091', + }; + Object.keys(thirdAssert).forEach((str) => { + expect(genChunkName(str, undefined, undefined, true)).toBe( + thirdAssert[str], + ); + }); + expect(genChunkName('d', undefined, undefined, true)).toBe('8277e091'); + }); +}); + describe('handleDuplicateRoutes', () => { const routes: RouteConfig[] = [ { @@ -110,14 +159,12 @@ describe('loadRoutes', () => { }, { content: 'blog/2018-12-14-Happy-First-Birthday-Slash.md', - metadata: null, }, { content: { __import: true, path: 'blog/2018-12-14-Happy-First-Birthday-Slash.md', }, - metadata: null, }, ], }, diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 7484ae966669..9a253211ffbe 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -6,7 +6,6 @@ */ import {docuHash, generate} from '@docusaurus/utils'; -import fs from 'fs-extra'; import path from 'path'; import type { LoadContext, @@ -28,7 +27,8 @@ import {applyRouteTrailingSlash, sortConfig} from './routeConfig'; /** * Initializes the plugins, runs `loadContent`, `translateContent`, - * `contentLoaded`, and `translateThemeConfig`. + * `contentLoaded`, and `translateThemeConfig`. Because `contentLoaded` is + * side-effect-ful (it generates temp files), so is this function. */ export async function loadPlugins(context: LoadContext): Promise<{ plugins: LoadedPlugin[]; @@ -99,65 +99,53 @@ export async function loadPlugins(context: LoadContext): Promise<{ if (!plugin.contentLoaded) { return; } - const pluginId = plugin.options.id; - // plugins data files are namespaced by pluginName/pluginId - const dataDirRoot = path.join(context.generatedFilesDir, plugin.name); - const dataDir = path.join(dataDirRoot, pluginId); - - const createData: PluginContentLoadedActions['createData'] = async ( - name, - data, - ) => { - const modulePath = path.join(dataDir, name); - await fs.ensureDir(path.dirname(modulePath)); - await generate(dataDir, name, data); - return modulePath; - }; - + const dataDir = path.join( + context.generatedFilesDir, + plugin.name, + pluginId, + ); // TODO this would be better to do all that in the codegen phase // TODO handle context for nested routes const pluginRouteContext: PluginRouteContext = { plugin: {name: plugin.name, id: pluginId}, data: undefined, // TODO allow plugins to provide context data }; - const pluginRouteContextModulePath = await createData( + const pluginRouteContextModulePath = path.join( + dataDir, `${docuHash('pluginRouteContextModule')}.json`, + ); + await generate( + '/', + pluginRouteContextModulePath, JSON.stringify(pluginRouteContext, null, 2), ); - const addRoute: PluginContentLoadedActions['addRoute'] = ( - initialRouteConfig, - ) => { - // Trailing slash behavior is handled in a generic way for all plugins - const finalRouteConfig = applyRouteTrailingSlash(initialRouteConfig, { - trailingSlash: context.siteConfig.trailingSlash, - baseUrl: context.siteConfig.baseUrl, - }); - pluginsRouteConfigs.push({ - ...finalRouteConfig, - modules: { - ...finalRouteConfig.modules, - __routeContextModule: pluginRouteContextModulePath, - }, - }); - }; - - // the plugins global data are namespaced to avoid data conflicts: - // - by plugin name - // - by plugin id (allow using multiple instances of the same plugin) - const setGlobalData: PluginContentLoadedActions['setGlobalData'] = ( - data, - ) => { - globalData[plugin.name] = globalData[plugin.name] ?? {}; - globalData[plugin.name]![pluginId] = data; - }; - const actions: PluginContentLoadedActions = { - addRoute, - createData, - setGlobalData, + addRoute(initialRouteConfig) { + // Trailing slash behavior is handled generically for all plugins + const finalRouteConfig = applyRouteTrailingSlash( + initialRouteConfig, + context.siteConfig, + ); + pluginsRouteConfigs.push({ + ...finalRouteConfig, + modules: { + ...finalRouteConfig.modules, + __routeContextModule: pluginRouteContextModulePath, + }, + }); + }, + async createData(name, data) { + const modulePath = path.join(dataDir, name); + await generate(dataDir, name, data); + return modulePath; + }, + setGlobalData(data) { + globalData[plugin.name] ??= {}; + globalData[plugin.name]![pluginId] = data; + }, }; const translatedContent = diff --git a/packages/docusaurus/src/server/plugins/routeConfig.ts b/packages/docusaurus/src/server/plugins/routeConfig.ts index 63fad7cd52f6..e5664dd1693f 100644 --- a/packages/docusaurus/src/server/plugins/routeConfig.ts +++ b/packages/docusaurus/src/server/plugins/routeConfig.ts @@ -11,6 +11,7 @@ import { type ApplyTrailingSlashParams, } from '@docusaurus/utils-common'; +/** Recursively applies trailing slash config to all nested routes. */ export function applyRouteTrailingSlash( route: RouteConfig, params: ApplyTrailingSlashParams, diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index 39affe45a31d..48fe2722d4ac 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -6,34 +6,90 @@ */ import { - genChunkName, + docuHash, normalizeUrl, - removeSuffix, simpleHash, escapePath, reportMessage, } from '@docusaurus/utils'; -import {stringify} from 'querystring'; +import _ from 'lodash'; +import query from 'querystring'; import {getAllFinalRoutes} from './utils'; import type { - ChunkRegistry, Module, RouteConfig, - RouteModule, + RouteModules, ChunkNames, + RouteChunkNames, ReportingSeverity, } from '@docusaurus/types'; -type RegistryMap = { - [chunkName: string]: ChunkRegistry; +type LoadedRoutes = { + /** Serialized routes config that can be directly emitted into temp file. */ + routesConfig: string; + /** @see {ChunkNames} */ + routesChunkNames: RouteChunkNames; + /** A map from chunk name to module loaders. */ + registry: { + [chunkName: string]: {loader: string; modulePath: string}; + }; + /** + * Collect all page paths for injecting it later in the plugin lifecycle. + * This is useful for plugins like sitemaps, redirects etc... Only collects + * "actual" pages, i.e. those without subroutes, because if a route has + * subroutes, it is probably a wrapper. + */ + routesPaths: string[]; }; +/** Indents every line of `str` by one level. */ function indent(str: string) { - const spaces = ' '; - return `${spaces}${str.replace(/\n/g, `\n${spaces}`)}`; + return ` ${str.replace(/\n/g, `\n `)}`; } -function createRouteCodeString({ +const chunkNameCache = new Map<string, string>(); + +/** + * Generates a unique chunk name that can be used in the chunk registry. + * + * @param modulePath A path to generate chunk name from. The actual value has no + * semantic significance. + * @param prefix A prefix to append to the chunk name, to avoid name clash. + * @param preferredName Chunk names default to `modulePath`, and this can supply + * a more human-readable name. + * @param shortId When `true`, the chunk name would only be a hash without any + * other characters. Useful for bundle size. Defaults to `true` in production. + */ +export function genChunkName( + modulePath: string, + prefix?: string, + preferredName?: string, + shortId: boolean = process.env.NODE_ENV === 'production', +): string { + let chunkName = chunkNameCache.get(modulePath); + if (!chunkName) { + if (shortId) { + chunkName = simpleHash(modulePath, 8); + } else { + let str = modulePath; + if (preferredName) { + const shortHash = simpleHash(modulePath, 3); + str = `${preferredName}${shortHash}`; + } + const name = str === '/' ? 'index' : docuHash(str); + chunkName = prefix ? `${prefix}---${name}` : name; + } + chunkNameCache.set(modulePath, chunkName); + } + return chunkName; +} + +/** + * Takes a piece of route config, and serializes it into raw JS code. The shape + * is the same as react-router's `RouteConfig`. Formatting is similar to + * `JSON.stringify` but without all the quotes. + */ +function serializeRouteConfig({ routePath, routeHash, exact, @@ -48,7 +104,7 @@ function createRouteCodeString({ }) { const parts = [ `path: '${routePath}'`, - `component: ComponentCreator('${routePath}','${routeHash}')`, + `component: ComponentCreator('${routePath}', '${routeHash}')`, ]; if (exact) { @@ -58,7 +114,7 @@ function createRouteCodeString({ if (subroutesCodeStrings) { parts.push( `routes: [ -${indent(removeSuffix(subroutesCodeStrings.join(',\n'), ',\n'))} +${indent(subroutesCodeStrings.join(',\n'))} ]`, ); } @@ -89,96 +145,67 @@ ${indent(parts.join(',\n'))} }`; } -const NotFoundRouteCode = `{ - path: '*', - component: ComponentCreator('*') -}`; - -const RoutesImportsCode = [ - `import React from 'react';`, - `import ComponentCreator from '@docusaurus/ComponentCreator';`, -].join('\n'); - -function isModule(value: unknown): value is Module { - if (typeof value === 'string') { - return true; - } - if ( - typeof value === 'object' && +const isModule = (value: unknown): value is Module => + typeof value === 'string' || + (typeof value === 'object' && // eslint-disable-next-line no-underscore-dangle - (value as {[key: string]: unknown})?.__import && - (value as {[key: string]: unknown})?.path - ) { - return true; - } - return false; -} + !!(value as {[key: string]: unknown})?.__import); +/** Takes a {@link Module} and returns the string path it represents. */ function getModulePath(target: Module): string { if (typeof target === 'string') { return target; } - const queryStr = target.query ? `?${stringify(target.query)}` : ''; + const queryStr = target.query ? `?${query.stringify(target.query)}` : ''; return `${target.path}${queryStr}`; } -function genRouteChunkNames( - registry: RegistryMap, - value: Module, - prefix?: string, - name?: string, -): string; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule, - prefix?: string, - name?: string, +/** + * Takes a route module (which is a tree of modules), and transforms each module + * into a chunk name. It also mutates `res.registry` and registers the loaders + * for each chunk. + * + * @param routeModule One route module to be transformed. + * @param prefix Prefix passed to {@link genChunkName}. + * @param name Preferred name passed to {@link genChunkName}. + * @param res The route structures being loaded. + */ +function genChunkNames( + routeModule: RouteModules, + prefix: string, + name: string, + res: LoadedRoutes, ): ChunkNames; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule[], - prefix?: string, - name?: string, -): ChunkNames[]; -function genRouteChunkNames( - registry: RegistryMap, - value: RouteModule | RouteModule[] | Module, - prefix?: string, - name?: string, +function genChunkNames( + routeModule: RouteModules | RouteModules[] | Module, + prefix: string, + name: string, + res: LoadedRoutes, ): ChunkNames | ChunkNames[] | string; -function genRouteChunkNames( - // TODO instead of passing a mutating the registry, return a registry slice? - registry: RegistryMap, - value: RouteModule | RouteModule[] | Module | null | undefined, - prefix?: string, - name?: string, -): null | string | ChunkNames | ChunkNames[] { - if (!value) { - return null; - } - - if (Array.isArray(value)) { - return value.map((val, index) => - genRouteChunkNames(registry, val, `${index}`, name), - ); - } - - if (isModule(value)) { - const modulePath = getModulePath(value); +function genChunkNames( + routeModule: RouteModules | RouteModules[] | Module, + prefix: string, + name: string, + res: LoadedRoutes, +): string | ChunkNames | ChunkNames[] { + if (isModule(routeModule)) { + // This is a leaf node, no need to recurse + const modulePath = getModulePath(routeModule); const chunkName = genChunkName(modulePath, prefix, name); - const loader = `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath( + res.registry[chunkName] = { + loader: `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath( + modulePath, + )}')`, modulePath, - )}')`; - - registry[chunkName] = {loader, modulePath}; + }; return chunkName; } - - const newValue: ChunkNames = {}; - Object.entries(value).forEach(([key, v]) => { - newValue[key] = genRouteChunkNames(registry, v, key, name); - }); - return newValue; + if (Array.isArray(routeModule)) { + return routeModule.map((val, index) => + genChunkNames(val, `${index}`, name, res), + ); + } + return _.mapValues(routeModule, (v, key) => genChunkNames(v, key, name, res)); } export function handleDuplicateRoutes( @@ -212,80 +239,82 @@ This could lead to non-deterministic routing behavior.`; } } -export async function loadRoutes( - pluginsRouteConfigs: RouteConfig[], - baseUrl: string, - onDuplicateRoutes: ReportingSeverity, -): Promise<{ - registry: {[chunkName: string]: ChunkRegistry}; - routesConfig: string; - routesChunkNames: {[routePath: string]: ChunkNames}; - routesPaths: string[]; -}> { - handleDuplicateRoutes(pluginsRouteConfigs, onDuplicateRoutes); - const registry: {[chunkName: string]: ChunkRegistry} = {}; - const routesPaths: string[] = [normalizeUrl([baseUrl, '404.html'])]; - const routesChunkNames: {[routePath: string]: ChunkNames} = {}; - - // This is the higher level overview of route code generation. - function generateRouteCode(routeConfig: RouteConfig): string { - const { - path: routePath, - component, - modules = {}, - routes: subroutes, - exact, - priority, - ...props - } = routeConfig; +/** + * This is the higher level overview of route code generation. For each route + * config node, it return the node's serialized form, and mutate `registry`, + * `routesPaths`, and `routesChunkNames` accordingly. + */ +function genRouteCode(routeConfig: RouteConfig, res: LoadedRoutes): string { + const { + path: routePath, + component, + modules = {}, + routes: subroutes, + priority, + exact, + ...props + } = routeConfig; - if (typeof routePath !== 'string' || !component) { - throw new Error( - `Invalid route config: path must be a string and component is required. + if (typeof routePath !== 'string' || !component) { + throw new Error( + `Invalid route config: path must be a string and component is required. ${JSON.stringify(routeConfig)}`, - ); - } + ); + } - // Collect all page paths for injecting it later in the plugin lifecycle - // This is useful for plugins like sitemaps, redirects etc... - // If a route has subroutes, it is not necessarily a valid page path (more - // likely to be a wrapper) - if (!subroutes) { - routesPaths.push(routePath); - } + if (!subroutes) { + res.routesPaths.push(routePath); + } - // We hash the route to generate the key, because 2 routes can conflict with - // each others if they have the same path, ex: parent=/docs, child=/docs - // see https://github.com/facebook/docusaurus/issues/2917 - const routeHash = simpleHash(JSON.stringify(routeConfig), 3); - const chunkNamesKey = `${routePath}-${routeHash}`; - routesChunkNames[chunkNamesKey] = { - ...genRouteChunkNames(registry, {component}, 'component', component), - ...genRouteChunkNames(registry, modules, 'module', routePath), - }; + const routeHash = simpleHash(JSON.stringify(routeConfig), 3); + res.routesChunkNames[`${routePath}-${routeHash}`] = { + ...genChunkNames({component}, 'component', component, res), + ...genChunkNames(modules, 'module', routePath, res), + }; - return createRouteCodeString({ - routePath: routeConfig.path.replace(/'/g, "\\'"), - routeHash, - exact, - subroutesCodeStrings: subroutes?.map(generateRouteCode), - props, - }); - } + return serializeRouteConfig({ + routePath: routePath.replace(/'/g, "\\'"), + routeHash, + subroutesCodeStrings: subroutes?.map((r) => genRouteCode(r, res)), + exact, + props, + }); +} - const routesConfig = ` -${RoutesImportsCode} +/** + * Routes are prepared into three temp files: + * + * - `routesConfig`, the route config passed to react-router. This file is kept + * minimal, because it can't be code-splitted. + * - `routesChunkNames`, a mapping from route paths (hashed) to code-splitted + * chunk names. + * - `registry`, a mapping from chunk names to options for react-loadable. + */ +export async function loadRoutes( + routeConfigs: RouteConfig[], + baseUrl: string, + onDuplicateRoutes: ReportingSeverity, +): Promise<LoadedRoutes> { + handleDuplicateRoutes(routeConfigs, onDuplicateRoutes); + const res: LoadedRoutes = { + // To be written + routesConfig: '', + routesChunkNames: {}, + registry: {}, + routesPaths: [normalizeUrl([baseUrl, '404.html'])], + }; + + res.routesConfig = `import React from 'react'; +import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ -${indent(`${pluginsRouteConfigs.map(generateRouteCode).join(',\n')},`)} -${indent(NotFoundRouteCode)} +${indent(`${routeConfigs.map((r) => genRouteCode(r, res)).join(',\n')},`)} + { + path: '*', + component: ComponentCreator('*'), + }, ]; `; - return { - registry, - routesConfig, - routesChunkNames, - routesPaths, - }; + return res; } diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index 85a80f2ca5de..1a388ed4e4f8 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -14,10 +14,7 @@ import { applyConfigurePostCss, getHttpsConfig, } from '../utils'; -import type { - ConfigureWebpackFn, - ConfigureWebpackFnMergeStrategy, -} from '@docusaurus/types'; +import type {Plugin} from '@docusaurus/types'; describe('customize JS loader', () => { it('getCustomizableJSLoader defaults to babel loader', () => { @@ -63,7 +60,7 @@ describe('extending generated webpack config', () => { }, }; - const configureWebpack: ConfigureWebpackFn = ( + const configureWebpack: Plugin['configureWebpack'] = ( generatedConfig, isServer, ) => { @@ -99,7 +96,7 @@ describe('extending generated webpack config', () => { }, }; - const configureWebpack: ConfigureWebpackFn = () => ({ + const configureWebpack: Plugin['configureWebpack'] = () => ({ entry: 'entry.js', output: { path: path.join(__dirname, 'dist'), @@ -128,9 +125,9 @@ describe('extending generated webpack config', () => { }, }; - const createConfigureWebpack: ( - mergeStrategy?: ConfigureWebpackFnMergeStrategy, - ) => ConfigureWebpackFn = (mergeStrategy) => () => ({ + const createConfigureWebpack: (mergeStrategy?: { + [key: string]: 'prepend' | 'append'; + }) => Plugin['configureWebpack'] = (mergeStrategy) => () => ({ module: { rules: [{use: 'zzz'}], }, diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index f9626b819604..85345c201b0a 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -25,8 +25,7 @@ import crypto from 'crypto'; import logger from '@docusaurus/logger'; import type {TransformOptions} from '@babel/core'; import type { - ConfigureWebpackFn, - ConfigurePostCssFn, + Plugin, PostCssOptions, ConfigureWebpackUtils, } from '@docusaurus/types'; @@ -172,7 +171,7 @@ export const getCustomizableJSLoader = * @returns final/ modified webpack config */ export function applyConfigureWebpack( - configureWebpack: ConfigureWebpackFn, + configureWebpack: NonNullable<Plugin['configureWebpack']>, config: Configuration, isServer: boolean, jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) | undefined, @@ -198,7 +197,7 @@ export function applyConfigureWebpack( } export function applyConfigurePostCss( - configurePostCss: NonNullable<ConfigurePostCssFn>, + configurePostCss: NonNullable<Plugin['configurePostCss']>, config: Configuration, ): Configuration { type LocalPostCSSLoader = unknown & { diff --git a/website/docs/api/plugin-methods/lifecycle-apis.md b/website/docs/api/plugin-methods/lifecycle-apis.md index 3d30cb3ea5ba..e963f401251e 100644 --- a/website/docs/api/plugin-methods/lifecycle-apis.md +++ b/website/docs/api/plugin-methods/lifecycle-apis.md @@ -46,13 +46,13 @@ Create a route to add to the website. interface RouteConfig { path: string; component: string; - modules?: RouteModule; + modules?: RouteModules; routes?: RouteConfig[]; exact?: boolean; priority?: number; } -interface RouteModule { - [module: string]: Module | RouteModule | RouteModule[]; +interface RouteModules { + [module: string]: Module | RouteModules | RouteModules[]; } type Module = | { From 4e45e14fdd760a7eff13f842c81654eba5e872a3 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Tue, 29 Mar 2022 18:02:09 +0800 Subject: [PATCH 100/405] fix(theme-common): use native scrolling when smooth behavior set in CSS (#7057) * fix(theme-common): use native scrolling when smooth behavior set in CSS * fix * fix again * fix again --- .../src/utils/scrollUtils.tsx | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx index 88142d54f221..79799c37fc24 100644 --- a/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/scrollUtils.tsx @@ -16,6 +16,7 @@ import React, { } from 'react'; import {useDynamicCallback, ReactContextError} from './reactUtils'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import useIsBrowser from '@docusaurus/useIsBrowser'; type ScrollController = { /** A boolean ref tracking whether scroll events are enabled. */ @@ -233,14 +234,6 @@ export function useScrollPositionBlocker(): { }; } -// Not all have support for smooth scrolling (particularly Safari mobile iOS) -// TODO proper detection is currently unreliable! -// see https://github.com/wessberg/scroll-behavior-polyfill/issues/16 -const SupportsNativeSmoothScrolling = false; -// const SupportsNativeSmoothScrolling = -// ExecutionEnvironment.canUseDOM && -// 'scrollBehavior' in document.documentElement.style; - type CancelScrollTop = () => void; function smoothScrollNative(top: number): CancelScrollTop { @@ -260,10 +253,7 @@ function smoothScrollPolyfill(top: number): CancelScrollTop { (!isUpScroll && currentScroll < top) ) { raf = requestAnimationFrame(rafRecursion); - window.scrollTo( - 0, - Math.floor(Math.abs(currentScroll - top) * 0.85) + top, - ); + window.scrollTo(0, Math.floor((currentScroll - top) * 0.85) + top); } } rafRecursion(); @@ -275,8 +265,9 @@ function smoothScrollPolyfill(top: number): CancelScrollTop { /** * A "smart polyfill" of `window.scrollTo({ top, behavior: "smooth" })`. - * This currently always uses a polyfilled implementation, because native - * support detection seems unreliable. + * This currently always uses a polyfilled implementation unless + * `scroll-behavior: smooth` has been set in CSS, because native support + * detection for scroll behavior seems unreliable. * * This hook does not do anything by itself: it returns a start and a stop * handle. You can execute either handle at any time. @@ -296,12 +287,22 @@ export function useSmoothScrollTo(): { cancelScroll: CancelScrollTop; } { const cancelRef = useRef<CancelScrollTop | null>(null); + const isBrowser = useIsBrowser(); + // Not all have support for smooth scrolling (particularly Safari mobile iOS) + // TODO proper detection is currently unreliable! + // see https://github.com/wessberg/scroll-behavior-polyfill/issues/16 + // For now, we only use native scroll behavior if smooth is already set, + // because otherwise the polyfill produces a weird UX when both CSS and JS try + // to scroll a page, and they cancel each other. + const supportsNativeSmoothScrolling = + isBrowser && + getComputedStyle(document.documentElement).scrollBehavior === 'smooth'; return { startScroll: (top: number) => { - cancelRef.current = SupportsNativeSmoothScrolling + cancelRef.current = supportsNativeSmoothScrolling ? smoothScrollNative(top) : smoothScrollPolyfill(top); }, - cancelScroll: () => cancelRef?.current, + cancelScroll: () => cancelRef.current?.(), }; } From 177e8d7c02f0c99b0cb812c60e2f7a3384f23fad Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Tue, 29 Mar 2022 19:09:01 +0800 Subject: [PATCH 101/405] docs: add firelordjs to showcase (#7059) * docs: add firelordjs to showcase docs: add firelordjs to showcase fixes kick CI Delete firelordjs.png Add files via upload * kick CI Co-authored-by: Acid Coder <5227509+tylim88@users.noreply.github.com> --- website/src/data/showcase/firelordjs.png | Bin 0 -> 24200 bytes website/src/data/users.tsx | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 website/src/data/showcase/firelordjs.png diff --git a/website/src/data/showcase/firelordjs.png b/website/src/data/showcase/firelordjs.png new file mode 100644 index 0000000000000000000000000000000000000000..4824ddd1a15efb2aad653935c9ab8eaea834f795 GIT binary patch literal 24200 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 oKXSqid{OMGSiXBX2+afF(tJ z4O9{k=%gcBg)3>ZNfa(hTbU1*wJ?*M8mNgYGq~QZWbbM7uPSPmF)yH0c*{w!bm8xp z)Y4AD^v1Hi<dswn<)bGhHB!0n!UKvno{%;o#ppw*bG`Y5N06Fy@aETXY#;!)#zzIM z44kM6ELo`a`la-%ntvff$k-S|>vLaDP1|BPvI)SzV40+7;oxY}EA#VJ^kSe7#r{Jh zFQQ9b&3K49`nly4{yt{GXZDKiB&j}8zN#R@FWa!o=5b`Xp}Wq%1+Cy=hf2geuv<G# z^WP54HG{Kr?=*fnsW$!C+Kj<Zp1@z#g&46h(vC<z<e?*Cgo;9tK$pTmY(9`-8Ik#& zy)nI6YgYBrP8J{i^HUYZA5TsD<_dcgbBwalaPfgiTP4n7CRe9_RzIrLR^LAN5Wa&1 z+;7lXTK>O_h2)(WwoFBY^I2;5zzf_CBm)TCD};4v5<rCGYt>k($Z-qngM{tVSX~Y_ zOWCn2U1?COoxG`BHlvV`^!Sv66gi)KjZ=X?7n*;pUnu!q&rz(4KM#tf+x7Pc_bWH- z{%h2-Z>=}9Ys@6f#ypD6HCA+6P!XLGV<L<h9>dmd9A~sR5V116!&$Crz1zB!i9U>3 z$P1J-A)!B*Qqr23xJ%J0xC5d@!9xCt@;FT@*2?Zr*09N>Y$^-1qSx)x8rsD3V28QS z%7t|ghs_T@vSJM>A%}G)C>6+$<Ew39(%km3v-M`V9Y-wD+)-kbv859O%WzcyAz=`4 zm<{^_{%>dhVt7bCxDn-p&2syw0_r7WE5aLMiYIBY{cG)JQ^2<NDtWkXY}aEuSxdqG zv3Z~QOYEN^F@R2c@PGvFFS+fuXds~iqofl#1ZS3q^<Rj0v5UW^N&T@n<%!8<>UVb} zjR$}H4<IF}SvvnNIeH*q=QL&-CAtYQGKF~wl4z;v⪼ssTP`yv62UFd1cCtz($o( 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 OT3$w3x?0LK`2PT(^br97 literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index d9e1bf63b1ec..13343e4c0e44 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -622,6 +622,14 @@ const Users: User[] = [ source: 'https://github.com/Camberi/firecms/tree/master/website', tags: ['opensource', 'design'], }, + { + title: 'FirelordJS', + description: 'Typescript Wrapper for Firestore', + preview: require('./showcase/firelordjs.png'), + website: 'https://firelordjs.com', + source: 'https://github.com/tylim88/FirelordJSDoc', + tags: ['opensource'], + }, { title: 'Flagsmith', description: 'Open Source Feature Flag and Remote Config Service', From 1f77fc93bba90e1b4db8e4f26ec52c29257ddd86 Mon Sep 17 00:00:00 2001 From: Chau Tran <nartc7789@gmail.com> Date: Tue, 29 Mar 2022 09:52:25 -0500 Subject: [PATCH 102/405] docs: add docusaurus-plugin-typedoc to resources (#7061) --- website/community/2-resources.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/community/2-resources.md b/website/community/2-resources.md index 37176ac4adc1..1490a1b8de40 100644 --- a/website/community/2-resources.md +++ b/website/community/2-resources.md @@ -46,6 +46,7 @@ See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase - [mdx-mermaid](https://github.com/sjwall/mdx-mermaid) - A Docusaurus v2 compatible MDX plugin for displaying [Mermaid](https://mermaid-js.github.io/mermaid) diagrams - [redocusaurus](https://github.com/rohit-gohri/redocusaurus) - A Docusaurus preset for integrating OpenAPI documentation into your docs with [Redoc](https://github.com/redocly/redoc) - [plugin-image-zoom](https://github.com/flexanalytics/plugin-image-zoom) - An Image Zoom plugin for Docusaurus 2 +- [docusaurus-plugin-typedoc](https://github.com/tgreyuk/typedoc-plugin-markdown/tree/master/packages/docusaurus-plugin-typedoc) - A Docusaurus 2 plugin to build documentation with [TypeDoc](https://typedoc.org/) ## Enterprise usage {#enterprise-usage} From 2e79597f83f93abbdeb9434dda2b3bd796882717 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 09:15:54 +0800 Subject: [PATCH 103/405] feat(theme-classic): show blog sidebar on mobile (#7012) * feat(theme-classic): show blog sidebar on mobile * fix * oops * docs * add a little margin * Update display.tsx * Update content.tsx * reformat --- .../src/theme/BlogSidebar/index.tsx | 33 +++- .../src/theme/BlogSidebar/styles.module.css | 6 +- .../src/contexts/navbarMobileSidebar.tsx | 6 +- .../src/contexts/navbarSecondaryMenu.tsx | 170 ------------------ .../contexts/navbarSecondaryMenu/content.tsx | 110 ++++++++++++ .../contexts/navbarSecondaryMenu/display.tsx | 102 +++++++++++ packages/docusaurus-theme-common/src/index.ts | 4 +- .../src/utils/navbarUtils.tsx | 17 +- 8 files changed, 260 insertions(+), 188 deletions(-) delete mode 100644 packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx create mode 100644 packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/content.tsx create mode 100644 packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/display.tsx diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx index 23cb7b4737e7..ad478860fe42 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx @@ -8,17 +8,21 @@ import React from 'react'; import clsx from 'clsx'; import Link from '@docusaurus/Link'; +import {translate} from '@docusaurus/Translate'; +import { + NavbarSecondaryMenuFiller, + useWindowSize, +} from '@docusaurus/theme-common'; import type {Props} from '@theme/BlogSidebar'; import styles from './styles.module.css'; -import {translate} from '@docusaurus/Translate'; -export default function BlogSidebar({sidebar}: Props): JSX.Element | null { - if (sidebar.items.length === 0) { - return null; - } +function BlogSidebarContent({ + sidebar, + className, +}: Props & {className?: string}): JSX.Element { return ( <nav - className={clsx(styles.sidebar, 'thin-scrollbar')} + className={clsx(styles.sidebar, 'thin-scrollbar', className)} aria-label={translate({ id: 'theme.blog.sidebar.navAriaLabel', message: 'Blog recent posts navigation', @@ -43,3 +47,20 @@ export default function BlogSidebar({sidebar}: Props): JSX.Element | null { </nav> ); } + +export default function BlogSidebar(props: Props): JSX.Element | null { + const windowSize = useWindowSize(); + if (props.sidebar.items.length === 0) { + return null; + } + // Mobile sidebar doesn't need to be server-rendered + if (windowSize === 'mobile') { + return ( + <NavbarSecondaryMenuFiller + component={BlogSidebarContent} + props={{...props, className: 'margin-left--md'}} + /> + ); + } + return <BlogSidebarContent {...props} className={styles.sidebarDesktop} />; +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css index 3ca0d4b8d5e7..d3e7700af508 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css @@ -40,7 +40,11 @@ } @media (max-width: 996px) { - .sidebar { + .sidebarDesktop { display: none; } + + .sidebar { + top: 0; + } } diff --git a/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx index 81e04fc391b5..c798605edb6c 100644 --- a/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/navbarMobileSidebar.tsx @@ -12,9 +12,9 @@ import React, { useMemo, type ReactNode, } from 'react'; +import {useNavbarSecondaryMenuContent} from './navbarSecondaryMenu/content'; import {useWindowSize} from '../hooks/useWindowSize'; import {useHistoryPopHandler} from '../utils/historyUtils'; -import {useActivePlugin} from '@docusaurus/plugin-content-docs/client'; import {useThemeConfig} from '../utils/useThemeConfig'; import {ReactContextError} from '../utils/reactUtils'; @@ -40,9 +40,9 @@ type ContextValue = { const Context = React.createContext<ContextValue | undefined>(undefined); function useIsNavbarMobileSidebarDisabled() { - const activeDocPlugin = useActivePlugin(); + const secondaryMenuContent = useNavbarSecondaryMenuContent(); const {items} = useThemeConfig().navbar; - return items.length === 0 && !activeDocPlugin; + return items.length === 0 && !secondaryMenuContent.component; } function useContextValue(): ContextValue { diff --git a/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx deleted file mode 100644 index 1b6f188915f1..000000000000 --- a/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu.tsx +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { - useState, - useContext, - useEffect, - useMemo, - useCallback, - type ReactNode, - type ComponentType, -} from 'react'; -import {ReactContextError, usePrevious} from '../utils/reactUtils'; -import {useNavbarMobileSidebar} from './navbarMobileSidebar'; - -export type NavbarSecondaryMenuComponent<Props> = ComponentType<Props>; - -type State = { - shown: boolean; - content: - | { - component: NavbarSecondaryMenuComponent<object>; - props: object; - } - | {component: null; props: null}; -}; - -const InitialState: State = { - shown: false, - content: {component: null, props: null}, -}; - -type ContextValue = [ - state: State, - setState: React.Dispatch<React.SetStateAction<State>>, -]; - -const Context = React.createContext<ContextValue | null>(null); - -function useContextValue(): ContextValue { - const mobileSidebar = useNavbarMobileSidebar(); - - const [state, setState] = useState<State>(InitialState); - - const setShown = (shown: boolean) => setState((s) => ({...s, shown})); - - const hasContent = state.content?.component !== null; - const previousHasContent = usePrevious(state.content?.component !== null); - - // When content is become available for the first time (set in useEffect) - // we set this content to be shown! - useEffect(() => { - const contentBecameAvailable = hasContent && !previousHasContent; - if (contentBecameAvailable) { - setShown(true); - } - }, [hasContent, previousHasContent]); - - // On sidebar close, secondary menu is set to be shown on next re-opening - // (if any secondary menu content available) - useEffect(() => { - if (!hasContent) { - setShown(false); - return; - } - if (!mobileSidebar.shown) { - setShown(true); - } - }, [mobileSidebar.shown, hasContent]); - - return [state, setState]; -} - -export function NavbarSecondaryMenuProvider({ - children, -}: { - children: ReactNode; -}): JSX.Element { - const value = useContextValue(); - return <Context.Provider value={value}>{children}</Context.Provider>; -} - -function useNavbarSecondaryMenuContext(): ContextValue { - const value = useContext(Context); - if (value === null) { - throw new ReactContextError('MobileSecondaryMenuProvider'); - } - return value; -} - -function useShallowMemoizedObject<O>(obj: O) { - return useMemo( - () => obj, - // Is this safe? - // eslint-disable-next-line react-hooks/exhaustive-deps - [...Object.keys(obj), ...Object.values(obj)], - ); -} - -/** - * This component renders nothing by itself, but it fills the placeholder in the - * generic secondary menu layout. This reduces coupling between the main layout - * and the specific page. - * - * This kind of feature is often called portal/teleport/gateway/outlet... - * Various unmaintained React libs exist. Most up-to-date one: - * https://github.com/gregberge/react-teleporter - * Not sure any of those is safe regarding concurrent mode. - */ -export function NavbarSecondaryMenuFiller<P extends object>({ - component, - props, -}: { - component: NavbarSecondaryMenuComponent<P>; - props: P; -}): JSX.Element | null { - const [, setState] = useNavbarSecondaryMenuContext(); - - // To avoid useless context re-renders, props are memoized shallowly - const memoizedProps = useShallowMemoizedObject(props); - - useEffect(() => { - // @ts-expect-error: context is not 100% type-safe but it's ok - setState((s) => ({...s, content: {component, props: memoizedProps}})); - }, [setState, component, memoizedProps]); - - useEffect( - () => () => setState((s) => ({...s, component: null, props: null})), - [setState], - ); - - return null; -} - -function renderElement(state: State): JSX.Element | undefined { - if (state.content?.component) { - const Comp = state.content.component; - return <Comp {...state.content.props} />; - } - return undefined; -} - -/** Wires the logic for rendering the mobile navbar secondary menu. */ -export function useNavbarSecondaryMenu(): { - /** Whether secondary menu is displayed. */ - shown: boolean; - /** - * Hide the secondary menu; fired either when hiding the entire sidebar, or - * when going back to the primary menu. - */ - hide: () => void; - /** The content returned from the current secondary menu filler. */ - content: JSX.Element | undefined; -} { - const [state, setState] = useNavbarSecondaryMenuContext(); - - const hide = useCallback( - () => setState((s) => ({...s, shown: false})), - [setState], - ); - - return useMemo( - () => ({shown: state.shown, hide, content: renderElement(state)}), - [hide, state], - ); -} diff --git a/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/content.tsx b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/content.tsx new file mode 100644 index 000000000000..1183362b2349 --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/content.tsx @@ -0,0 +1,110 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + useState, + useContext, + useEffect, + useMemo, + type ReactNode, + type ComponentType, +} from 'react'; +import {ReactContextError} from '../../utils/reactUtils'; + +// This context represents a "global layout store". A component (usually a +// layout component) can request filling this store through +// `NavbarSecondaryMenuFiller`. It doesn't actually control rendering by itself, +// and this context should be considered internal implementation. The user- +// facing value comes from `display.tsx`, which takes the `component` and +// `props` stored here and renders the actual element. + +export type NavbarSecondaryMenuComponent<Props> = ComponentType<Props>; + +/** @internal */ +export type Content = + | { + component: NavbarSecondaryMenuComponent<object>; + props: object; + } + | {component: null; props: null}; + +type ContextValue = [ + content: Content, + setContent: React.Dispatch<React.SetStateAction<Content>>, +]; + +const Context = React.createContext<ContextValue | null>(null); + +/** @internal */ +export function NavbarSecondaryMenuContentProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const value = useState({component: null, props: null}); + return ( + // @ts-expect-error: this context is hard to type + <Context.Provider value={value}>{children}</Context.Provider> + ); +} + +/** @internal */ +export function useNavbarSecondaryMenuContent(): Content { + const value = useContext(Context); + if (!value) { + throw new ReactContextError('NavbarSecondaryMenuContentProvider'); + } + return value[0]; +} + +function useShallowMemoizedObject<O>(obj: O) { + return useMemo( + () => obj, + // Is this safe? + // eslint-disable-next-line react-hooks/exhaustive-deps + [...Object.keys(obj), ...Object.values(obj)], + ); +} + +/** + * This component renders nothing by itself, but it fills the placeholder in the + * generic secondary menu layout. This reduces coupling between the main layout + * and the specific page. + * + * This kind of feature is often called portal/teleport/gateway/outlet... + * Various unmaintained React libs exist. Most up-to-date one: + * https://github.com/gregberge/react-teleporter + * Not sure any of those is safe regarding concurrent mode. + */ +export function NavbarSecondaryMenuFiller<P extends object>({ + component, + props, +}: { + component: NavbarSecondaryMenuComponent<P>; + props: P; +}): JSX.Element | null { + const context = useContext(Context); + if (!context) { + throw new ReactContextError('NavbarSecondaryMenuContentProvider'); + } + const [, setContent] = context; + + // To avoid useless context re-renders, props are memoized shallowly + const memoizedProps = useShallowMemoizedObject(props); + + useEffect(() => { + // @ts-expect-error: this context is hard to type + setContent({component, props: memoizedProps}); + }, [setContent, component, memoizedProps]); + + useEffect( + () => () => setContent({component: null, props: null}), + [setContent], + ); + + return null; +} diff --git a/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/display.tsx b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/display.tsx new file mode 100644 index 000000000000..06d39f93b4da --- /dev/null +++ b/packages/docusaurus-theme-common/src/contexts/navbarSecondaryMenu/display.tsx @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + useState, + useContext, + useEffect, + useMemo, + useCallback, + type ReactNode, +} from 'react'; +import {ReactContextError, usePrevious} from '../../utils/reactUtils'; +import {useNavbarMobileSidebar} from '../navbarMobileSidebar'; +import {useNavbarSecondaryMenuContent, type Content} from './content'; + +type ContextValue = [ + shown: boolean, + setShown: React.Dispatch<React.SetStateAction<boolean>>, +]; + +const Context = React.createContext<ContextValue | null>(null); + +function useContextValue(): ContextValue { + const mobileSidebar = useNavbarMobileSidebar(); + const content = useNavbarSecondaryMenuContent(); + + const [shown, setShown] = useState(false); + + const hasContent = content.component !== null; + const previousHasContent = usePrevious(hasContent); + + // When content is become available for the first time (set in useEffect) + // we set this content to be shown! + useEffect(() => { + const contentBecameAvailable = hasContent && !previousHasContent; + if (contentBecameAvailable) { + setShown(true); + } + }, [hasContent, previousHasContent]); + + // On sidebar close, secondary menu is set to be shown on next re-opening + // (if any secondary menu content available) + useEffect(() => { + if (!hasContent) { + setShown(false); + return; + } + if (!mobileSidebar.shown) { + setShown(true); + } + }, [mobileSidebar.shown, hasContent]); + + return useMemo(() => [shown, setShown], [shown]); +} + +/** @internal */ +export function NavbarSecondaryMenuDisplayProvider({ + children, +}: { + children: ReactNode; +}): JSX.Element { + const value = useContextValue(); + return <Context.Provider value={value}>{children}</Context.Provider>; +} + +function renderElement(content: Content): JSX.Element | undefined { + if (content.component) { + const Comp = content.component; + return <Comp {...content.props} />; + } + return undefined; +} + +/** Wires the logic for rendering the mobile navbar secondary menu. */ +export function useNavbarSecondaryMenu(): { + /** Whether secondary menu is displayed. */ + shown: boolean; + /** + * Hide the secondary menu; fired either when hiding the entire sidebar, or + * when going back to the primary menu. + */ + hide: () => void; + /** The content returned from the current secondary menu filler. */ + content: JSX.Element | undefined; +} { + const value = useContext(Context); + if (!value) { + throw new ReactContextError('NavbarSecondaryMenuDisplayProvider'); + } + const [shown, setShown] = value; + const hide = useCallback(() => setShown(false), [setShown]); + const content = useNavbarSecondaryMenuContent(); + + return useMemo( + () => ({shown, hide, content: renderElement(content)}), + [hide, content, shown], + ); +} diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 82b95d849577..18820aa13fc9 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -141,10 +141,10 @@ export { export {useNavbarMobileSidebar} from './contexts/navbarMobileSidebar'; export { - useNavbarSecondaryMenu, NavbarSecondaryMenuFiller, type NavbarSecondaryMenuComponent, -} from './contexts/navbarSecondaryMenu'; +} from './contexts/navbarSecondaryMenu/content'; +export {useNavbarSecondaryMenu} from './contexts/navbarSecondaryMenu/display'; export {useBackToTopButton} from './hooks/useBackToTopButton'; export {useHideableNavbar} from './hooks/useHideableNavbar'; diff --git a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx index cb93708d3fb5..bd64eac04880 100644 --- a/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/navbarUtils.tsx @@ -7,7 +7,8 @@ import React, {type ReactNode} from 'react'; import {NavbarMobileSidebarProvider} from '../contexts/navbarMobileSidebar'; -import {NavbarSecondaryMenuProvider} from '../contexts/navbarSecondaryMenu'; +import {NavbarSecondaryMenuContentProvider} from '../contexts/navbarSecondaryMenu/content'; +import {NavbarSecondaryMenuDisplayProvider} from '../contexts/navbarSecondaryMenu/display'; const DefaultNavItemPosition = 'right'; @@ -28,13 +29,17 @@ export function splitNavbarItems<T extends {position?: 'left' | 'right'}>( } /** - * Composes the `NavbarMobileSidebarProvider` and `NavbarSecondaryMenuProvider`. - * Because the latter depends on the former, they can't be re-ordered. + * Composes multiple navbar state providers that are mutually dependent and + * hence can't be re-ordered. */ export function NavbarProvider({children}: {children: ReactNode}): JSX.Element { return ( - <NavbarMobileSidebarProvider> - <NavbarSecondaryMenuProvider>{children}</NavbarSecondaryMenuProvider> - </NavbarMobileSidebarProvider> + <NavbarSecondaryMenuContentProvider> + <NavbarMobileSidebarProvider> + <NavbarSecondaryMenuDisplayProvider> + {children} + </NavbarSecondaryMenuDisplayProvider> + </NavbarMobileSidebarProvider> + </NavbarSecondaryMenuContentProvider> ); } From 3f33e90704223638c7fbfb93e3553e4fbdd66f93 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 11:05:50 +0800 Subject: [PATCH 104/405] chore: upgrade dependencies (#7065) * chore: upgrade dependencies * fix project words --- admin/new.docusaurus.io/package.json | 2 +- package.json | 20 +- packages/create-docusaurus/package.json | 2 +- .../templates/facebook/package.json | 8 +- .../docusaurus-cssnano-preset/package.json | 2 +- packages/docusaurus-mdx-loader/package.json | 8 +- packages/docusaurus-migrate/package.json | 4 +- .../src/index.d.ts | 4 +- .../package.json | 6 +- .../docusaurus-theme-classic/package.json | 2 +- .../src/index.ts | 3 +- packages/docusaurus-types/src/index.d.ts | 8 +- packages/docusaurus/src/server/index.ts | 2 +- .../src/server/translations/translations.ts | 10 +- .../translations/translationsExtractor.ts | 5 +- .../docusaurus/src/webpack/aliases/index.ts | 6 +- packages/stylelint-copyright/package.json | 2 +- project-words.txt | 3 +- website/package.json | 4 +- yarn.lock | 526 +++++++++--------- 20 files changed, 314 insertions(+), 313 deletions(-) diff --git a/admin/new.docusaurus.io/package.json b/admin/new.docusaurus.io/package.json index b756cdbeea9e..923af87d97ab 100644 --- a/admin/new.docusaurus.io/package.json +++ b/admin/new.docusaurus.io/package.json @@ -9,6 +9,6 @@ "@netlify/functions": "^1.0.0" }, "devDependencies": { - "netlify-cli": "^9.13.4" + "netlify-cli": "^9.13.6" } } diff --git a/package.json b/package.json index 25f827aa4247..6c2fe7139a60 100644 --- a/package.json +++ b/package.json @@ -64,12 +64,12 @@ "@babel/core": "^7.17.8", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", - "@swc/core": "^1.2.160", + "@swc/core": "^1.2.161", "@swc/jest": "^0.2.20", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", - "@types/lodash": "^4.14.180", + "@types/lodash": "^4.14.181", "@types/node": "^17.0.23", "@types/prompts": "^2.0.14", "@types/react": "^17.0.43", @@ -77,12 +77,12 @@ "@types/react-test-renderer": "^17.0.1", "@types/semver": "^7.3.9", "@types/shelljs": "^0.8.11", - "@typescript-eslint/eslint-plugin": "^5.16.0", - "@typescript-eslint/parser": "^5.16.0", + "@typescript-eslint/eslint-plugin": "^5.17.0", + "@typescript-eslint/parser": "^5.17.0", "concurrently": "^7.0.0", "cross-env": "^7.0.3", "cspell": "^5.19.3", - "eslint": "^8.11.0", + "eslint": "^8.12.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", @@ -90,7 +90,7 @@ "eslint-plugin-jest": "^26.1.3", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", - "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-react-hooks": "^4.4.0", "eslint-plugin-regexp": "^1.6.0", "husky": "^7.0.4", "image-size": "^1.0.1", @@ -99,19 +99,19 @@ "lerna": "^4.0.0", "lerna-changelog": "^2.2.0", "lint-staged": "^12.3.7", - "netlify-cli": "^9.13.4", + "netlify-cli": "^9.13.6", "nodemon": "^2.0.15", - "prettier": "^2.6.0", + "prettier": "^2.6.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-test-renderer": "^17.0.2", "remark-parse": "^8.0.2", "rimraf": "^3.0.2", "sharp": "^0.30.3", - "stylelint": "^14.6.0", + "stylelint": "^14.6.1", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard": "^25.0.0", "typescript": "^4.6.3", - "unified": "^9.2.1" + "unified": "^9.2.2" } } diff --git a/packages/create-docusaurus/package.json b/packages/create-docusaurus/package.json index e9d943f4b5c3..f13a742a866e 100755 --- a/packages/create-docusaurus/package.json +++ b/packages/create-docusaurus/package.json @@ -29,7 +29,7 @@ "prompts": "^2.4.2", "semver": "^7.3.5", "shelljs": "^0.8.5", - "supports-color": "^9.2.1", + "supports-color": "^9.2.2", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/packages/create-docusaurus/templates/facebook/package.json b/packages/create-docusaurus/templates/facebook/package.json index 38bd9866b0af..9abb5de9bc36 100644 --- a/packages/create-docusaurus/templates/facebook/package.json +++ b/packages/create-docusaurus/templates/facebook/package.json @@ -27,16 +27,16 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.17.0", - "eslint": "^8.11.0", + "eslint": "^8.12.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", - "eslint-plugin-react-hooks": "^4.3.0", - "prettier": "^2.6.0", - "stylelint": "^14.6.0" + "eslint-plugin-react-hooks": "^4.4.0", + "prettier": "^2.6.1", + "stylelint": "^14.6.1" }, "browserslist": { "production": [ diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index 43d2f19522ff..4b9948e77d90 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -18,6 +18,6 @@ "postcss-sort-media-queries": "^4.2.1" }, "devDependencies": { - "to-vfile": "^6.0.0" + "to-vfile": "^6.1.0" } } diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 1215aed4270e..366bdf8cf5c7 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -28,10 +28,10 @@ "fs-extra": "^10.0.1", "image-size": "^1.0.1", "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", + "remark-emoji": "^2.2.0", "stringify-object": "^3.3.0", "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "unist-util-visit": "^2.0.3", "url-loader": "^4.1.1", "webpack": "^5.70.0" }, @@ -41,9 +41,9 @@ "@types/mdast": "^3.0.10", "@types/stringify-object": "^3.3.1", "@types/unist": "^2.0.6", - "remark": "^12.0.0", + "remark": "^12.0.1", "remark-mdx": "^1.6.21", - "to-vfile": "^6.0.0", + "to-vfile": "^6.1.0", "unist-builder": "^2.0.3", "unist-util-remove-position": "^3.0.0" }, diff --git a/packages/docusaurus-migrate/package.json b/packages/docusaurus-migrate/package.json index 01457dd55b72..3dd093f1394f 100644 --- a/packages/docusaurus-migrate/package.json +++ b/packages/docusaurus-migrate/package.json @@ -38,8 +38,8 @@ "remark-stringify": "^8.1.0", "semver": "^7.3.5", "tslib": "^2.3.1", - "unified": "^9.2.1", - "unist-util-visit": "^2.0.2" + "unified": "^9.2.2", + "unist-util-visit": "^2.0.3" }, "devDependencies": { "@types/color": "^3.0.3", diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index e8a8655a1e79..0e4b69c68759 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -65,7 +65,9 @@ declare module '@generated/i18n' { } declare module '@generated/codeTranslations' { - const codeTranslations: {[msgId: string]: string}; + import type {CodeTranslations} from '@docusaurus/types'; + + const codeTranslations: CodeTranslations; export = codeTranslations; } diff --git a/packages/docusaurus-remark-plugin-npm2yarn/package.json b/packages/docusaurus-remark-plugin-npm2yarn/package.json index 3c0468b12340..30f3d7909d0b 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/package.json +++ b/packages/docusaurus-remark-plugin-npm2yarn/package.json @@ -19,13 +19,13 @@ "dependencies": { "npm-to-yarn": "^1.0.1", "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2" + "unist-util-visit": "^2.0.3" }, "devDependencies": { "@types/mdast": "^3.0.10", - "remark": "^12.0.0", + "remark": "^12.0.1", "remark-mdx": "^1.6.21", - "to-vfile": "^6.0.0" + "to-vfile": "^6.1.0" }, "engines": { "node": ">=14" diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 6820614d1571..9536af7b3b17 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -46,7 +46,7 @@ "@docusaurus/types": "2.0.0-beta.18", "@types/mdx-js__react": "^1.5.5", "@types/prismjs": "^1.26.0", - "@types/rtlcss": "^3.1.2", + "@types/rtlcss": "^3.1.3", "cross-env": "^7.0.3", "fs-extra": "^10.0.1", "react-test-renderer": "^17.0.2", diff --git a/packages/docusaurus-theme-translations/src/index.ts b/packages/docusaurus-theme-translations/src/index.ts index f586fe0d9ffd..743ac3a6087f 100644 --- a/packages/docusaurus-theme-translations/src/index.ts +++ b/packages/docusaurus-theme-translations/src/index.ts @@ -7,6 +7,7 @@ import path from 'path'; import fs from 'fs-extra'; +import type {CodeTranslations} from '@docusaurus/types'; function getDefaultLocalesDirPath(): string { return path.join(__dirname, '../locales'); @@ -39,7 +40,7 @@ export async function readDefaultCodeTranslationMessages({ dirPath?: string; locale: string; name: string; -}): Promise<{[msgId: string]: string}> { +}): Promise<CodeTranslations> { const localesToTry = codeTranslationLocalesToTry(locale); // Return the content of the first file that match diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 2c33f1599a3e..58969aa81136 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -149,7 +149,7 @@ export type SiteMetadata = { * @see https://help.phrase.com/help/chrome-json-messages */ export type TranslationMessage = {message: string; description?: string}; -export type TranslationFileContent = {[key: string]: TranslationMessage}; +export type TranslationFileContent = {[msgId: string]: TranslationMessage}; /** * An abstract representation of how a translation file exists on disk. The core * would handle the file reading/writing; plugins just need to deal with @@ -169,12 +169,14 @@ export type I18n = DeepRequired<I18nConfig> & {currentLocale: string}; export type GlobalData = {[pluginName: string]: {[pluginId: string]: unknown}}; +export type CodeTranslations = {[msgId: string]: string}; + export type DocusaurusContext = { siteConfig: DocusaurusConfig; siteMetadata: SiteMetadata; globalData: GlobalData; i18n: I18n; - codeTranslations: {[msgId: string]: string}; + codeTranslations: CodeTranslations; // Don't put mutable values here, to avoid triggering re-renders // We could reconsider that choice if context selectors are implemented @@ -226,7 +228,7 @@ export type LoadContext = { baseUrl: string; i18n: I18n; ssrTemplate: string; - codeTranslations: {[msgId: string]: string}; + codeTranslations: CodeTranslations; }; export type Props = LoadContext & { diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index bfdfc4f3c6d8..282bee4c366f 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -137,7 +137,7 @@ export async function load(options: LoadContextOptions): Promise<Props> { baseUrl, siteConfig.onDuplicateRoutes, ); - const codeTranslations: {[msgId: string]: string} = { + const codeTranslations = { ...(await getPluginsDefaultCodeTranslationMessages(plugins)), ...siteCodeTranslations, }; diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index ae89e0308e20..4d0bcb24740f 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -19,7 +19,7 @@ import logger from '@docusaurus/logger'; import type { TranslationFileContent, TranslationFile, - TranslationMessage, + CodeTranslations, InitializedPlugin, } from '@docusaurus/types'; @@ -262,7 +262,7 @@ export async function localizePluginTranslationFile({ export async function getPluginsDefaultCodeTranslationMessages( plugins: InitializedPlugin[], -): Promise<{[msgId: string]: string}> { +): Promise<CodeTranslations> { const pluginsMessages = await Promise.all( plugins.map((plugin) => plugin.getDefaultCodeTranslationMessages?.() ?? {}), ); @@ -277,9 +277,9 @@ export function applyDefaultCodeTranslations({ extractedCodeTranslations, defaultCodeMessages, }: { - extractedCodeTranslations: {[msgId: string]: TranslationMessage}; - defaultCodeMessages: {[msgId: string]: string}; -}): {[msgId: string]: TranslationMessage} { + extractedCodeTranslations: TranslationFileContent; + defaultCodeMessages: CodeTranslations; +}): TranslationFileContent { const unusedDefaultCodeMessages = _.difference( Object.keys(defaultCodeMessages), Object.keys(extractedCodeTranslations), diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index 3be8f1f13b34..73a1a0cbfe7c 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -18,7 +18,6 @@ import { import type { InitializedPlugin, TranslationFileContent, - TranslationMessage, } from '@docusaurus/types'; import nodePath from 'path'; import {SRC_DIR_NAME} from '@docusaurus/utils'; @@ -130,7 +129,7 @@ function logSourceCodeFileTranslationsWarnings( type SourceCodeFileTranslations = { sourceCodeFilePath: string; - translations: {[msgId: string]: TranslationMessage}; + translations: TranslationFileContent; warnings: string[]; }; @@ -189,7 +188,7 @@ function extractSourceCodeAstTranslations( Full code: ${generate(node).code}`; } - const translations: {[msgId: string]: TranslationMessage} = {}; + const translations: TranslationFileContent = {}; const warnings: string[] = []; let translateComponentName: string | undefined; let translateFunctionName: string | undefined; diff --git a/packages/docusaurus/src/webpack/aliases/index.ts b/packages/docusaurus/src/webpack/aliases/index.ts index 4f7e67a34ec8..984876571c29 100644 --- a/packages/docusaurus/src/webpack/aliases/index.ts +++ b/packages/docusaurus/src/webpack/aliases/index.ts @@ -126,13 +126,11 @@ export function loadThemeAliases({ * instead of naively aliasing this to `client/exports`, we use fine-grained * aliases instead. */ -export async function loadDocusaurusAliases(): Promise<{ - [aliasName: string]: string; -}> { +export async function loadDocusaurusAliases(): Promise<ThemeAliases> { const dirPath = path.resolve(__dirname, '../../client/exports'); const extensions = ['.js', '.ts', '.tsx']; - const aliases: {[key: string]: string} = {}; + const aliases: ThemeAliases = {}; (await fs.readdir(dirPath)) .filter((fileName) => extensions.includes(path.extname(fileName))) diff --git a/packages/stylelint-copyright/package.json b/packages/stylelint-copyright/package.json index f5a24cd77cda..8c669225c399 100644 --- a/packages/stylelint-copyright/package.json +++ b/packages/stylelint-copyright/package.json @@ -10,6 +10,6 @@ "directory": "packages/stylelint-copyright" }, "dependencies": { - "stylelint": "^14.6.0" + "stylelint": "^14.6.1" } } diff --git a/project-words.txt b/project-words.txt index ce93c4352c27..1c730dc2c574 100644 --- a/project-words.txt +++ b/project-words.txt @@ -150,9 +150,9 @@ marocchino massoud mathjax mdast +mdxa mdxast mdxhast -MDXA metadatum metastring middlewares @@ -301,6 +301,7 @@ treosh triaging typecheck typechecks +typedoc typesense unflat unist diff --git a/website/package.json b/website/package.json index 2ee13f7bb689..cfbed1d06b70 100644 --- a/website/package.json +++ b/website/package.json @@ -49,7 +49,7 @@ "@docusaurus/utils": "2.0.0-beta.18", "@docusaurus/utils-common": "2.0.0-beta.18", "@popperjs/core": "^2.11.4", - "@swc/core": "^1.2.160", + "@swc/core": "^1.2.161", "clsx": "^1.1.1", "color": "^4.2.1", "fs-extra": "^10.0.1", @@ -62,7 +62,7 @@ "rehype-katex": "^6.0.2", "remark-math": "^3.0.1", "swc-loader": "^0.1.15", - "unist-util-visit": "^2.0.2", + "unist-util-visit": "^2.0.3", "workbox-routing": "^6.5.2", "workbox-strategies": "^6.5.2" }, diff --git a/yarn.lock b/yarn.lock index 3201f262349f..5974ee3c406f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2594,14 +2594,14 @@ stringify-object "^3.3.0" "@mapbox/node-pre-gyp@^1.0.5": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58" - integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg== + version "1.0.9" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== dependencies: - detect-libc "^1.0.3" + detect-libc "^2.0.0" https-proxy-agent "^5.0.0" make-dir "^3.1.0" - node-fetch "^2.6.5" + node-fetch "^2.6.7" nopt "^5.0.0" npmlog "^5.0.1" rimraf "^3.0.2" @@ -2651,7 +2651,7 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@netlify/build@^26.5.0": +"@netlify/build@^26.5.1": version "26.5.1" resolved "https://registry.yarnpkg.com/@netlify/build/-/build-26.5.1.tgz#cce2d91740af7a46d022dd8dd5ee693bb811c45b" integrity sha512-sqS/7zyJwp48f1nsKJ9XaZF8FSoJpdCp1EH2g5777rc0hGyYC1AFX0NaJnT3weN47VjsLkaxcfHBUvwo6lyEJw== @@ -2725,7 +2725,7 @@ path-exists "^5.0.0" readdirp "^3.4.0" -"@netlify/config@^17.0.0", "@netlify/config@^17.0.18": +"@netlify/config@^17.0.0", "@netlify/config@^17.0.19": version "17.0.19" resolved "https://registry.yarnpkg.com/@netlify/config/-/config-17.0.19.tgz#f1d7a1bc8d005ad188c2f58d6064bfaaf36d057c" integrity sha512-GH2fKuqmNt+syuQrWIejB0FqkPZWo1/M1AmiZbcYMHh9oQFnBKo+OixD0BPl66HFKd4/rPKqqwaSg/xZ3Y9mKg== @@ -2906,9 +2906,9 @@ rollup-plugin-terser "^7.0.2" "@netlify/plugins-list@^6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.17.0.tgz#fd6ff86a81de0f2b4bc14ec2f0f5f9431ec54bd6" - integrity sha512-XQMijnVOxbZwkOeSzUZ8Hwon8WIv9uka5R6+mjJs25lcFiTscA8HqHWjhSHf2xPSrcKopJm4BNJZja5YHV3NQg== + version "6.18.0" + resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.18.0.tgz#5338079577db61c9b35d726201ee6723fb9e93f5" + integrity sha512-aDcWLHPVqAOwtS5e/kj2jqWLVdKQrHPc7Wj6nxH6aiTuzp85ELRXW4rPEWrvibio5lbeYaNBhCTw/sHKUVYIcg== "@netlify/routing-local-proxy-darwin-arm64@^0.34.1": version "0.34.1" @@ -3220,9 +3220,9 @@ "@rollup/pluginutils" "^3.1.0" "@rollup/plugin-commonjs@^21.0.0": - version "21.0.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz#0b9c539aa1837c94abfaf87945838b0fc8564891" - integrity sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.3.tgz#287896c64926ef3d7f0013708dcdcc1223576ef0" + integrity sha512-ThGfwyvcLc6cfP/MWxA5ACF+LZCvsuhUq7V5134Az1oQWsiC7lNpLT4mJI86WQunK7BYmpUiHmMk2Op6OAHs0g== dependencies: "@rollup/pluginutils" "^3.1.0" commondir "^1.0.1" @@ -3486,89 +3486,89 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" -"@swc/core-android-arm-eabi@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.160.tgz#f5aaf852e9d104b4ad58d34851bac3bd41a64a60" - integrity sha512-VzFP7tYgvpkUhd8wgyNtERqvoPBBDretyMFxAxPe2SxClaBs9Ka95PdiPPZalRq+vFCb/dFxD8Vhz+XO16Kpjg== - -"@swc/core-android-arm64@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.160.tgz#458f7e6aff52958e0764c34500528c18bbb31894" - integrity sha512-m+xqQaa7TqW3Vm9MUvITtdU8OlAc/9yT+TgOS4l8WlfFI87IDnLLfinKKEp+xfKwzYDdIsh+sC+jdGdIBTMB+Q== - -"@swc/core-darwin-arm64@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.160.tgz#34d48b449de0eae9fddd71b064d36aa5353f22cc" - integrity sha512-9bG70KYKvjNf7tZtjOu1h4kDZPtoidZptIXPGSHuUgJ1BbSJYpfRR5xAmq4k37+GqOjIPJp4+lSGQPa2HfejpA== - -"@swc/core-darwin-x64@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.160.tgz#109d92457df928717c73055f01c99ca88815000d" - integrity sha512-+b4HdKAVf/XPZ9DjgG2axGLbquPEuYwEP3zeWgbWn0s0FYQ7WTFxznf3YrTJE9MYadJeCOs3U80E2xVAtRRS9Q== - -"@swc/core-freebsd-x64@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.160.tgz#debdccce0129aa856e496f06981cc8e8271fcb41" - integrity sha512-E5agJwv+RVMoZ8FQIPSO5wLPDQx6jqcMpV207EB3pPaxPWGe4n3DH3vcibHp80RACDNdiaqo5lBeBnGJI4ithw== - -"@swc/core-linux-arm-gnueabihf@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.160.tgz#27669f1084c152153c017fc320b6a92cd6b71244" - integrity sha512-uCttZRNx+lWVhCYGC6/pGUej08g1SQc5am6R9NVFh111goytcdlPnC4jV8oWzq2QhDWkkKxLoP2CZOytzI4+0w== - -"@swc/core-linux-arm64-gnu@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.160.tgz#a8ecadee30639c298e9c2175099d55c1c82f912e" - integrity sha512-sB18roiv8m/zsY6tXLSrbUls0eKkSkxOEF0ennXVEtz97rMJ+WWnkOc8gI+rUpj3MHbVAIxyDNyyZU4cH5g1jQ== - -"@swc/core-linux-arm64-musl@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.160.tgz#1a2cf738c8a394fcb21fe91f13b1fb9c775cca0b" - integrity sha512-PJ7Ukb+BRR3pGYcUag8qRWOB11eByc5YLx/xAMSc3bRmaYW/oj6s8k+1DYiR//BAuNQdf14MpMFzDuWiDEUh7A== - -"@swc/core-linux-x64-gnu@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.160.tgz#f54c4e0510b69d68f56e681050b717991627ad68" - integrity sha512-wVh8Q86xz3t0y5zoUryWQ64bFG/YxdcykBgaog8lU9xkFb1KSqVRE9ia7aKA12/ZtAfpJZLRBleZxBAcaCg9FQ== - -"@swc/core-linux-x64-musl@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.160.tgz#6f8ec092d8b65a9750faf0a2323b52f39c5bd540" - integrity sha512-AnWdarl9WWuDdbc2AX1w76W1jaekSCokxRrWdSGUgQytaZRtybKZEgThvJCQDrSlYQD4XDOhhVRCurTvy4JsfQ== - -"@swc/core-win32-arm64-msvc@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.160.tgz#b4f226ab86e550762b5cc83d0ebe4cf43f1a3624" - integrity sha512-ScL27mZRTwEIqBIv9RY34nQvyBvhosiM5Lus4dCFmS71flPcAEv7hJgy4GE3YUQV0ryGNK9NaO43H8sAyNwKVQ== - -"@swc/core-win32-ia32-msvc@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.160.tgz#243bb5b15eab76f4c8f004381d63c6d72a8cef68" - integrity sha512-e75zbWlhlyrd5HdrYzELa6OlZxgyaVpJj+c9xMD95HcdklVbmsyt1vuqRxMyqaZUDLyehwwCDRX/ZeDme//M/A== - -"@swc/core-win32-x64-msvc@1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.160.tgz#8708986433e891687bb4a836a683f90bc95e1fce" - integrity sha512-GAYT+WzYQY4sr17S21yJh4flJp/sQ62mAs6RfN89p7jIWgm0Bl/SooRl6ocsftTlnZm7K7QC8zmQVeNCWDCLPw== - -"@swc/core@^1.2.160": - version "1.2.160" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.160.tgz#d91730a5021d4c8aef87855dde11fc8931496176" - integrity sha512-nXoC7HA+aY7AtBPsiqGXocoRLAzzA7MV+InWQtILN7Uru4hB9+rLnLCPc3zSdg7pgnxJLa1tHup1Rz7Vv6TcIQ== +"@swc/core-android-arm-eabi@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.161.tgz#3a723984a51705a6360fefc7c7efb5a7681c8f3f" + integrity sha512-SYm08FusdMo70JaKEYE7GpJHVp020iqPL3FjYEmQ+iyhc0Id8RlMeFt7ZtIj0aYHPKudR3GljzG5FVJXmm1Iuw== + +"@swc/core-android-arm64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.161.tgz#4d9e1b2d6a42ee767fda8ee7d46f059ab001ff0b" + integrity sha512-zk+GgVGKwIO9PsUcLZ7tG1XGGBJ/xyv5Or9/R0rQArBTGS5mvSK4d+9XrItQph8i3ECZhik3PuexmR7us6ysCw== + +"@swc/core-darwin-arm64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.161.tgz#bdef41c63d905a1da094c6756f09ca3ff19644d1" + integrity sha512-pf65TWy9oFkWCRzRq16Ec6rglurdajWT5tv1E93Kh4izEFLvKN/Mp+8EMnqOcoAn+HEtjzp2R6NosBruV/d1Ww== + +"@swc/core-darwin-x64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.161.tgz#96980fb8c3207f8305457864241c4a942b4d9903" + integrity sha512-QdgsY+BjYO0ngSIwR/xZn6W3iP0E/+of38Afon3maANDiKzvzsvyZm4IVTznOaxG1ZUJ/q1oKeRV/DcW7QvHiw== + +"@swc/core-freebsd-x64@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.161.tgz#8b41d589a04c1236ab0d6163cca548574925cae4" + integrity sha512-yApHncnlQNQINxxcz+Y+svlrdU3d/yaJ769eoThIQXsZTL0Il3gnhhkjJkMEigLTexpQZQOGjgYnV9HKkpYqkw== + +"@swc/core-linux-arm-gnueabihf@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.161.tgz#4d475d57fdccaab900d88195e2b4e1b990e45e21" + integrity sha512-DGSKqKSBQ42mAMmPhWkfgzXaci4RU0XgmnO1bFVkl8Yw9TaxBBBeCbLIBYJik4DehOOYic9gtXZIfEs90+oc2w== + +"@swc/core-linux-arm64-gnu@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.161.tgz#e528dd661ed85f9069a5792536a2f784cab377f8" + integrity sha512-wdEPjBLuf0bUMafURrUN11MOGs7PHnedWOFAfvyRuNf4HdfwbS2nYDpFCL4mklN8BuprxvRFWfoA+ROigexK4g== + +"@swc/core-linux-arm64-musl@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.161.tgz#928dc578ba5cd8bb26decee62d150c565a09f1f5" + integrity sha512-EPwDDlAIchv1FG1Vc2ArUGsX2b87LSEXHjF59TuOj+oXOANHnFRQa/28wHpeMYN5lHYmyjMplfn37XYLMo8BDw== + +"@swc/core-linux-x64-gnu@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.161.tgz#c13866ef8a1eade5bf9b9b0f0be4b90d69970f10" + integrity sha512-UE+8n2PLCojxywQd1nPbMcus/3zLQjg05Oozrvl1IkHBssk89tk2GhLujUwbFS+MoGFPKAmL+wT+9lXHavK7Og== + +"@swc/core-linux-x64-musl@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.161.tgz#dd171b5357a5e34ece729e4aba528c15cfe4727b" + integrity sha512-mkshCdRhS5s1w1Koph/kS8EJVEmrq+/p4iLsLDozXi1RL16lzk5SYn4ppmzF/Zj9OpgJ+Nzk7kNcZMMJMVIwqw== + +"@swc/core-win32-arm64-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.161.tgz#e8e7cb5bac7319525ba297e4a2819dafc44f98d6" + integrity sha512-5ZMhPSeFJO+h0Ejoq766S25VvrooUW0RdhfcG2u7OFqhdlTXHlvryL7jdf6tILltmJxNWeAGrNE8YI+ARolTeQ== + +"@swc/core-win32-ia32-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.161.tgz#938e66e731f2d72b3dcf8af963c36a807f46286b" + integrity sha512-/c+L8bYCjg8pbx3Jbgx9Cns9nlLUpB4CmugfIdlW+2EdncyZyKu+u+D0egnOjvtlxe8BNw0889oH1Lv4p7KuhA== + +"@swc/core-win32-x64-msvc@1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.161.tgz#f95a8ebe77fe35a1b9e87b52628b870a706b43be" + integrity sha512-FXzZXf+kXvqgZFd+dIzD8Pcc22yejm/XNvpGTy9HZHWYLvlif+QSXrNgvX1oyMWZYT+NCVHwebKjS9FTnTMi9w== + +"@swc/core@^1.2.161": + version "1.2.161" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.161.tgz#bbc79daeb33c1436df8eac58994dc0b73480a02f" + integrity sha512-RXv1y2HDqZ4gAjdvqV0KL1Oms8vUkDgXRU5SPOEa3zMzMDNKHvRfoiBk4ZyaGzhGcr0zflqT4EADKgTB8RFNsw== optionalDependencies: - "@swc/core-android-arm-eabi" "1.2.160" - "@swc/core-android-arm64" "1.2.160" - "@swc/core-darwin-arm64" "1.2.160" - "@swc/core-darwin-x64" "1.2.160" - "@swc/core-freebsd-x64" "1.2.160" - "@swc/core-linux-arm-gnueabihf" "1.2.160" - "@swc/core-linux-arm64-gnu" "1.2.160" - "@swc/core-linux-arm64-musl" "1.2.160" - "@swc/core-linux-x64-gnu" "1.2.160" - "@swc/core-linux-x64-musl" "1.2.160" - "@swc/core-win32-arm64-msvc" "1.2.160" - "@swc/core-win32-ia32-msvc" "1.2.160" - "@swc/core-win32-x64-msvc" "1.2.160" + "@swc/core-android-arm-eabi" "1.2.161" + "@swc/core-android-arm64" "1.2.161" + "@swc/core-darwin-arm64" "1.2.161" + "@swc/core-darwin-x64" "1.2.161" + "@swc/core-freebsd-x64" "1.2.161" + "@swc/core-linux-arm-gnueabihf" "1.2.161" + "@swc/core-linux-arm64-gnu" "1.2.161" + "@swc/core-linux-arm64-musl" "1.2.161" + "@swc/core-linux-x64-gnu" "1.2.161" + "@swc/core-linux-x64-musl" "1.2.161" + "@swc/core-win32-arm64-msvc" "1.2.161" + "@swc/core-win32-ia32-msvc" "1.2.161" + "@swc/core-win32-x64-msvc" "1.2.161" "@swc/jest@^0.2.20": version "0.2.20" @@ -3965,9 +3965,9 @@ recast "^0.20.3" "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.10" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" - integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": version "0.0.29" @@ -3986,10 +3986,10 @@ dependencies: "@types/node" "*" -"@types/lodash@^4.14.180": - version "4.14.180" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" - integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== +"@types/lodash@^4.14.181": + version "4.14.181" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.181.tgz#d1d3740c379fda17ab175165ba04e2d03389385d" + integrity sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag== "@types/mdast@^3.0.0", "@types/mdast@^3.0.10": version "3.0.10" @@ -4196,10 +4196,10 @@ resolved "https://registry.yarnpkg.com/@types/rtl-detect/-/rtl-detect-1.0.0.tgz#5791e18a111f2b8b5b328160af97f3991a5697a5" integrity sha512-lyYh44YgrejEK9/5rhASghvRUOxrSJyyyQmqK7L6F/V5qs6PY1RfCi1VbjSkY6kuDt7lzQyhd006slhda4Oypg== -"@types/rtlcss@^3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@types/rtlcss/-/rtlcss-3.1.2.tgz#2e7b49b270b8724cdc165b1e05f7a71f5a6dc9e6" - integrity sha512-OUggG1uaTQzLYwssBd1PXUoQha995qTInFm5KhDs3OSHjFCkILzQle36GMy93bNf3jOquDUh/2PbrsxLZxtS+Q== +"@types/rtlcss@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/rtlcss/-/rtlcss-3.1.3.tgz#c73f372ec6b94c6b8d7652588559ee88da4f92a8" + integrity sha512-4bYHYzUeHMqnWKDxjJZfriqKJC+KZ91xyB+HoyPCiCzHfvUFcUZZ1SWvsIosPz/E0zsLgR11KHQgZs8fwqkI4Q== dependencies: postcss "^8.2.x" @@ -4388,14 +4388,14 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" - integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== +"@typescript-eslint/eslint-plugin@^5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz#704eb4e75039000531255672bf1c85ee85cf1d67" + integrity sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ== dependencies: - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/type-utils" "5.16.0" - "@typescript-eslint/utils" "5.16.0" + "@typescript-eslint/scope-manager" "5.17.0" + "@typescript-eslint/type-utils" "5.17.0" + "@typescript-eslint/utils" "5.17.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -4403,30 +4403,30 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" - integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== +"@typescript-eslint/parser@^5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.17.0.tgz#7def77d5bcd8458d12d52909118cf3f0a45f89d5" + integrity sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig== dependencies: - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/typescript-estree" "5.16.0" + "@typescript-eslint/scope-manager" "5.17.0" + "@typescript-eslint/types" "5.17.0" + "@typescript-eslint/typescript-estree" "5.17.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" - integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== +"@typescript-eslint/scope-manager@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz#4cea7d0e0bc0e79eb60cad431c89120987c3f952" + integrity sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w== dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" + "@typescript-eslint/types" "5.17.0" + "@typescript-eslint/visitor-keys" "5.17.0" -"@typescript-eslint/type-utils@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" - integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== +"@typescript-eslint/type-utils@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz#1c4549d68c89877662224aabb29fbbebf5fc9672" + integrity sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg== dependencies: - "@typescript-eslint/utils" "5.16.0" + "@typescript-eslint/utils" "5.17.0" debug "^4.3.2" tsutils "^3.21.0" @@ -4435,18 +4435,18 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" - integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== +"@typescript-eslint/types@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f" + integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw== -"@typescript-eslint/typescript-estree@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" - integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== +"@typescript-eslint/typescript-estree@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488" + integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg== dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" + "@typescript-eslint/types" "5.17.0" + "@typescript-eslint/visitor-keys" "5.17.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -4466,15 +4466,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.16.0", "@typescript-eslint/utils@^5.10.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" - integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== +"@typescript-eslint/utils@5.17.0", "@typescript-eslint/utils@^5.10.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.17.0.tgz#549a9e1d491c6ccd3624bc3c1b098f5cfb45f306" + integrity sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/typescript-estree" "5.16.0" + "@typescript-eslint/scope-manager" "5.17.0" + "@typescript-eslint/types" "5.17.0" + "@typescript-eslint/typescript-estree" "5.17.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -4486,12 +4486,12 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" - integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== +"@typescript-eslint/visitor-keys@5.17.0": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128" + integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA== dependencies: - "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/types" "5.17.0" eslint-visitor-keys "^3.0.0" "@vercel/nft@^0.17.0": @@ -4890,9 +4890,9 @@ ansi-regex@^2.0.0: integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ== + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== ansi-regex@^4.1.0: version "4.1.1" @@ -5955,9 +5955,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: - version "1.0.30001320" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" - integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== + version "1.0.30001322" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz#2e4c09d11e1e8f852767dab287069a8d0c29d623" + integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== caseless@~0.12.0: version "0.12.0" @@ -6059,15 +6059,15 @@ chardet@^0.7.0: integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== cheerio-select@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" - integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.6.0.tgz#489f36604112c722afa147dedd0d4609c09e1696" + integrity sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g== dependencies: - css-select "^4.1.3" - css-what "^5.0.1" + css-select "^4.3.0" + css-what "^6.0.1" domelementtype "^2.2.0" - domhandler "^4.2.0" - domutils "^2.7.0" + domhandler "^4.3.1" + domutils "^2.8.0" cheerio@^0.22.0: version "0.22.0" @@ -6970,9 +6970,9 @@ create-require@^1.1.0: integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cron-parser@^4.1.0, cron-parser@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.2.1.tgz#b43205d05ccd5c93b097dae64f3bd811f5993af3" - integrity sha512-5sJBwDYyCp+0vU5b7POl8zLWfgV5fOHxlc45FWoWdHecGC7MQHCjx0CHivCMRnGFovghKhhyYM+Zm9DcY5qcHg== + version "4.3.0" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.3.0.tgz#16c3932fa62d0c30708d4200f510d6ca26bf35a2" + integrity sha512-mK6qJ6k9Kn0/U7Cv6LKQnReUW3GqAW4exgwmHJGb3tPgcy0LrS+PeqxPPiwL8uW/4IJsMsCZrCc4vf1nnXMjzA== dependencies: luxon "^1.28.0" @@ -7081,11 +7081,9 @@ cspell@^5.19.3: vscode-uri "^3.0.3" css-declaration-sorter@^6.0.3: - version "6.1.4" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4" - integrity sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw== - dependencies: - timsort "^0.3.0" + version "6.2.2" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02" + integrity sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg== css-functions-list@^3.0.1: version "3.0.1" @@ -7126,14 +7124,14 @@ css-minimizer-webpack-plugin@^3.4.1: serialize-javascript "^6.0.0" source-map "^0.6.1" -css-select@^4.1.3: - version "4.2.1" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" - integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== +css-select@^4.1.3, css-select@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== dependencies: boolbase "^1.0.0" - css-what "^5.1.0" - domhandler "^4.3.0" + css-what "^6.0.1" + domhandler "^4.3.1" domutils "^2.8.0" nth-check "^2.0.1" @@ -7160,10 +7158,10 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== -css-what@^5.0.1, css-what@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" - integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== +css-what@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.0.1.tgz#3be33be55b9f302f710ba3a9c3abc1e2a63fc7eb" + integrity sha512-z93ZGFLNc6yaoXAmVhqoSIb+BduplteCt1fepvwhBUQK6MNE4g6fgjpuZKJKp0esUe+vXWlIkwZZjNWoOKw0ZA== cssesc@^3.0.0: version "3.0.0" @@ -7325,7 +7323,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3: +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -7599,7 +7597,7 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== -detect-libc@^1.0.2, detect-libc@^1.0.3: +detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== @@ -7840,7 +7838,7 @@ domhandler@^2.3.0: dependencies: domelementtype "1" -domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== @@ -7863,7 +7861,7 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -domutils@^2.5.2, domutils@^2.7.0, domutils@^2.8.0: +domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== @@ -7973,9 +7971,9 @@ ejs@^3.1.6: jake "^10.6.1" electron-to-chromium@^1.4.84: - version "1.4.92" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz#88996e9aceb3a500710fd439abfa89b6cc1ac56c" - integrity sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA== + version "1.4.100" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.100.tgz#da82de8a19a47ea3dcdf141dde85355942fbc4e7" + integrity sha512-pNrSE2naf8fizl6/Uxq8UbKb8hU9EiYW4OzCYswosXoLV5NTMOUVKECNzDaHiUubsPq/kAckOzZd7zd8S8CHVw== elegant-spinner@^1.0.1: version "1.0.1" @@ -8089,9 +8087,9 @@ error-stack-parser@^2.0.2, error-stack-parser@^2.0.3, error-stack-parser@^2.0.6: stackframe "^1.1.1" es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + version "1.19.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.2.tgz#8f7b696d8f15b167ae3640b4060670f3d054143f" + integrity sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" @@ -8099,15 +8097,15 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: get-intrinsic "^1.1.1" get-symbol-description "^1.0.0" has "^1.0.3" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" is-callable "^1.2.4" - is-negative-zero "^2.0.1" + is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.1" is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" + is-weakref "^1.0.2" + object-inspect "^1.12.0" object-keys "^1.1.1" object.assign "^4.1.2" string.prototype.trimend "^1.0.4" @@ -8269,10 +8267,10 @@ eslint-plugin-jsx-a11y@^6.5.1: language-tags "^1.0.5" minimatch "^3.0.4" -eslint-plugin-react-hooks@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" - integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== +eslint-plugin-react-hooks@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.4.0.tgz#71c39e528764c848d8253e1aa2c7024ed505f6c4" + integrity sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ== eslint-plugin-react@^7.29.4: version "7.29.4" @@ -8341,10 +8339,10 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" - integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== +eslint@^8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.12.0.tgz#c7a5bd1cfa09079aae64c9076c07eada66a46e8e" + integrity sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q== dependencies: "@eslint/eslintrc" "^1.2.1" "@humanwhocodes/config-array" "^0.9.2" @@ -8849,12 +8847,12 @@ figures@^3.0.0, figures@^3.2.0: escape-string-regexp "^1.0.5" figures@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-4.0.0.tgz#116f140b9d45d1e7a736e7fe80473f1e93f6e4d6" - integrity sha512-VnYcWq6H6F0qDN0QnorznBr0abEovifzUokmnezpKZBUbDmbLAt7LMryOp1TKFVxLxyNYkxEkCEADZR58U9oSw== + version "4.0.1" + resolved "https://registry.yarnpkg.com/figures/-/figures-4.0.1.tgz#27b26609907bc888b3e3b0ef5403643f80aa2518" + integrity sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w== dependencies: escape-string-regexp "^5.0.0" - is-unicode-supported "^1.0.0" + is-unicode-supported "^1.2.0" file-entry-cache@^6.0.1: version "6.0.1" @@ -10117,9 +10115,9 @@ html-encoding-sniffer@^2.0.1: whatwg-encoding "^1.0.5" html-entities@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" - integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== html-escaper@^2.0.0: version "2.0.2" @@ -10836,7 +10834,7 @@ is-natural-number@^4.0.1: resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" integrity sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ== -is-negative-zero@^2.0.1: +is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== @@ -11037,7 +11035,7 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-unicode-supported@^1.0.0: +is-unicode-supported@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz#f4f54f34d8ebc84a46b93559a036763b6d3e1014" integrity sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ== @@ -11047,7 +11045,7 @@ is-url@^1.2.4: resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== -is-weakref@^1.0.1: +is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== @@ -12079,11 +12077,16 @@ libnpmpublish@^4.0.0: semver "^7.1.3" ssri "^8.0.1" -lilconfig@2.0.4, lilconfig@^2.0.3: +lilconfig@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== +lilconfig@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -13218,9 +13221,9 @@ nano-css@^5.3.1: stylis "^4.0.6" nanoid@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + version "3.3.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" + integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== nanomatch@^1.2.9: version "1.2.13" @@ -13269,17 +13272,17 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.2: integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" - integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== + version "2.1.1" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" + integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== -netlify-cli@^9.13.4: - version "9.13.4" - resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.4.tgz#362f34b28b5c76b1b6eea74096e6957fa4440eda" - integrity sha512-Ws9qKeeGqmHezoKVzGKCfYr+gh2LJZ1RfCjRX8US+3S1YxFyiHpbR8LN7lNDbZj34jEhZeOrwYwS5zbwJtqHCQ== +netlify-cli@^9.13.6: + version "9.13.6" + resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.6.tgz#b86984ada9c3194588296bc113e541fe371e98eb" + integrity sha512-6S+uWGZSroD+2Y+RQj0a5bcsjpNCPrJBt2nJHHg0SnGiSCAkf/h2aRUTrFHiyDB/CDWE9brswggxDvGqdSAEAg== dependencies: - "@netlify/build" "^26.5.0" - "@netlify/config" "^17.0.18" + "@netlify/build" "^26.5.1" + "@netlify/config" "^17.0.19" "@netlify/framework-info" "^9.0.2" "@netlify/local-functions-proxy" "^1.1.1" "@netlify/plugin-edge-handlers" "^3.0.7" @@ -13349,7 +13352,7 @@ netlify-cli@^9.13.4: memoize-one "^6.0.0" minimist "^1.2.5" multiparty "^4.2.1" - netlify "^11.0.0" + netlify "^11.0.1" netlify-headers-parser "^6.0.2" netlify-onegraph-internal "0.0.50" netlify-redirect-parser "^13.0.5" @@ -13428,7 +13431,7 @@ netlify-redirector@^0.2.1: resolved "https://registry.yarnpkg.com/netlify-redirector/-/netlify-redirector-0.2.1.tgz#efdb761ea2c52edb3ecb5f237db0e10861f2ff0e" integrity sha512-17vDR9p1Loanp+vd57y+b6WlKb5X+qb0LZ44oTYsKJbdonz4Md+Ybv1lzH1w1aKm5YWWXHR8LMpWyY9bjlAJKw== -netlify@^11.0.0, netlify@^11.0.1: +netlify@^11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/netlify/-/netlify-11.0.1.tgz#ab2551001e3d2d845ac0c14c2138427c90a3935e" integrity sha512-TkVuTvmhlAtvAdgqb+iA5wMehEHS5QcPOrULm1t809Q6KmZIhe+7b0+jwZSsDqgX3OWK/P3xgk/AU0ZbTv7ufw== @@ -13490,7 +13493,7 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch@2.6.7, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.5, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -13506,10 +13509,10 @@ node-fetch@^3.0.0: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-forge@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2" - integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA== +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.2: version "4.3.0" @@ -13892,7 +13895,7 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.9.0: +object-inspect@^1.12.0, object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== @@ -15123,10 +15126,10 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prettier@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.0.tgz#12f8f504c4d8ddb76475f441337542fa799207d4" - integrity sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A== +prettier@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" + integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== pretty-bytes@^5.3.0, pretty-bytes@^5.6.0: version "5.6.0" @@ -16108,7 +16111,7 @@ remark-admonitions@^1.2.1: unified "^8.4.2" unist-util-visit "^2.0.1" -remark-emoji@^2.1.0: +remark-emoji@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7" integrity sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w== @@ -16190,7 +16193,7 @@ remark-stringify@^8.0.0, remark-stringify@^8.1.0: unherit "^1.0.4" xtend "^4.0.1" -remark@^12.0.0: +remark@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/remark/-/remark-12.0.1.tgz#f1ddf68db7be71ca2bad0a33cd3678b86b9c709f" integrity sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw== @@ -16633,11 +16636,11 @@ select-hose@^2.0.0: integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== selfsigned@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.0.tgz#e927cd5377cbb0a1075302cff8df1042cc2bce5b" - integrity sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56" + integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ== dependencies: - node-forge "^1.2.0" + node-forge "^1" semver-diff@^3.1.1: version "3.1.1" @@ -17602,16 +17605,16 @@ stylelint-config-standard@^25.0.0: dependencies: stylelint-config-recommended "^7.0.0" -stylelint@^14.6.0: - version "14.6.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.0.tgz#bf577103c8a1d47cd8818469e27db77b83ab3cc1" - integrity sha512-Xk2sqXYPi9nXgq70nBiZkbQm/QOOKd83NBTaBE1fXEWAEeRlgHnKC/E7kJFlT6K0SaNDOK5yIvR7GFPGsNLuOg== +stylelint@^14.6.1: + version "14.6.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.1.tgz#aff137b0254515fc36b91921d88a3eb2edc194bf" + integrity sha512-FfNdvZUZdzh9KDQxDnO7Opp+prKh8OQVuSW8S13cBtxrooCbm6J6royhUeb++53WPMt04VB+ZbOz/QmzAijs6Q== dependencies: balanced-match "^2.0.0" colord "^2.9.2" cosmiconfig "^7.0.1" css-functions-list "^3.0.1" - debug "^4.3.3" + debug "^4.3.4" execall "^2.0.0" fast-glob "^3.2.11" fastest-levenshtein "^1.0.12" @@ -17685,10 +17688,10 @@ supports-color@^8.0.0, supports-color@^8.1.0: dependencies: has-flag "^4.0.0" -supports-color@^9.0.0, supports-color@^9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" - integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== +supports-color@^9.0.0, supports-color@^9.2.1, supports-color@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.2.tgz#502acaf82f2b7ee78eb7c83dcac0f89694e5a7bb" + integrity sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA== supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.2.0: version "2.2.0" @@ -18017,11 +18020,6 @@ timed-out@^4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A== - tiny-invariant@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" @@ -18110,7 +18108,7 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -to-vfile@^6.0.0: +to-vfile@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/to-vfile/-/to-vfile-6.1.0.tgz#5f7a3f65813c2c4e34ee1f7643a5646344627699" integrity sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw== @@ -18527,7 +18525,7 @@ unified@^8.4.2: trough "^1.0.0" vfile "^4.0.0" -unified@^9.0.0, unified@^9.2.1: +unified@^9.0.0, unified@^9.2.2: version "9.2.2" resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== @@ -18667,7 +18665,7 @@ unist-util-visit-parents@^5.0.0: "@types/unist" "^2.0.0" unist-util-is "^5.0.0" -unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist-util-visit@^2.0.2, unist-util-visit@^2.0.3: +unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist-util-visit@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== From fd24bd180d78de0f2f135d534fbb6222ad89e23b Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 11:57:13 +0800 Subject: [PATCH 105/405] fix(core): all plugin lifecycles should receive translated content (#7066) --- packages/docusaurus/src/server/index.ts | 5 +- .../__snapshots__/index.test.ts.snap | 1 - .../docusaurus/src/server/plugins/index.ts | 183 ++++++++---------- 3 files changed, 77 insertions(+), 112 deletions(-) diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index 282bee4c366f..fecb98e3111f 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -125,10 +125,7 @@ export async function load(options: LoadContextOptions): Promise<Props> { ssrTemplate, codeTranslations: siteCodeTranslations, } = context; - const {plugins, pluginsRouteConfigs, globalData, themeConfigTranslated} = - await loadPlugins(context); - // Side-effect to replace the untranslated themeConfig by the translated one - context.siteConfig.themeConfig = themeConfigTranslated; + const {plugins, pluginsRouteConfigs, globalData} = await loadPlugins(context); const clientModules = loadClientModules(plugins); const {headTags, preBodyTags, postBodyTags} = loadHtmlTags(plugins); const {registry, routesChunkNames, routesConfig, routesPaths} = diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap index 0a16be1b45b0..688eaa837af2 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/index.test.ts.snap @@ -64,6 +64,5 @@ exports[`loadPlugins loads plugins 1`] = ` }, ], "pluginsRouteConfigs": [], - "themeConfigTranslated": {}, } `; diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 9a253211ffbe..5fe5990cc544 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -13,7 +13,6 @@ import type { RouteConfig, AllContent, GlobalData, - ThemeConfig, LoadedPlugin, InitializedPlugin, PluginRouteContext, @@ -28,13 +27,13 @@ import {applyRouteTrailingSlash, sortConfig} from './routeConfig'; /** * Initializes the plugins, runs `loadContent`, `translateContent`, * `contentLoaded`, and `translateThemeConfig`. Because `contentLoaded` is - * side-effect-ful (it generates temp files), so is this function. + * side-effect-ful (it generates temp files), so is this function. This function + * would also mutate `context.siteConfig.themeConfig` to translate it. */ export async function loadPlugins(context: LoadContext): Promise<{ plugins: LoadedPlugin[]; pluginsRouteConfigs: RouteConfig[]; globalData: GlobalData; - themeConfigTranslated: ThemeConfig; }> { // 1. Plugin Lifecycle - Initialization/Constructor. const plugins: InitializedPlugin[] = await initPlugins(context); @@ -48,21 +47,15 @@ export async function loadPlugins(context: LoadContext): Promise<{ // Currently plugins run lifecycle methods in parallel and are not // order-dependent. We could change this in future if there are plugins which // need to run in certain order or depend on others for data. + // This would also translate theme config and content upfront, given the + // translation files that the plugin declares. const loadedPlugins: LoadedPlugin[] = await Promise.all( plugins.map(async (plugin) => { const content = await plugin.loadContent?.(); - return {...plugin, content}; - }), - ); - - const contentLoadedTranslatedPlugins = await Promise.all( - loadedPlugins.map(async (plugin) => { - const translationFiles = - (await plugin?.getTranslationFiles?.({ - content: plugin.content, - })) ?? []; - const localizedTranslationFiles = await Promise.all( - translationFiles.map((translationFile) => + const rawTranslationFiles = + (await plugin?.getTranslationFiles?.({content})) ?? []; + const translationFiles = await Promise.all( + rawTranslationFiles.map((translationFile) => localizePluginTranslationFile({ locale: context.i18n.currentLocale, siteDir: context.siteDir, @@ -71,10 +64,17 @@ export async function loadPlugins(context: LoadContext): Promise<{ }), ), ); - return { - ...plugin, - translationFiles: localizedTranslationFiles, - }; + const translatedContent = + plugin.translateContent?.({content, translationFiles}) ?? content; + const translatedThemeConfigSlice = plugin.translateThemeConfig?.({ + themeConfig: context.siteConfig.themeConfig, + translationFiles, + }); + // Side-effect to merge theme config translations. A plugin should only + // translate its own slice of theme config and should make no assumptions + // about other plugins' keys, so this is safe to run in parallel. + Object.assign(context.siteConfig.themeConfig, translatedThemeConfigSlice); + return {...plugin, content: translatedContent}; }), ); @@ -90,86 +90,75 @@ export async function loadPlugins(context: LoadContext): Promise<{ // 3. Plugin Lifecycle - contentLoaded. const pluginsRouteConfigs: RouteConfig[] = []; - const globalData: GlobalData = {}; await Promise.all( - contentLoadedTranslatedPlugins.map( - async ({content, translationFiles, ...plugin}) => { - if (!plugin.contentLoaded) { - return; - } - const pluginId = plugin.options.id; - // plugins data files are namespaced by pluginName/pluginId - const dataDir = path.join( - context.generatedFilesDir, - plugin.name, - pluginId, - ); - // TODO this would be better to do all that in the codegen phase - // TODO handle context for nested routes - const pluginRouteContext: PluginRouteContext = { - plugin: {name: plugin.name, id: pluginId}, - data: undefined, // TODO allow plugins to provide context data - }; - const pluginRouteContextModulePath = path.join( - dataDir, - `${docuHash('pluginRouteContextModule')}.json`, - ); - await generate( - '/', - pluginRouteContextModulePath, - JSON.stringify(pluginRouteContext, null, 2), - ); - - const actions: PluginContentLoadedActions = { - addRoute(initialRouteConfig) { - // Trailing slash behavior is handled generically for all plugins - const finalRouteConfig = applyRouteTrailingSlash( - initialRouteConfig, - context.siteConfig, - ); - pluginsRouteConfigs.push({ - ...finalRouteConfig, - modules: { - ...finalRouteConfig.modules, - __routeContextModule: pluginRouteContextModulePath, - }, - }); - }, - async createData(name, data) { - const modulePath = path.join(dataDir, name); - await generate(dataDir, name, data); - return modulePath; - }, - setGlobalData(data) { - globalData[plugin.name] ??= {}; - globalData[plugin.name]![pluginId] = data; - }, - }; + loadedPlugins.map(async ({content, ...plugin}) => { + if (!plugin.contentLoaded) { + return; + } + const pluginId = plugin.options.id; + // plugins data files are namespaced by pluginName/pluginId + const dataDir = path.join( + context.generatedFilesDir, + plugin.name, + pluginId, + ); + // TODO this would be better to do all that in the codegen phase + // TODO handle context for nested routes + const pluginRouteContext: PluginRouteContext = { + plugin: {name: plugin.name, id: pluginId}, + data: undefined, // TODO allow plugins to provide context data + }; + const pluginRouteContextModulePath = path.join( + dataDir, + `${docuHash('pluginRouteContextModule')}.json`, + ); + await generate( + '/', + pluginRouteContextModulePath, + JSON.stringify(pluginRouteContext, null, 2), + ); - const translatedContent = - plugin.translateContent?.({content, translationFiles}) ?? content; + const actions: PluginContentLoadedActions = { + addRoute(initialRouteConfig) { + // Trailing slash behavior is handled generically for all plugins + const finalRouteConfig = applyRouteTrailingSlash( + initialRouteConfig, + context.siteConfig, + ); + pluginsRouteConfigs.push({ + ...finalRouteConfig, + modules: { + ...finalRouteConfig.modules, + __routeContextModule: pluginRouteContextModulePath, + }, + }); + }, + async createData(name, data) { + const modulePath = path.join(dataDir, name); + await generate(dataDir, name, data); + return modulePath; + }, + setGlobalData(data) { + globalData[plugin.name] ??= {}; + globalData[plugin.name]![pluginId] = data; + }, + }; - await plugin.contentLoaded({ - content: translatedContent, - actions, - allContent, - }); - }, - ), + await plugin.contentLoaded({content, actions, allContent}); + }), ); // 4. Plugin Lifecycle - routesLoaded. await Promise.all( - contentLoadedTranslatedPlugins.map(async (plugin) => { + loadedPlugins.map(async (plugin) => { if (!plugin.routesLoaded) { return; } - // TODO remove this deprecated lifecycle soon - // deprecated since alpha-60 - // TODO, 1 user reported usage of this lifecycle! https://github.com/facebook/docusaurus/issues/3918 + // TODO alpha-60: remove this deprecated lifecycle soon + // 1 user reported usage of this lifecycle: https://github.com/facebook/docusaurus/issues/3918 logger.error`Plugin code=${'routesLoaded'} lifecycle is deprecated. If you think we should keep this lifecycle, please report here: url=${'https://github.com/facebook/docusaurus/issues/3918'}`; await plugin.routesLoaded(pluginsRouteConfigs); @@ -180,25 +169,5 @@ export async function loadPlugins(context: LoadContext): Promise<{ // routes are always placed last. sortConfig(pluginsRouteConfigs, context.siteConfig.baseUrl); - // Apply each plugin one after the other to translate the theme config - const themeConfigTranslated = contentLoadedTranslatedPlugins.reduce( - (currentThemeConfig, plugin) => { - const translatedThemeConfigSlice = plugin.translateThemeConfig?.({ - themeConfig: currentThemeConfig, - translationFiles: plugin.translationFiles, - }); - return { - ...currentThemeConfig, - ...translatedThemeConfigSlice, - }; - }, - context.siteConfig.themeConfig, - ); - - return { - plugins: loadedPlugins, - pluginsRouteConfigs, - globalData, - themeConfigTranslated, - }; + return {plugins: loadedPlugins, pluginsRouteConfigs, globalData}; } From 13e7de853e0f0968916b60bae769bd49d224a19d Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 14:50:04 +0800 Subject: [PATCH 106/405] refactor(theme-classic): extract doc-related navbar items' logic to theme-common (#7067) --- .../src/theme-classic.d.ts | 9 +- .../src/theme/NavbarItem/DocNavbarItem.tsx | 39 ++------ .../theme/NavbarItem/DocSidebarNavbarItem.tsx | 58 ++--------- .../DocsVersionDropdownNavbarItem.tsx | 59 +++++------- .../NavbarItem/DocsVersionNavbarItem.tsx | 13 +-- .../LocaleDropdownNavbarItem/index.tsx | 8 +- .../src/theme/NavbarItem/utils.ts | 7 +- .../src/contexts/docsPreferredVersion.tsx | 7 +- packages/docusaurus-theme-common/src/index.ts | 3 + .../src/utils/docsUtils.tsx | 96 +++++++++++++++++++ .../src/utils/searchUtils.ts | 2 + 11 files changed, 166 insertions(+), 135 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 04e8b6ccd92b..9f3c48ed3da0 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -780,7 +780,14 @@ declare module '@theme/NavbarItem' { } declare module '@theme/NavbarItem/utils' { - export function getInfimaActiveClassName(mobile?: boolean): string; + /** + * On desktop and mobile, we would apply different class names for dropdown + * items. + * @see https://github.com/facebook/docusaurus/pull/5431 + */ + export function getInfimaActiveClassName( + mobile?: boolean, + ): `${'menu' | 'navbar'}__link--active`; } declare module '@theme/PaginatorNavLink' { diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx index 8c56cebf24fd..a5e9b06f02bc 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx @@ -7,30 +7,11 @@ import React from 'react'; import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; -import { - useLatestVersion, - useActiveDocContext, -} from '@docusaurus/plugin-content-docs/client'; +import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client'; import clsx from 'clsx'; import {getInfimaActiveClassName} from '@theme/NavbarItem/utils'; import type {Props} from '@theme/NavbarItem/DocNavbarItem'; -import {useDocsPreferredVersion, uniq} from '@docusaurus/theme-common'; -import type {GlobalVersion} from '@docusaurus/plugin-content-docs/client'; - -function getDocInVersions(versions: GlobalVersion[], docId: string) { - const allDocs = versions.flatMap((version) => version.docs); - const doc = allDocs.find((versionDoc) => versionDoc.id === docId); - if (!doc) { - const docIds = allDocs.map((versionDoc) => versionDoc.id).join('\n- '); - throw new Error( - `DocNavbarItem: couldn't find any doc with id "${docId}" in version${ - versions.length ? 's' : '' - } ${versions.map((version) => version.name).join(', ')}". -Available doc ids are:\n- ${docIds}`, - ); - } - return doc; -} +import {useLayoutDoc} from '@docusaurus/theme-common'; export default function DocNavbarItem({ docId, @@ -38,17 +19,8 @@ export default function DocNavbarItem({ docsPluginId, ...props }: Props): JSX.Element { - const {activeVersion, activeDoc} = useActiveDocContext(docsPluginId); - const {preferredVersion} = useDocsPreferredVersion(docsPluginId); - const latestVersion = useLatestVersion(docsPluginId); - - // Versions used to look for the doc to link to, ordered + no duplicate - const versions = uniq( - [activeVersion, preferredVersion, latestVersion].filter( - Boolean, - ) as GlobalVersion[], - ); - const doc = getDocInVersions(versions, docId); + const {activeDoc} = useActiveDocContext(docsPluginId); + const doc = useLayoutDoc(docId, docsPluginId); const activeDocInfimaClassName = getInfimaActiveClassName(props.mobile); return ( @@ -57,6 +29,9 @@ export default function DocNavbarItem({ {...props} className={clsx(props.className, { [activeDocInfimaClassName]: + // Do not make the item active if the active doc doesn't have sidebar. + // If `activeDoc === doc` react-router will make it active anyways, + // regardless of the existence of a sidebar activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar, })} activeClassName={activeDocInfimaClassName} diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocSidebarNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocSidebarNavbarItem.tsx index ca6ec3d86687..965664855603 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocSidebarNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocSidebarNavbarItem.tsx @@ -7,48 +7,12 @@ import React from 'react'; import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; -import { - useLatestVersion, - useActiveDocContext, -} from '@docusaurus/plugin-content-docs/client'; +import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client'; import clsx from 'clsx'; import {getInfimaActiveClassName} from '@theme/NavbarItem/utils'; -import {useDocsPreferredVersion, uniq} from '@docusaurus/theme-common'; +import {useLayoutDocsSidebar} from '@docusaurus/theme-common'; import type {Props} from '@theme/NavbarItem/DocSidebarNavbarItem'; -import type { - GlobalVersion, - GlobalSidebar, -} from '@docusaurus/plugin-content-docs/client'; - -function getSidebarLink(versions: GlobalVersion[], sidebarId: string) { - const allSidebars = versions - .flatMap((version) => { - if (version.sidebars) { - return Object.entries(version.sidebars); - } - return undefined; - }) - .filter( - (sidebarItem): sidebarItem is [string, GlobalSidebar] => !!sidebarItem, - ); - const sidebarEntry = allSidebars.find((sidebar) => sidebar[0] === sidebarId); - if (!sidebarEntry) { - throw new Error( - `DocSidebarNavbarItem: couldn't find any sidebar with id "${sidebarId}" in version${ - versions.length ? 's' : '' - } ${versions.map((version) => version.name).join(', ')}". -Available sidebar ids are: -- ${Object.keys(allSidebars).join('\n- ')}`, - ); - } - if (!sidebarEntry[1].link) { - throw new Error( - `DocSidebarNavbarItem: couldn't find any document for sidebar with id "${sidebarId}"`, - ); - } - return sidebarEntry[1].link; -} export default function DocSidebarNavbarItem({ sidebarId, @@ -56,17 +20,13 @@ export default function DocSidebarNavbarItem({ docsPluginId, ...props }: Props): JSX.Element { - const {activeVersion, activeDoc} = useActiveDocContext(docsPluginId); - const {preferredVersion} = useDocsPreferredVersion(docsPluginId); - const latestVersion = useLatestVersion(docsPluginId); - - // Versions used to look for the doc to link to, ordered + no duplicate - const versions = uniq( - [activeVersion, preferredVersion, latestVersion].filter( - Boolean, - ) as GlobalVersion[], - ); - const sidebarLink = getSidebarLink(versions, sidebarId); + const {activeDoc} = useActiveDocContext(docsPluginId); + const sidebarLink = useLayoutDocsSidebar(sidebarId, docsPluginId).link; + if (!sidebarLink) { + throw new Error( + `DocSidebarNavbarItem: Sidebar with ID "${sidebarId}" doesn't have anything to be linked to.`, + ); + } const activeDocInfimaClassName = getInfimaActiveClassName(props.mobile); return ( diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx index 2cf17478358f..9624dc3ddedb 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx @@ -10,14 +10,15 @@ import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import { useVersions, - useLatestVersion, useActiveDocContext, } from '@docusaurus/plugin-content-docs/client'; -import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; -import {useDocsPreferredVersion} from '@docusaurus/theme-common'; +import { + useDocsPreferredVersion, + useDocsVersionCandidates, +} from '@docusaurus/theme-common'; import {translate} from '@docusaurus/Translate'; import type {GlobalVersion} from '@docusaurus/plugin-content-docs/client'; -import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; +import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; const getVersionMainDoc = (version: GlobalVersion) => version.docs.find((doc) => doc.id === version.mainDocId)!; @@ -32,36 +33,28 @@ export default function DocsVersionDropdownNavbarItem({ }: Props): JSX.Element { const activeDocContext = useActiveDocContext(docsPluginId); const versions = useVersions(docsPluginId); - const latestVersion = useLatestVersion(docsPluginId); - - const {preferredVersion, savePreferredVersionName} = - useDocsPreferredVersion(docsPluginId); - - function getItems(): LinkLikeNavbarItemProps[] { - const versionLinks = versions.map((version) => { - // We try to link to the same doc, in another version - // When not possible, fallback to the "main doc" of the version - const versionDoc = - activeDocContext?.alternateDocVersions[version.name] || - getVersionMainDoc(version); - return { - isNavLink: true, - label: version.label, - to: versionDoc.path, - isActive: () => version === activeDocContext?.activeVersion, - onClick: () => { - savePreferredVersionName(version.name); - }, - }; - }); - - return [...dropdownItemsBefore, ...versionLinks, ...dropdownItemsAfter]; - } - - const items = getItems(); + const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId); + const versionLinks = versions.map((version) => { + // We try to link to the same doc, in another version + // When not possible, fallback to the "main doc" of the version + const versionDoc = + activeDocContext?.alternateDocVersions[version.name] ?? + getVersionMainDoc(version); + return { + isNavLink: true, + label: version.label, + to: versionDoc.path, + isActive: () => version === activeDocContext?.activeVersion, + onClick: () => savePreferredVersionName(version.name), + }; + }); + const items = [ + ...dropdownItemsBefore, + ...versionLinks, + ...dropdownItemsAfter, + ]; - const dropdownVersion = - activeDocContext.activeVersion ?? preferredVersion ?? latestVersion; + const dropdownVersion = useDocsVersionCandidates(docsPluginId)[0]; // Mobile dropdown is handled a bit differently const dropdownLabel = diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx index 5d88a534ae3b..db6873764319 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx @@ -7,13 +7,9 @@ import React from 'react'; import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; -import { - useActiveVersion, - useLatestVersion, - type GlobalVersion, -} from '@docusaurus/plugin-content-docs/client'; +import {useDocsVersionCandidates} from '@docusaurus/theme-common'; +import type {GlobalVersion} from '@docusaurus/plugin-content-docs/client'; import type {Props} from '@theme/NavbarItem/DocsVersionNavbarItem'; -import {useDocsPreferredVersion} from '@docusaurus/theme-common'; const getVersionMainDoc = (version: GlobalVersion) => version.docs.find((doc) => doc.id === version.mainDocId)!; @@ -24,10 +20,7 @@ export default function DocsVersionNavbarItem({ docsPluginId, ...props }: Props): JSX.Element { - const activeVersion = useActiveVersion(docsPluginId); - const {preferredVersion} = useDocsPreferredVersion(docsPluginId); - const latestVersion = useLatestVersion(docsPluginId); - const version = activeVersion ?? preferredVersion ?? latestVersion; + const version = useDocsVersionCandidates(docsPluginId)[0]; const label = staticLabel ?? version.label; const path = staticTo ?? getVersionMainDoc(version).path; return <DefaultNavbarItem {...props} label={label} to={path} />; diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx index 13e014c4ca03..bec77b1a309b 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx @@ -27,10 +27,6 @@ export default function LocaleDropdownNavbarItem({ } = useDocusaurusContext(); const alternatePageUtils = useAlternatePageUtils(); - function getLocaleLabel(locale: string) { - return localeConfigs[locale]!.label; - } - const localeItems = locales.map((locale): LinkLikeNavbarItemProps => { const to = `pathname://${alternatePageUtils.createUrl({ locale, @@ -38,7 +34,7 @@ export default function LocaleDropdownNavbarItem({ })}`; return { isNavLink: true, - label: getLocaleLabel(locale), + label: localeConfigs[locale]!.label, to, target: '_self', autoAddBaseUrl: false, @@ -55,7 +51,7 @@ export default function LocaleDropdownNavbarItem({ id: 'theme.navbar.mobileLanguageDropdown.label', description: 'The label for the mobile language switcher dropdown', }) - : getLocaleLabel(currentLocale); + : localeConfigs[currentLocale]!.label; return ( <DropdownNavbarItem diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/utils.ts b/packages/docusaurus-theme-classic/src/theme/NavbarItem/utils.ts index b3f9cce11440..a98db455f25e 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/utils.ts +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/utils.ts @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -// eslint-disable-next-line import/no-named-export -export const getInfimaActiveClassName = (mobile?: boolean): string => +/* eslint-disable import/no-named-export */ + +export const getInfimaActiveClassName = ( + mobile?: boolean, +): `${'menu' | 'navbar'}__link--active` => mobile ? 'menu__link--active' : 'navbar__link--active'; diff --git a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx index a2da2c71b699..0922c2c33c89 100644 --- a/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsPreferredVersion.tsx @@ -198,8 +198,11 @@ function useDocsPreferredVersionContext(): ContextValue { } /** - * Returns a read-write interface to a plugin's preferred version. - * Note, the `preferredVersion` attribute will always be `null` before mount. + * Returns a read-write interface to a plugin's preferred version. The + * "preferred version" is defined as the last version that the user visited. + * For example, if a user is using v3, even when v4 is later published, the user + * would still be browsing v3 docs when she opens the website next time. Note, + * the `preferredVersion` attribute will always be `null` before mount. */ export function useDocsPreferredVersion( pluginId: string | undefined = DEFAULT_PLUGIN_ID, diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 18820aa13fc9..77afa2fdfd21 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -50,6 +50,9 @@ export { useCurrentSidebarCategory, isActiveSidebarItem, useSidebarBreadcrumbs, + useDocsVersionCandidates, + useLayoutDoc, + useLayoutDocsSidebar, } from './utils/docsUtils'; export {useTitleFormatter} from './utils/generalUtils'; diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index e5e54478b415..64e700a48722 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -5,9 +5,15 @@ * LICENSE file in the root directory of this source tree. */ +import {useMemo} from 'react'; import { useAllDocsData, useActivePlugin, + useActiveDocContext, + useLatestVersion, + type GlobalVersion, + type GlobalSidebar, + type GlobalDoc, } from '@docusaurus/plugin-content-docs/client'; import type { PropSidebar, @@ -16,8 +22,10 @@ import type { PropVersionDoc, PropSidebarBreadcrumbsItem, } from '@docusaurus/plugin-content-docs'; +import {useDocsPreferredVersion} from '../contexts/docsPreferredVersion'; import {useDocsVersion} from '../contexts/docsVersion'; import {useDocsSidebar} from '../contexts/docsSidebar'; +import {uniq} from './jsUtils'; import {isSamePath} from './routesUtils'; import {useLocation} from '@docusaurus/router'; @@ -178,3 +186,91 @@ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null { return breadcrumbs.reverse(); } + +/** + * "Version candidates" are mostly useful for the layout components, which must + * be able to work on all pages. For example, if a user has `{ type: "doc", + * docId: "intro" }` as a navbar item, which version does that refer to? We + * believe that it could refer to at most three version candidates: + * + * 1. The **active version**, the one that the user is currently browsing. See + * {@link useActiveDocContext}. + * 2. The **preferred version**, the one that the user last visited. See + * {@link useDocsPreferredVersion}. + * 3. The **latest version**, the "default". See {@link useLatestVersion}. + * + * @param docsPluginId The plugin ID to get versions from. + * @returns An array of 1~3 versions with priorities defined above, guaranteed + * to be unique and non-sparse. Will be memoized, hence stable for deps array. + */ +export function useDocsVersionCandidates( + docsPluginId?: string, +): [GlobalVersion, ...GlobalVersion[]] { + const {activeVersion} = useActiveDocContext(docsPluginId); + const {preferredVersion} = useDocsPreferredVersion(docsPluginId); + const latestVersion = useLatestVersion(docsPluginId); + return useMemo( + () => + uniq( + [activeVersion, preferredVersion, latestVersion].filter(Boolean), + ) as [GlobalVersion, ...GlobalVersion[]], + [activeVersion, preferredVersion, latestVersion], + ); +} + +/** + * The layout components, like navbar items, must be able to work on all pages, + * even on non-doc ones. This hook would always return a sidebar to be linked + * to. See also {@link useDocsVersionCandidates} for how this selection is done. + * + * @throws This hook throws if a sidebar with said ID is not found. + */ +export function useLayoutDocsSidebar( + sidebarId: string, + docsPluginId?: string, +): GlobalSidebar { + const versions = useDocsVersionCandidates(docsPluginId); + return useMemo(() => { + const allSidebars = versions.flatMap((version) => + version.sidebars ? Object.entries(version.sidebars) : [], + ); + const sidebarEntry = allSidebars.find( + (sidebar) => sidebar[0] === sidebarId, + ); + if (!sidebarEntry) { + throw new Error( + `Can't find any sidebar with id "${sidebarId}" in version${ + versions.length > 1 ? 's' : '' + } ${versions.map((version) => version.name).join(', ')}". + Available sidebar ids are: + - ${Object.keys(allSidebars).join('\n- ')}`, + ); + } + return sidebarEntry[1]; + }, [sidebarId, versions]); +} + +/** + * The layout components, like navbar items, must be able to work on all pages, + * even on non-doc ones. This hook would always return a doc to be linked + * to. See also {@link useDocsVersionCandidates} for how this selection is done. + * + * @throws This hook throws if a doc with said ID is not found. + */ +export function useLayoutDoc(docId: string, docsPluginId?: string): GlobalDoc { + const versions = useDocsVersionCandidates(docsPluginId); + return useMemo(() => { + const allDocs = versions.flatMap((version) => version.docs); + const doc = allDocs.find((versionDoc) => versionDoc.id === docId); + if (!doc) { + throw new Error( + `DocNavbarItem: couldn't find any doc with id "${docId}" in version${ + versions.length > 1 ? 's' : '' + } ${versions.map((version) => version.name).join(', ')}". +Available doc ids are: +- ${uniq(allDocs.map((versionDoc) => versionDoc.id)).join('\n- ')}`, + ); + } + return doc; + }, [docId, versions]); +} diff --git a/packages/docusaurus-theme-common/src/utils/searchUtils.ts b/packages/docusaurus-theme-common/src/utils/searchUtils.ts index 57fdb3635f9b..463c69a90fa6 100644 --- a/packages/docusaurus-theme-common/src/utils/searchUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/searchUtils.ts @@ -35,6 +35,8 @@ export function useContextualSearchFilters(): {locale: string; tags: string[]} { const activePluginAndVersion = useActivePluginAndVersion(); const docsPreferredVersionByPluginId = useDocsPreferredVersionByPluginId(); + // This can't use more specialized hooks because we are mapping over all + // plugin instances. function getDocPluginTags(pluginId: string) { const activeVersion = activePluginAndVersion?.activePlugin?.pluginId === pluginId From 04affa60b6317ed34bb7575b1b880e36680f2090 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 22:01:16 +0800 Subject: [PATCH 107/405] refactor(core): add comments for react-loadable logic (#7075) * refactor(core): add comments for react-loadable logic * fix test --- .../src/client/exports/ComponentCreator.tsx | 78 ++++++++++++------- packages/docusaurus/src/client/prefetch.ts | 16 +--- .../docusaurus/src/client/serverEntry.tsx | 4 +- .../__snapshots__/routes.test.ts.snap | 26 +++---- .../docusaurus/src/server/plugins/index.ts | 2 +- packages/docusaurus/src/server/routes.ts | 12 ++- 6 files changed, 77 insertions(+), 61 deletions(-) diff --git a/packages/docusaurus/src/client/exports/ComponentCreator.tsx b/packages/docusaurus/src/client/exports/ComponentCreator.tsx index 86c52a213ed3..7c79b3357530 100644 --- a/packages/docusaurus/src/client/exports/ComponentCreator.tsx +++ b/packages/docusaurus/src/client/exports/ComponentCreator.tsx @@ -21,77 +21,97 @@ export default function ComponentCreator( if (path === '*') { return Loadable({ loading: Loading, - loader: async () => { - const NotFound = (await import('@theme/NotFound')).default; - return (props) => ( - // Is there a better API for this? + loader: () => + import('@theme/NotFound').then(({default: NotFound}) => (props) => ( <RouteContextProvider + // Do we want a better name than native-default? value={{plugin: {name: 'native', id: 'default'}}}> <NotFound {...(props as never)} /> </RouteContextProvider> - ); - }, + )), }); } const chunkNames = routesChunkNames[`${path}-${hash}`]!; // eslint-disable-next-line @typescript-eslint/no-explicit-any - const optsLoader: {[key: string]: () => Promise<any>} = {}; - const optsModules: string[] = []; + const loader: {[key: string]: () => Promise<any>} = {}; + const modules: string[] = []; const optsWebpack: string[] = []; + // A map from prop names to chunk names. + // e.g. Suppose the plugin added this as route: + // { __comp: "...", prop: { foo: "..." }, items: ["...", "..."] } + // It will become: + // { __comp: "...", "prop.foo": "...", "items.0": "...", "items.1": ... } + // Loadable.Map will _map_ over `loader` and load each key. const flatChunkNames = flat(chunkNames); - Object.entries(flatChunkNames).forEach(([key, chunkName]) => { + Object.entries(flatChunkNames).forEach(([keyPath, chunkName]) => { const chunkRegistry = registry[chunkName]; if (chunkRegistry) { // eslint-disable-next-line prefer-destructuring - optsLoader[key] = chunkRegistry[0]; - optsModules.push(chunkRegistry[1]); + loader[keyPath] = chunkRegistry[0]; + modules.push(chunkRegistry[1]); optsWebpack.push(chunkRegistry[2]); } }); return Loadable.Map({ loading: Loading, - loader: optsLoader, - modules: optsModules, + loader, + modules, webpack: () => optsWebpack, render: (loaded, props) => { - // Clone the original object since we don't want to alter the original. + // `loaded` will be a map from key path (as returned from the flattened + // chunk names) to the modules loaded from the loaders. We now have to + // restore the chunk names' previous shape from this flat record. + // We do so by taking advantage of the existing `chunkNames` and replacing + // each chunk name with its loaded module, so we don't create another + // object from scratch. const loadedModules = JSON.parse(JSON.stringify(chunkNames)); - Object.keys(loaded).forEach((key) => { - const newComp = loaded[key].default; - if (!newComp) { + Object.entries(loaded).forEach(([keyPath, loadedModule]) => { + // JSON modules are also loaded as `{ default: ... }` (`import()` + // semantics) but we just want to pass the actual value to props. + const chunk = loadedModule.default; + // One loaded chunk can only be one of two things: a module (props) or a + // component. Modules are always JSON, so `default` always exists. This + // could only happen with a user-defined component. + if (!chunk) { throw new Error( `The page component at ${path} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`, ); } - if (typeof newComp === 'object' || typeof newComp === 'function') { - Object.keys(loaded[key]) + // A module can be a primitive, for example, if the user stored a string + // as a prop. However, there seems to be a bug with swc-loader's CJS + // logic, in that it would load a JSON module with content "foo" as + // `{ default: "foo", 0: "f", 1: "o", 2: "o" }`. Just to be safe, we + // first make sure that the chunk is non-primitive. + if (typeof chunk === 'object' || typeof chunk === 'function') { + Object.keys(loadedModule) .filter((k) => k !== 'default') .forEach((nonDefaultKey) => { - newComp[nonDefaultKey] = loaded[key][nonDefaultKey]; + chunk[nonDefaultKey] = loadedModule[nonDefaultKey]; }); } + // We now have this chunk prepared. Go down the key path and replace the + // chunk name with the actual chunk. let val = loadedModules; - const keyPath = key.split('.'); - keyPath.slice(0, -1).forEach((k) => { + const keyPaths = keyPath.split('.'); + keyPaths.slice(0, -1).forEach((k) => { val = val[k]; }); - val[keyPath[keyPath.length - 1]!] = newComp; + val[keyPaths[keyPaths.length - 1]!] = chunk; }); - const Component = loadedModules.component; - delete loadedModules.component; - /* eslint-disable no-underscore-dangle */ - const routeContextModule = loadedModules.__routeContextModule; - delete loadedModules.__routeContextModule; + const Component = loadedModules.__comp; + delete loadedModules.__comp; + const routeContext = loadedModules.__context; + delete loadedModules.__context; /* eslint-enable no-underscore-dangle */ // Is there any way to put this RouteContextProvider upper in the tree? return ( - <RouteContextProvider value={routeContextModule}> + <RouteContextProvider value={routeContext}> <Component {...loadedModules} {...props} /> </RouteContextProvider> ); diff --git a/packages/docusaurus/src/client/prefetch.ts b/packages/docusaurus/src/client/prefetch.ts index 8223c7d89d56..5c28025eef1d 100644 --- a/packages/docusaurus/src/client/prefetch.ts +++ b/packages/docusaurus/src/client/prefetch.ts @@ -5,21 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -function support(feature: string) { - if (typeof document === 'undefined') { - return false; - } - - const fakeLink = document.createElement('link'); +function supports(feature: string) { try { - if (fakeLink.relList && typeof fakeLink.relList.supports === 'function') { - return fakeLink.relList.supports(feature); - } + const fakeLink = document.createElement('link'); + return fakeLink.relList?.supports?.(feature); } catch (err) { return false; } - - return false; } function linkPrefetchStrategy(url: string) { @@ -61,7 +53,7 @@ function xhrPrefetchStrategy(url: string): Promise<void> { }); } -const supportedPrefetchStrategy = support('prefetch') +const supportedPrefetchStrategy = supports('prefetch') ? linkPrefetchStrategy : xhrPrefetchStrategy; diff --git a/packages/docusaurus/src/client/serverEntry.tsx b/packages/docusaurus/src/client/serverEntry.tsx index 32af3e4e1576..d8cbfee47d33 100644 --- a/packages/docusaurus/src/client/serverEntry.tsx +++ b/packages/docusaurus/src/client/serverEntry.tsx @@ -78,14 +78,14 @@ async function doRender(locals: Locals & {path: string}) { const location = routesLocation[locals.path]!; await preload(routes, location); const modules = new Set<string>(); - const context = {}; + const routerContext = {}; const helmetContext = {}; const linksCollector = createStatefulLinksCollector(); const appHtml = ReactDOMServer.renderToString( <Loadable.Capture report={(moduleName) => modules.add(moduleName)}> <HelmetProvider context={helmetContext}> - <StaticRouter location={location} context={context}> + <StaticRouter location={location} context={routerContext}> <LinksCollectorProvider linksCollector={linksCollector}> <App /> </LinksCollectorProvider> diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index a69dd7b18c1a..b895467529bc 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -12,8 +12,8 @@ This could lead to non-deterministic routing behavior." exports[`loadRoutes loads flat route config 1`] = ` { "registry": { - "component---theme-blog-list-pagea-6-a-7ba": { - "loader": "() => import(/* webpackChunkName: 'component---theme-blog-list-pagea-6-a-7ba' */ '@theme/BlogListPage')", + "__comp---theme-blog-list-pagea-6-a-7ba": { + "loader": "() => import(/* webpackChunkName: '__comp---theme-blog-list-pagea-6-a-7ba' */ '@theme/BlogListPage')", "modulePath": "@theme/BlogListPage", }, "content---blog-0-b-4-09e": { @@ -31,7 +31,7 @@ exports[`loadRoutes loads flat route config 1`] = ` }, "routesChunkNames": { "/blog-599": { - "component": "component---theme-blog-list-pagea-6-a-7ba", + "__comp": "__comp---theme-blog-list-pagea-6-a-7ba", "items": [ { "content": "content---blog-0-b-4-09e", @@ -71,12 +71,12 @@ export default [ exports[`loadRoutes loads nested route config 1`] = ` { "registry": { - "component---theme-doc-item-178-a40": { - "loader": "() => import(/* webpackChunkName: 'component---theme-doc-item-178-a40' */ '@theme/DocItem')", + "__comp---theme-doc-item-178-a40": { + "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-item-178-a40' */ '@theme/DocItem')", "modulePath": "@theme/DocItem", }, - "component---theme-doc-page-1-be-9be": { - "loader": "() => import(/* webpackChunkName: 'component---theme-doc-page-1-be-9be' */ '@theme/DocPage')", + "__comp---theme-doc-page-1-be-9be": { + "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-page-1-be-9be' */ '@theme/DocPage')", "modulePath": "@theme/DocPage", }, "content---docs-foo-baz-8-ce-61e": { @@ -102,16 +102,16 @@ exports[`loadRoutes loads nested route config 1`] = ` }, "routesChunkNames": { "/docs/hello-44b": { - "component": "component---theme-doc-item-178-a40", + "__comp": "__comp---theme-doc-item-178-a40", "content": "content---docs-helloaff-811", "metadata": "metadata---docs-hello-956-741", }, "/docs:route-52d": { - "component": "component---theme-doc-page-1-be-9be", + "__comp": "__comp---theme-doc-page-1-be-9be", "docsMetadata": "docsMetadata---docs-routef-34-881", }, "docs/foo/baz-070": { - "component": "component---theme-doc-item-178-a40", + "__comp": "__comp---theme-doc-item-178-a40", "content": "content---docs-foo-baz-8-ce-61e", "metadata": "metadata---docs-foo-baz-2-cf-fa7", }, @@ -159,14 +159,14 @@ export default [ exports[`loadRoutes loads route config with empty (but valid) path string 1`] = ` { "registry": { - "component---hello-world-jse-0-f-b6c": { - "loader": "() => import(/* webpackChunkName: 'component---hello-world-jse-0-f-b6c' */ 'hello/world.js')", + "__comp---hello-world-jse-0-f-b6c": { + "loader": "() => import(/* webpackChunkName: '__comp---hello-world-jse-0-f-b6c' */ 'hello/world.js')", "modulePath": "hello/world.js", }, }, "routesChunkNames": { "-b2a": { - "component": "component---hello-world-jse-0-f-b6c", + "__comp": "__comp---hello-world-jse-0-f-b6c", }, }, "routesConfig": "import React from 'react'; diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index 5fe5990cc544..d63b95589bc4 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -131,7 +131,7 @@ export async function loadPlugins(context: LoadContext): Promise<{ ...finalRouteConfig, modules: { ...finalRouteConfig.modules, - __routeContextModule: pluginRouteContextModulePath, + __context: pluginRouteContextModulePath, }, }); }, diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index 48fe2722d4ac..22fb44bbd7fc 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -151,7 +151,10 @@ const isModule = (value: unknown): value is Module => // eslint-disable-next-line no-underscore-dangle !!(value as {[key: string]: unknown})?.__import); -/** Takes a {@link Module} and returns the string path it represents. */ +/** + * Takes a {@link Module} (which is nothing more than a path plus some metadata + * like query) and returns the string path it represents. + */ function getModulePath(target: Module): string { if (typeof target === 'string') { return target; @@ -241,7 +244,7 @@ This could lead to non-deterministic routing behavior.`; /** * This is the higher level overview of route code generation. For each route - * config node, it return the node's serialized form, and mutate `registry`, + * config node, it returns the node's serialized form, and mutates `registry`, * `routesPaths`, and `routesChunkNames` accordingly. */ function genRouteCode(routeConfig: RouteConfig, res: LoadedRoutes): string { @@ -268,7 +271,8 @@ ${JSON.stringify(routeConfig)}`, const routeHash = simpleHash(JSON.stringify(routeConfig), 3); res.routesChunkNames[`${routePath}-${routeHash}`] = { - ...genChunkNames({component}, 'component', component, res), + // Avoid clash with a prop called "component" + ...genChunkNames({__comp: component}, 'component', component, res), ...genChunkNames(modules, 'module', routePath, res), }; @@ -297,7 +301,7 @@ export async function loadRoutes( ): Promise<LoadedRoutes> { handleDuplicateRoutes(routeConfigs, onDuplicateRoutes); const res: LoadedRoutes = { - // To be written + // To be written by `genRouteCode` routesConfig: '', routesChunkNames: {}, registry: {}, From bb55586c20a3477e04cedcc6b50bddadfac10431 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 30 Mar 2022 22:50:16 +0800 Subject: [PATCH 108/405] fix(website): lazy-load YT iframe (#6746) --- website/src/pages/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 6bc84ed12667..77bb4637642e 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -171,6 +171,7 @@ function VideoContainer() { frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen + loading="lazy" /> </div> </div> @@ -196,6 +197,7 @@ function Feature({ width={feature.image.width} height={feature.image.height} src={withBaseUrl(feature.image.src)} + loading="lazy" /> <h3 className={clsx(styles.featureHeading)}>{feature.title}</h3> <p className="padding-horiz--md">{feature.text}</p> From 949a72e6a56132ebd16ace7489d105441266b06a Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic <mail@lenzw.de> Date: Thu, 31 Mar 2022 09:42:57 +0200 Subject: [PATCH 109/405] perf(mdx-loader): cache mdx/remark compiler instances (#4997) * (mdx-loader) only create mdx compiler once per webpack config * type fixes * fix path * remove assertion * docs: add missing Tab/TabItem imports * fixup Co-authored-by: slorber <lorber.sebastien@gmail.com> Co-authored-by: Josh-Cena <sidachen2003@gmail.com> --- packages/docusaurus-mdx-loader/src/deps.d.ts | 22 +++--- packages/docusaurus-mdx-loader/src/index.ts | 75 ++++++++++++------- .../src/index.ts | 9 +-- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/deps.d.ts b/packages/docusaurus-mdx-loader/src/deps.d.ts index 78beb9c74562..f4adca18b3c8 100644 --- a/packages/docusaurus-mdx-loader/src/deps.d.ts +++ b/packages/docusaurus-mdx-loader/src/deps.d.ts @@ -10,19 +10,17 @@ declare module '@mdx-js/mdx' { import type {Processor} from 'unified'; import type {RemarkOrRehypePlugin} from '@docusaurus/mdx-loader'; - namespace mdx { - interface Options { - filepath?: string; - skipExport?: boolean; - wrapExport?: string; - remarkPlugins?: RemarkOrRehypePlugin[]; - rehypePlugins?: RemarkOrRehypePlugin[]; - } - - function sync(content: string, options?: Options): string; - function createMdxAstCompiler(options?: Options): Processor; - function createCompiler(options?: Options): Processor; + export interface Options { + filepath?: string; + skipExport?: boolean; + wrapExport?: string; + remarkPlugins?: RemarkOrRehypePlugin[]; + rehypePlugins?: RemarkOrRehypePlugin[]; } + + export function sync(content: string, options?: Options): string; + export function createMdxAstCompiler(options?: Options): Processor; + export function createCompiler(options?: Options): Processor; export default function mdx( content: string, options?: mdx.Options, diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index 34cea4978d23..8d6e55c79c5e 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -6,7 +6,7 @@ */ import fs from 'fs-extra'; -import mdx from '@mdx-js/mdx'; +import {createCompiler} from '@mdx-js/mdx'; import logger from '@docusaurus/logger'; import emoji from 'remark-emoji'; import { @@ -23,11 +23,18 @@ import transformImage from './remark/transformImage'; import transformLinks from './remark/transformLinks'; import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {LoaderContext} from 'webpack'; +import type {Processor} from 'unified'; const { loaders: {inlineMarkdownImageFileLoader}, } = getFileLoaderUtils(); +const pragma = ` +/* @jsxRuntime classic */ +/* @jsx mdx */ +/* @jsxFrag mdx.Fragment */ +`; + const DEFAULT_OPTIONS: MDXOptions = { rehypePlugins: [], remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc], @@ -35,6 +42,8 @@ const DEFAULT_OPTIONS: MDXOptions = { beforeDefaultRehypePlugins: [], }; +const compilerCache = new Map<string | Options, [Processor, Options]>(); + type Options = MDXOptions & { staticDirs: string[]; siteDir: string; @@ -124,38 +133,47 @@ export default async function mdxLoader( const hasFrontMatter = Object.keys(frontMatter).length > 0; - const options: Options = { - ...reqOptions, - remarkPlugins: [ - ...(reqOptions.beforeDefaultRemarkPlugins ?? []), - ...DEFAULT_OPTIONS.remarkPlugins, - [ - transformImage, - { - staticDirs: reqOptions.staticDirs, - siteDir: reqOptions.siteDir, - }, + if (!compilerCache.has(this.query)) { + const options: Options = { + ...reqOptions, + remarkPlugins: [ + ...(reqOptions.beforeDefaultRemarkPlugins ?? []), + ...DEFAULT_OPTIONS.remarkPlugins, + [ + transformImage, + { + staticDirs: reqOptions.staticDirs, + siteDir: reqOptions.siteDir, + }, + ], + [ + transformLinks, + { + staticDirs: reqOptions.staticDirs, + siteDir: reqOptions.siteDir, + }, + ], + ...(reqOptions.remarkPlugins ?? []), ], - [ - transformLinks, - { - staticDirs: reqOptions.staticDirs, - siteDir: reqOptions.siteDir, - }, + rehypePlugins: [ + ...(reqOptions.beforeDefaultRehypePlugins ?? []), + ...DEFAULT_OPTIONS.rehypePlugins, + ...(reqOptions.rehypePlugins ?? []), ], - ...(reqOptions.remarkPlugins ?? []), - ], - rehypePlugins: [ - ...(reqOptions.beforeDefaultRehypePlugins ?? []), - ...DEFAULT_OPTIONS.rehypePlugins, - ...(reqOptions.rehypePlugins ?? []), - ], - filepath: filePath, - }; + }; + compilerCache.set(this.query, [createCompiler(options), options]); + } + + const [compiler, options] = compilerCache.get(this.query)!; let result: string; try { - result = await mdx(content, options); + result = await compiler + .process({ + contents: content, + path: this.resourcePath, + }) + .then((res) => res.toString()); } catch (err) { return callback(err as Error); } @@ -214,6 +232,7 @@ ${assets ? `export const assets = ${createAssetsExportCode(assets)};` : ''} `; const code = ` +${pragma} import React from 'react'; import { mdx } from '@mdx-js/react'; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts index b16949dd72e4..19c03c4b21c5 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts @@ -6,7 +6,7 @@ */ import type {Code, Content, Literal} from 'mdast'; -import type {Plugin, Transformer} from 'unified'; +import type {Plugin} from 'unified'; import type {Node, Parent} from 'unist'; import visit from 'unist-util-visit'; import npmToYarn from 'npm-to-yarn'; @@ -61,9 +61,9 @@ const nodeForImport: Literal = { const plugin: Plugin<[PluginOptions?]> = (options = {}) => { const {sync = false} = options; - let transformed = false; - let alreadyImported = false; - const transformer: Transformer = (root) => { + return (root) => { + let transformed = false; + let alreadyImported = false; visit(root, (node: Node) => { if (isImport(node) && node.value.includes('@theme/Tabs')) { alreadyImported = true; @@ -87,7 +87,6 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => { (root as Parent).children.unshift(nodeForImport); } }; - return transformer; }; // To continue supporting `require('npm2yarn')` without the `.default` ㄟ(▔,▔)ㄏ From ce2b631455c38693983bc48fb55abaefe5e5183f Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 31 Mar 2022 15:49:07 +0800 Subject: [PATCH 110/405] fix(create): install types for JS template as well (#7078) --- .../create-docusaurus/templates/classic/docusaurus.config.js | 3 +++ packages/create-docusaurus/templates/classic/package.json | 3 +++ .../create-docusaurus/templates/facebook/docusaurus.config.js | 3 +++ packages/docusaurus-types/package.json | 2 -- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/create-docusaurus/templates/classic/docusaurus.config.js b/packages/create-docusaurus/templates/classic/docusaurus.config.js index 437d1fba1a63..58deac51c392 100644 --- a/packages/create-docusaurus/templates/classic/docusaurus.config.js +++ b/packages/create-docusaurus/templates/classic/docusaurus.config.js @@ -13,6 +13,9 @@ const config = { onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', favicon: 'img/favicon.ico', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. organizationName: 'facebook', // Usually your GitHub org/user name. projectName: 'docusaurus', // Usually your repo name. diff --git a/packages/create-docusaurus/templates/classic/package.json b/packages/create-docusaurus/templates/classic/package.json index 56e16d39efaa..30077a6ba5cd 100644 --- a/packages/create-docusaurus/templates/classic/package.json +++ b/packages/create-docusaurus/templates/classic/package.json @@ -22,6 +22,9 @@ "react": "^17.0.2", "react-dom": "^17.0.2" }, + "devDependencies": { + "@docusaurus/module-type-aliases": "2.0.0-beta.18" + }, "browserslist": { "production": [ ">0.5%", diff --git a/packages/create-docusaurus/templates/facebook/docusaurus.config.js b/packages/create-docusaurus/templates/facebook/docusaurus.config.js index a88ea59b1d5a..f63126e2fe5e 100644 --- a/packages/create-docusaurus/templates/facebook/docusaurus.config.js +++ b/packages/create-docusaurus/templates/facebook/docusaurus.config.js @@ -18,6 +18,9 @@ const config = { onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', favicon: 'img/favicon.ico', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. organizationName: 'facebook', // Usually your GitHub org/user name. projectName: 'docusaurus', // Usually your repo name. diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index df32340b1745..f708f1ea07c9 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -16,8 +16,6 @@ "test": "tsc -p ." }, "dependencies": { - "@docusaurus/react-loadable": "5.5.2", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", "commander": "^5.1.0", "history": "^4.9.0", "joi": "^17.6.0", From 24c205a83582235a91c1ff2eb0f52cb753bd875a Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 31 Mar 2022 19:16:07 +0800 Subject: [PATCH 111/405] refactor: replace non-prop interface with type; allow plugin lifecycles to have sync type (#7080) * refactor: replace non-prop interface with type; allow plugin lifecycles to have sync type * fix --- packages/docusaurus-mdx-loader/src/deps.d.ts | 4 +-- packages/docusaurus-mdx-loader/src/index.ts | 4 +-- .../src/remark/headings/index.ts | 9 +++---- .../src/remark/toc/index.ts | 4 +-- packages/docusaurus-migrate/src/types.ts | 4 +-- .../src/index.d.ts | 3 ++- .../src/__tests__/frontMatter.test.ts | 5 +++- .../src/index.ts | 2 +- .../src/plugin-content-blog.d.ts | 19 +++++++------- .../src/types.ts | 26 ++++++++++--------- .../src/__tests__/frontMatter.test.ts | 7 +++-- .../src/index.ts | 2 +- .../src/plugin-content-docs.d.ts | 4 +-- .../src/sidebars/types.ts | 19 ++++++-------- .../src/deps.d.ts | 4 +-- .../src/index.ts | 4 +-- .../docusaurus-theme-classic/src/index.ts | 2 +- .../src/contexts/docsSidebar.tsx | 14 +++++----- .../src/utils/docsUtils.tsx | 10 ++++--- .../src/utils/metadataUtils.tsx | 4 +-- .../src/utils/storageUtils.ts | 4 +-- .../src/utils/tocUtils.ts | 2 +- .../src/deps.d.ts | 4 +-- .../src/theme-live-codeblock.d.ts | 4 +-- packages/docusaurus-types/src/index.d.ts | 16 +++++++----- .../src/validationSchemas.ts | 2 +- .../src/client/PendingNavigation.tsx | 12 ++++----- .../src/client/exports/ErrorBoundary.tsx | 4 +-- packages/docusaurus/src/deps.d.ts | 8 +++--- .../src/server/plugins/synthetic.ts | 25 +++++++++--------- .../src/webpack/plugins/CleanWebpackPlugin.ts | 4 +-- .../src/webpack/plugins/WaitPlugin.ts | 4 +-- website/docs/api/plugin-methods/README.md | 4 +-- .../docs/api/plugin-methods/lifecycle-apis.md | 12 ++++----- website/docs/docusaurus-core.md | 16 ++++++------ website/src/components/Svg/index.tsx | 4 +-- .../src/components/TeamProfileCards/index.tsx | 4 +-- website/src/data/tweets.tsx | 4 +-- 38 files changed, 145 insertions(+), 138 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/deps.d.ts b/packages/docusaurus-mdx-loader/src/deps.d.ts index f4adca18b3c8..510bfc74e092 100644 --- a/packages/docusaurus-mdx-loader/src/deps.d.ts +++ b/packages/docusaurus-mdx-loader/src/deps.d.ts @@ -10,13 +10,13 @@ declare module '@mdx-js/mdx' { import type {Processor} from 'unified'; import type {RemarkOrRehypePlugin} from '@docusaurus/mdx-loader'; - export interface Options { + export type Options = { filepath?: string; skipExport?: boolean; wrapExport?: string; remarkPlugins?: RemarkOrRehypePlugin[]; rehypePlugins?: RemarkOrRehypePlugin[]; - } + }; export function sync(content: string, options?: Options): string; export function createMdxAstCompiler(options?: Options): Processor; diff --git a/packages/docusaurus-mdx-loader/src/index.ts b/packages/docusaurus-mdx-loader/src/index.ts index 8d6e55c79c5e..4991f774cf1e 100644 --- a/packages/docusaurus-mdx-loader/src/index.ts +++ b/packages/docusaurus-mdx-loader/src/index.ts @@ -182,9 +182,9 @@ export default async function mdxLoader( // Partial are not expected to have associated metadata files or front matter const isMDXPartial = options.isMDXPartial?.(filePath); if (isMDXPartial && hasFrontMatter) { - const errorMessage = `Docusaurus MDX partial files should not contain FrontMatter. + const errorMessage = `Docusaurus MDX partial files should not contain front matter. Those partial files use the _ prefix as a convention by default, but this is configurable. -File at ${filePath} contains FrontMatter that will be ignored: +File at ${filePath} contains front matter that will be ignored: ${JSON.stringify(frontMatter, null, 2)}`; if (!options.isMDXPartialFrontMatterWarningDisabled) { diff --git a/packages/docusaurus-mdx-loader/src/remark/headings/index.ts b/packages/docusaurus-mdx-loader/src/remark/headings/index.ts index c964b8d266c1..51b0cb6c7bbd 100644 --- a/packages/docusaurus-mdx-loader/src/remark/headings/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/headings/index.ts @@ -9,9 +9,8 @@ import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils'; import visit from 'unist-util-visit'; -import toString from 'mdast-util-to-string'; +import mdastToString from 'mdast-util-to-string'; import type {Transformer} from 'unified'; -import type {Parent} from 'unist'; import type {Heading, Text} from 'mdast'; export default function plugin(): Transformer { @@ -30,10 +29,8 @@ export default function plugin(): Transformer { const headingTextNodes = headingNode.children.filter( ({type}) => !['html', 'jsx'].includes(type), ); - const heading = toString( - headingTextNodes.length > 0 - ? ({children: headingTextNodes} as Parent) - : headingNode, + const heading = mdastToString( + headingTextNodes.length > 0 ? headingTextNodes : headingNode, ); // Support explicit heading IDs diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts index e733d5ab93a4..e10dbe70a3f3 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/toc/index.ts @@ -27,9 +27,9 @@ const isImport = (child: Node): child is Literal => child.type === 'import'; const hasImports = (index: number) => index > -1; const isExport = (child: Node): child is Literal => child.type === 'export'; -interface PluginOptions { +type PluginOptions = { name?: string; -} +}; const isTarget = (child: Literal, name: string) => { let found = false; diff --git a/packages/docusaurus-migrate/src/types.ts b/packages/docusaurus-migrate/src/types.ts index 8a3583fcfad2..022139f3489d 100644 --- a/packages/docusaurus-migrate/src/types.ts +++ b/packages/docusaurus-migrate/src/types.ts @@ -37,7 +37,7 @@ export type SidebarEntries = { | Array<{[key: string]: unknown} | string>; }; -export interface VersionTwoConfig { +export type VersionTwoConfig = { baseUrl: string; favicon: string; tagline?: string; @@ -93,7 +93,7 @@ export interface VersionTwoConfig { [key: string]: unknown; } )[]; -} +}; export type VersionOneConfig = { title?: string; diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 0e4b69c68759..9d98309ef69c 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -140,8 +140,9 @@ declare module '@docusaurus/Head' { declare module '@docusaurus/Link' { import type {CSSProperties, ComponentProps} from 'react'; + import type {NavLinkProps as RRNavLinkProps} from 'react-router-dom'; - type NavLinkProps = Partial<import('react-router-dom').NavLinkProps>; + type NavLinkProps = Partial<RRNavLinkProps>; export type Props = NavLinkProps & ComponentProps<'a'> & { readonly className?: string; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts index 99e3c694bfbd..cb1020c680ef 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts @@ -314,7 +314,10 @@ describe('validateBlogPostFrontMatter tags', () => { {tags: ['hello', {label: 'tagLabel', permalink: '/tagPermalink'}]}, ], invalidFrontMatters: [ - [{tags: ''}, '"tags" does not look like a valid FrontMatter Yaml array.'], + [ + {tags: ''}, + '"tags" does not look like a valid front matter Yaml array.', + ], [{tags: ['']}, 'not allowed to be empty'], ], // See https://github.com/facebook/docusaurus/issues/4642 diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index c1b8d82089ef..3414d2820a07 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -102,7 +102,7 @@ export default async function pluginContentBlog( ) as string[]; }, - async getTranslationFiles() { + getTranslationFiles() { return getTranslationFiles(options); }, diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index e7fd5a65ab88..1733bff9bc16 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -10,7 +10,7 @@ declare module '@docusaurus/plugin-content-blog' { import type {FrontMatterTag, Tag} from '@docusaurus/utils'; import type {Overwrite} from 'utility-types'; - export interface Assets { + export type Assets = { /** * If `metadata.image` is a collocated image path, this entry will be the * bundler-generated image path. Otherwise, it's empty, and the image URL @@ -25,13 +25,9 @@ declare module '@docusaurus/plugin-content-blog' { * should be accessed through `authors.imageURL`. */ authorsImageUrls: (string | undefined)[]; - } + }; - /** - * Unknown keys are allowed, so that we can pass custom fields to authors, - * e.g., `twitter`. - */ - export interface Author extends Record<string, unknown> { + export type Author = { /** * If `name` doesn't exist, an `imageURL` is expected. */ @@ -55,7 +51,12 @@ declare module '@docusaurus/plugin-content-blog' { * to generate a fallback `mailto:` URL. */ email?: string; - } + /** + * Unknown keys are allowed, so that we can pass custom fields to authors, + * e.g., `twitter`. + */ + [key: string]: unknown; + }; /** * Everything is partial/unnormalized, because front matter is always @@ -443,8 +444,6 @@ declare module '@theme/BlogPostPage' { >; export type Content = { - // TODO remove this. `metadata.frontMatter` is preferred because it can be - // accessed in enhanced plugins /** Same as `metadata.frontMatter` */ readonly frontMatter: FrontMatter; /** diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index a96390f71d51..220ddbf1d579 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -11,39 +11,41 @@ import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage'; export type BlogContentPaths = ContentPaths; -export interface BlogContent { +export type BlogContent = { blogSidebarTitle: string; blogPosts: BlogPost[]; blogListPaginated: BlogPaginated[]; blogTags: BlogTags; blogTagsListPath: string | null; -} +}; -export interface BlogTags { +export type BlogTags = { // TODO, the key is the tag slug/permalink // This is due to legacy frontmatter: tags: // [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}] // Soon we should forbid declaring permalink through frontmatter [tagKey: string]: BlogTag; -} +}; -export interface BlogTag { +export type BlogTag = { name: string; - items: string[]; // blog post permalinks + /** Blog post permalinks. */ + items: string[]; permalink: string; pages: BlogPaginated[]; -} +}; -export interface BlogPost { +export type BlogPost = { id: string; metadata: BlogPostMetadata; content: string; -} +}; -export interface BlogPaginated { +export type BlogPaginated = { metadata: BlogPaginatedMetadata; - items: string[]; // blog post permalinks -} + /** Blog post permalinks. */ + items: string[]; +}; export type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>; export type BlogMarkdownLoaderOptions = { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index 7e295afb0cb0..40f2f3f54fee 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -265,10 +265,13 @@ describe('validateDocFrontMatter tags', () => { validFrontMatters: [{}, {tags: undefined}, {tags: ['tag1', 'tag2']}], convertibleFrontMatter: [[{tags: ['tag1', 42]}, {tags: ['tag1', '42']}]], invalidFrontMatters: [ - [{tags: 42}, '"tags" does not look like a valid FrontMatter Yaml array.'], + [ + {tags: 42}, + '"tags" does not look like a valid front matter Yaml array.', + ], [ {tags: 'tag1, tag2'}, - '"tags" does not look like a valid FrontMatter Yaml array.', + '"tags" does not look like a valid front matter Yaml array.', ], [{tags: [{}]}, '"tags[0]" does not look like a valid tag'], [{tags: [true]}, '"tags[0]" does not look like a valid tag'], diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index ed35fa390c55..a0dc21768960 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -106,7 +106,7 @@ export default async function pluginContentDocs( }); }, - async getTranslationFiles({content}) { + getTranslationFiles({content}) { return getLoadedContentTranslationFiles(content); }, diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 92d375fc700a..271bfa4923db 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -10,9 +10,9 @@ declare module '@docusaurus/plugin-content-docs' { import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils'; import type {Required} from 'utility-types'; - export interface Assets { + export type Assets = { image?: string; - } + }; /** * Custom callback for parsing number prefixes from file/folder names. diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index 9f4d68a3ae45..2dfaf5b7f553 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -254,18 +254,15 @@ export type SidebarItemsGenerator = ( generatorArgs: SidebarItemsGeneratorArgs, ) => Promise<NormalizedSidebar>; -// Also inject the default generator to conveniently wrap/enhance/sort the -// default sidebar gen logic -// see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320 -export type SidebarItemsGeneratorOptionArgs = { - /** - * Useful to re-use/enhance the default sidebar generation logic from - * Docusaurus. - */ - defaultSidebarItemsGenerator: SidebarItemsGenerator; -} & SidebarItemsGeneratorArgs; export type SidebarItemsGeneratorOption = ( - generatorArgs: SidebarItemsGeneratorOptionArgs, + generatorArgs: { + /** + * Useful to re-use/enhance the default sidebar generation logic from + * Docusaurus. + * @see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320 + */ + defaultSidebarItemsGenerator: SidebarItemsGenerator; + } & SidebarItemsGeneratorArgs, ) => Promise<NormalizedSidebarItem[]>; export type SidebarProcessorParams = { diff --git a/packages/docusaurus-plugin-ideal-image/src/deps.d.ts b/packages/docusaurus-plugin-ideal-image/src/deps.d.ts index 769d0561cc60..839a35fac984 100644 --- a/packages/docusaurus-plugin-ideal-image/src/deps.d.ts +++ b/packages/docusaurus-plugin-ideal-image/src/deps.d.ts @@ -33,12 +33,12 @@ declare module '@endiliey/react-ideal-image' { | 'noicon' | 'offline'; - export interface SrcType { + export type SrcType = { width: number; src?: string; size?: number; format?: 'webp' | 'jpeg' | 'png' | 'gif'; - } + }; type ThemeKey = 'placeholder' | 'img' | 'icon' | 'noscript'; diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts index 19c03c4b21c5..0764763e9540 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts @@ -11,9 +11,9 @@ import type {Node, Parent} from 'unist'; import visit from 'unist-util-visit'; import npmToYarn from 'npm-to-yarn'; -interface PluginOptions { +type PluginOptions = { sync?: boolean; -} +}; // E.g. global install: 'npm i' -> 'yarn' const convertNpmToYarn = (npmCode: string) => npmToYarn(npmCode, 'yarn'); diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index 64f56392a45e..8aa1c7b805ad 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -118,7 +118,7 @@ export default function docusaurusThemeClassic( return '../src/theme'; }, - getTranslationFiles: async () => getTranslationFiles({themeConfig}), + getTranslationFiles: () => getTranslationFiles({themeConfig}), translateThemeConfig: (params) => translateThemeConfig({ diff --git a/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx index 2fb4d1cb0f19..56aacc9380ed 100644 --- a/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx +++ b/packages/docusaurus-theme-common/src/contexts/docsSidebar.tsx @@ -13,11 +13,11 @@ import {ReactContextError} from '../utils/reactUtils'; // Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx const EmptyContext: unique symbol = Symbol('EmptyContext'); -type SidebarContextValue = {name: string; items: PropSidebar}; +type ContextValue = {name: string; items: PropSidebar}; -const Context = React.createContext< - SidebarContextValue | null | typeof EmptyContext ->(EmptyContext); +const Context = React.createContext<ContextValue | null | typeof EmptyContext>( + EmptyContext, +); /** * Provide the current sidebar to your children. @@ -31,7 +31,7 @@ export function DocsSidebarProvider({ name: string | undefined; items: PropSidebar | undefined; }): JSX.Element { - const stableValue: SidebarContextValue | null = useMemo( + const stableValue: ContextValue | null = useMemo( () => name && items ? { @@ -45,9 +45,9 @@ export function DocsSidebarProvider({ } /** - * Gets the sidebar data that's currently displayed, or `null` if there isn't one + * Gets the sidebar that's currently displayed, or `null` if there isn't one */ -export function useDocsSidebar(): SidebarContextValue | null { +export function useDocsSidebar(): ContextValue | null { const value = useContext(Context); if (value === EmptyContext) { throw new ReactContextError('DocsSidebarProvider'); diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 64e700a48722..13e63bd44def 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -220,8 +220,9 @@ export function useDocsVersionCandidates( /** * The layout components, like navbar items, must be able to work on all pages, - * even on non-doc ones. This hook would always return a sidebar to be linked - * to. See also {@link useDocsVersionCandidates} for how this selection is done. + * even on non-doc ones where there's no version context, so a sidebar ID could + * be ambiguous. This hook would always return a sidebar to be linked to. See + * also {@link useDocsVersionCandidates} for how this selection is done. * * @throws This hook throws if a sidebar with said ID is not found. */ @@ -252,8 +253,9 @@ export function useLayoutDocsSidebar( /** * The layout components, like navbar items, must be able to work on all pages, - * even on non-doc ones. This hook would always return a doc to be linked - * to. See also {@link useDocsVersionCandidates} for how this selection is done. + * even on non-doc ones where there's no version context, so a doc ID could be + * ambiguous. This hook would always return a doc to be linked to. See also + * {@link useDocsVersionCandidates} for how this selection is done. * * @throws This hook throws if a doc with said ID is not found. */ diff --git a/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx index d7b85f0d04b3..9610faa2e40b 100644 --- a/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/metadataUtils.tsx @@ -12,13 +12,13 @@ import useRouteContext from '@docusaurus/useRouteContext'; import {useBaseUrlUtils} from '@docusaurus/useBaseUrl'; import {useTitleFormatter} from './generalUtils'; -interface PageMetadataProps { +type PageMetadataProps = { readonly title?: string; readonly description?: string; readonly keywords?: readonly string[] | string; readonly image?: string; readonly children?: ReactNode; -} +}; /** * Helper component to manipulate page metadata and override site defaults. diff --git a/packages/docusaurus-theme-common/src/utils/storageUtils.ts b/packages/docusaurus-theme-common/src/utils/storageUtils.ts index d5dcbdc8c3f5..08ab3be1aee8 100644 --- a/packages/docusaurus-theme-common/src/utils/storageUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/storageUtils.ts @@ -54,11 +54,11 @@ Possible reasons: running Docusaurus in an iframe, in an incognito browser sessi } // Convenient storage interface for a single storage key -export interface StorageSlot { +export type StorageSlot = { get: () => string | null; set: (value: string) => void; del: () => void; -} +}; const NoopStorageSlot: StorageSlot = { get: () => null, diff --git a/packages/docusaurus-theme-common/src/utils/tocUtils.ts b/packages/docusaurus-theme-common/src/utils/tocUtils.ts index c5a7fc9c6659..2b83f1a2f920 100644 --- a/packages/docusaurus-theme-common/src/utils/tocUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tocUtils.ts @@ -101,7 +101,7 @@ function filterTOC({ * to ensure that weird TOC structures preserve their semantics. For example, an * h3-h2-h4 sequence should not be treeified as an "h3 > h4" hierarchy with * min=3, max=4, but should rather be "[h3, h4]" (since the h2 heading has split - * the two headings and they are not parents) + * the two headings and they are not parent-children) */ export function useFilteredAndTreeifiedTOC({ toc, diff --git a/packages/docusaurus-theme-live-codeblock/src/deps.d.ts b/packages/docusaurus-theme-live-codeblock/src/deps.d.ts index 57918444adca..036cdb62f1b6 100644 --- a/packages/docusaurus-theme-live-codeblock/src/deps.d.ts +++ b/packages/docusaurus-theme-live-codeblock/src/deps.d.ts @@ -10,10 +10,10 @@ declare module '@philpl/buble' { // eslint-disable-next-line import/no-extraneous-dependencies, no-restricted-syntax export * from 'buble'; export const features: string[]; - export interface TransformOptions extends OriginalTransformOptions { + export type TransformOptions = OriginalTransformOptions & { transforms?: OriginalTransformOptions['transforms'] & { asyncAwait?: boolean; getterSetter?: boolean; }; - } + }; } diff --git a/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts b/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts index b377abadb66a..5bb5e51d2d26 100644 --- a/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts +++ b/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts @@ -23,9 +23,9 @@ declare module '@theme/Playground' { } declare module '@theme/ReactLiveScope' { - interface Scope { + type Scope = { [key: string]: unknown; - } + }; const ReactLiveScope: Scope; export default ReactLiveScope; diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 58969aa81136..7bc1f119a2ee 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -86,7 +86,7 @@ export type DocusaurusConfig = { | string | { src: string; - [key: string]: unknown; + [key: string]: string | boolean | undefined; } )[]; clientModules: string[]; @@ -96,7 +96,7 @@ export type DocusaurusConfig = { | string | { href: string; - [key: string]: unknown; + [key: string]: string | boolean | undefined; } )[]; titleDelimiter?: string; @@ -304,16 +304,16 @@ export type ThemeConfigValidationContext<T> = { export type Plugin<Content = unknown> = { name: string; - loadContent?: () => Promise<Content>; + loadContent?: () => Promise<Content> | Content; contentLoaded?: (args: { /** the content loaded by this plugin instance */ content: Content; // /** content loaded by ALL the plugins */ allContent: AllContent; actions: PluginContentLoadedActions; - }) => Promise<void>; + }) => Promise<void> | void; routesLoaded?: (routes: RouteConfig[]) => void; // TODO remove soon, deprecated (alpha-60) - postBuild?: (props: Props & {content: Content}) => Promise<void>; + postBuild?: (props: Props & {content: Content}) => Promise<void> | void; // TODO refactor the configureWebpack API surface: use an object instead of // multiple params (requires breaking change) configureWebpack?: ( @@ -342,8 +342,10 @@ export type Plugin<Content = unknown> = { // translations getTranslationFiles?: (args: { content: Content; - }) => Promise<TranslationFile[]>; - getDefaultCodeTranslationMessages?: () => Promise<{[id: string]: string}>; + }) => Promise<TranslationFile[]> | TranslationFile[]; + getDefaultCodeTranslationMessages?: () => + | Promise<{[id: string]: string}> + | {[id: string]: string}; translateContent?: (args: { /** The content loaded by this plugin instance. */ content: Content; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index f49b962a853b..4e6134a7b2a1 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -83,7 +83,7 @@ export const FrontMatterTagsSchema = JoiFrontMatter.array() .items(FrontMatterTagSchema) .messages({ 'array.base': - '{{#label}} does not look like a valid FrontMatter Yaml array.', + '{{#label}} does not look like a valid front matter Yaml array.', }); export const FrontMatterTOCHeadingLevels = { diff --git a/packages/docusaurus/src/client/PendingNavigation.tsx b/packages/docusaurus/src/client/PendingNavigation.tsx index 56e7e9c062b5..d9a87706a1fa 100644 --- a/packages/docusaurus/src/client/PendingNavigation.tsx +++ b/packages/docusaurus/src/client/PendingNavigation.tsx @@ -19,18 +19,18 @@ import './nprogress.css'; nprogress.configure({showSpinner: false}); -interface Props extends RouteComponentProps { +type Props = RouteComponentProps & { readonly routes: RouteConfig[]; readonly delay: number; readonly location: Location; -} -interface State { +}; +type State = { nextRouteHasLoaded: boolean; -} +}; class PendingNavigation extends React.Component<Props, State> { - previousLocation: Location | null; - progressBarTimeout: NodeJS.Timeout | null; + private previousLocation: Location | null; + private progressBarTimeout: NodeJS.Timeout | null; constructor(props: Props) { super(props); diff --git a/packages/docusaurus/src/client/exports/ErrorBoundary.tsx b/packages/docusaurus/src/client/exports/ErrorBoundary.tsx index 9b9515898a84..5fc50be15dbd 100644 --- a/packages/docusaurus/src/client/exports/ErrorBoundary.tsx +++ b/packages/docusaurus/src/client/exports/ErrorBoundary.tsx @@ -11,9 +11,9 @@ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import type {Props} from '@docusaurus/ErrorBoundary'; import DefaultFallback from '@theme/Error'; -interface State { +type State = { error: Error | null; -} +}; export default class ErrorBoundary extends React.Component<Props, State> { constructor(props: Props) { diff --git a/packages/docusaurus/src/deps.d.ts b/packages/docusaurus/src/deps.d.ts index f977549c7c7a..acaccfcebb0c 100644 --- a/packages/docusaurus/src/deps.d.ts +++ b/packages/docusaurus/src/deps.d.ts @@ -26,9 +26,9 @@ declare module 'react-loadable-ssr-addon-v5-slorber' { modulesToBeLoaded: string[], ): {js: Asset[]; css: Asset[]}; - interface ReactLoadableSSRAddon { + type ReactLoadableSSRAddon = { new (props: {filename: string}); - } + }; const plugin: ReactLoadableSSRAddon; export default plugin; @@ -47,7 +47,7 @@ declare module '@slorber/static-site-generator-webpack-plugin' { noIndex: boolean; }; - interface StaticSiteGeneratorPlugin { + type StaticSiteGeneratorPlugin = { new (props: { entry: string; locals: Locals; @@ -55,7 +55,7 @@ declare module '@slorber/static-site-generator-webpack-plugin' { preferFoldersOutput?: boolean; globals: {[key: string]: unknown}; }); - } + }; const plugin: StaticSiteGeneratorPlugin; export default plugin; diff --git a/packages/docusaurus/src/server/plugins/synthetic.ts b/packages/docusaurus/src/server/plugins/synthetic.ts index f44fad1eb3d8..67e297ffe5f5 100644 --- a/packages/docusaurus/src/server/plugins/synthetic.ts +++ b/packages/docusaurus/src/server/plugins/synthetic.ts @@ -36,26 +36,27 @@ export function createBootstrapPlugin({ return siteConfigClientModules; }, injectHtmlTags: () => { - const stylesheetsTags = stylesheets.map((source) => - typeof source === 'string' - ? `<link rel="stylesheet" href="${source}">` - : ({ - tagName: 'link', - attributes: { - rel: 'stylesheet', - ...source, + const stylesheetsTags = stylesheets.map( + (source): string | HtmlTagObject => + typeof source === 'string' + ? `<link rel="stylesheet" href="${source}">` + : { + tagName: 'link', + attributes: { + rel: 'stylesheet', + ...source, + }, }, - } as HtmlTagObject), ); - const scriptsTags = scripts.map((source) => + const scriptsTags = scripts.map((source): string | HtmlTagObject => typeof source === 'string' ? `<script src="${source}"></script>` - : ({ + : { tagName: 'script', attributes: { ...source, }, - } as HtmlTagObject), + }, ); return { headTags: [...stylesheetsTags, ...scriptsTags], diff --git a/packages/docusaurus/src/webpack/plugins/CleanWebpackPlugin.ts b/packages/docusaurus/src/webpack/plugins/CleanWebpackPlugin.ts index e6bae7173dea..46b4ca424fde 100644 --- a/packages/docusaurus/src/webpack/plugins/CleanWebpackPlugin.ts +++ b/packages/docusaurus/src/webpack/plugins/CleanWebpackPlugin.ts @@ -33,7 +33,7 @@ import type {Compiler, Stats} from 'webpack'; import path from 'path'; import {sync as delSync} from 'del'; -export interface Options { +export type Options = { /** * Write Logs to Console * (Always enabled when dry is true) @@ -65,7 +65,7 @@ export interface Options { * default: ['**\/*'] */ cleanOnceBeforeBuildPatterns?: string[]; -} +}; export default class CleanWebpackPlugin { private readonly verbose: boolean; diff --git a/packages/docusaurus/src/webpack/plugins/WaitPlugin.ts b/packages/docusaurus/src/webpack/plugins/WaitPlugin.ts index ab2130911647..2ace27913e4c 100644 --- a/packages/docusaurus/src/webpack/plugins/WaitPlugin.ts +++ b/packages/docusaurus/src/webpack/plugins/WaitPlugin.ts @@ -10,9 +10,9 @@ import fs from 'fs-extra'; import waitOn from 'wait-on'; import type {Compiler} from 'webpack'; -interface WaitPluginOptions { +type WaitPluginOptions = { filepath: string; -} +}; export default class WaitPlugin { filepath: string; diff --git a/website/docs/api/plugin-methods/README.md b/website/docs/api/plugin-methods/README.md index 0e9d816c6f6d..a59fc2059f47 100644 --- a/website/docs/api/plugin-methods/README.md +++ b/website/docs/api/plugin-methods/README.md @@ -24,13 +24,13 @@ The plugin module's default export is a constructor function with the signature `context` is plugin-agnostic, and the same object will be passed into all plugins used for a Docusaurus website. The `context` object contains the following fields: ```ts -interface LoadContext { +type LoadContext = { siteDir: string; generatedFilesDir: string; siteConfig: DocusaurusConfig; outDir: string; baseUrl: string; -} +}; ``` ### `options` {#options} diff --git a/website/docs/api/plugin-methods/lifecycle-apis.md b/website/docs/api/plugin-methods/lifecycle-apis.md index e963f401251e..bc583e8d38e0 100644 --- a/website/docs/api/plugin-methods/lifecycle-apis.md +++ b/website/docs/api/plugin-methods/lifecycle-apis.md @@ -43,17 +43,17 @@ The data that was loaded in `loadContent` will be consumed in `contentLoaded`. I Create a route to add to the website. ```ts -interface RouteConfig { +type RouteConfig = { path: string; component: string; modules?: RouteModules; routes?: RouteConfig[]; exact?: boolean; priority?: number; -} -interface RouteModules { +}; +type RouteModules = { [module: string]: Module | RouteModules | RouteModules[]; -} +}; type Module = | { path: string; @@ -339,7 +339,7 @@ function injectHtmlTags(): { type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[]; -interface HtmlTagObject { +type HtmlTagObject = { /** * Attributes of the HTML tag * E.g. `{'disabled': true, 'value': 'demo', 'rel': 'preconnect'}` @@ -355,7 +355,7 @@ interface HtmlTagObject { * The inner HTML */ innerHTML?: string; -} +}; ``` Example: diff --git a/website/docs/docusaurus-core.md b/website/docs/docusaurus-core.md index fcd35040dd0d..26316d033364 100644 --- a/website/docs/docusaurus-core.md +++ b/website/docs/docusaurus-core.md @@ -341,31 +341,31 @@ type PluginVersionInformation = | {readonly type: 'local'} | {readonly type: 'synthetic'}; -interface SiteMetadata { +type SiteMetadata = { readonly docusaurusVersion: string; readonly siteVersion?: string; readonly pluginVersions: Record<string, PluginVersionInformation>; -} +}; -interface I18nLocaleConfig { +type I18nLocaleConfig = { label: string; direction: string; -} +}; -interface I18n { +type I18n = { defaultLocale: string; locales: [string, ...string[]]; currentLocale: string; localeConfigs: Record<string, I18nLocaleConfig>; -} +}; -interface DocusaurusContext { +type DocusaurusContext = { siteConfig: DocusaurusConfig; siteMetadata: SiteMetadata; globalData: Record<string, unknown>; i18n: I18n; codeTranslations: Record<string, string>; -} +}; ``` Usage example: diff --git a/website/src/components/Svg/index.tsx b/website/src/components/Svg/index.tsx index 3fe951af3571..a37a4eddd7ed 100644 --- a/website/src/components/Svg/index.tsx +++ b/website/src/components/Svg/index.tsx @@ -9,14 +9,14 @@ import React, {type ReactNode, type ComponentProps} from 'react'; import clsx from 'clsx'; import styles from './styles.module.css'; -export interface SvgIconProps extends ComponentProps<'svg'> { +export type SvgIconProps = ComponentProps<'svg'> & { viewBox?: string; size?: 'inherit' | 'small' | 'medium' | 'large'; color?: 'inherit' | 'primary' | 'secondary' | 'success' | 'error' | 'warning'; svgClass?: string; // Class attribute on the child colorAttr?: string; // Applies a color attribute to the SVG element. children: ReactNode; // Node passed into the SVG element. -} +}; export default function Svg(props: SvgIconProps): JSX.Element { const { diff --git a/website/src/components/TeamProfileCards/index.tsx b/website/src/components/TeamProfileCards/index.tsx index 7c212fe38b39..92b6858df745 100644 --- a/website/src/components/TeamProfileCards/index.tsx +++ b/website/src/components/TeamProfileCards/index.tsx @@ -19,13 +19,13 @@ function WebsiteLink({to, children}: {to: string; children?: ReactNode}) { ); } -interface ProfileProps { +type ProfileProps = { className?: string; name: string; children: ReactNode; githubUrl?: string; twitterUrl?: string; -} +}; function TeamProfileCard({ className, diff --git a/website/src/data/tweets.tsx b/website/src/data/tweets.tsx index 9656e1a5747b..157bc0fb0e67 100644 --- a/website/src/data/tweets.tsx +++ b/website/src/data/tweets.tsx @@ -9,9 +9,9 @@ import React from 'react'; import type {Props as Tweet} from '../components/Tweet'; -export interface TweetItem extends Tweet { +export type TweetItem = Tweet & { showOnHomepage: boolean; -} +}; const TWEETS: TweetItem[] = [ { From ff966068653fb2b2ebe221a3d79126c29d4ea56f Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 31 Mar 2022 20:23:44 +0800 Subject: [PATCH 112/405] docs: fix some casing inconsistencies (#7081) --- .github/workflows/build-perf.yml | 2 +- .github/workflows/tests-e2e.yml | 8 ++++---- CHANGELOG.md | 20 +++++++++---------- README.md | 2 +- admin/publish.md | 6 +++--- admin/testing-changes-on-Docusaurus-itself.md | 2 +- packages/create-docusaurus/src/index.ts | 10 +++++----- .../__fixtures__/simple-site/sidebars.json | 2 +- .../__tests__/__snapshots__/cli.test.ts.snap | 2 +- .../__snapshots__/index.test.ts.snap | 4 ++-- .../__fixtures__/sidebars/sidebars.json | 2 +- .../__snapshots__/index.test.ts.snap | 2 +- .../src/sidebars/__tests__/validation.test.ts | 4 ++-- .../src/__tests__/validateThemeConfig.test.ts | 2 +- packages/docusaurus-utils/src/pathUtils.ts | 4 ++-- .../2021-03-09-releasing-docusaurus-i18n.md | 2 +- .../2022-01-24-docusaurus-2021-recap/index.md | 4 ++-- website/docs/advanced/plugins.md | 2 +- website/docs/deployment.mdx | 2 +- website/docs/guides/creating-pages.md | 2 +- .../markdown-features-code-blocks.mdx | 2 +- .../markdown-features-plugins.mdx | 2 +- .../markdown-features-tabs.mdx | 16 +++++++-------- website/docs/i18n/i18n-crowdin.mdx | 4 ++-- website/docs/i18n/i18n-tutorial.md | 2 +- website/docs/typescript-support.md | 4 ++-- website/src/data/users.tsx | 8 ++++---- .../version-2.0.0-beta.17/advanced/plugins.md | 2 +- .../version-2.0.0-beta.17/deployment.mdx | 2 +- .../guides/creating-pages.md | 2 +- .../markdown-features-code-blocks.mdx | 2 +- .../markdown-features-plugins.mdx | 2 +- .../markdown-features-tabs.mdx | 16 +++++++-------- .../i18n/i18n-crowdin.mdx | 4 ++-- .../i18n/i18n-tutorial.md | 2 +- .../typescript-support.md | 4 ++-- .../version-2.0.0-beta.18/advanced/plugins.md | 2 +- .../version-2.0.0-beta.18/deployment.mdx | 2 +- .../guides/creating-pages.md | 2 +- .../markdown-features-code-blocks.mdx | 2 +- .../markdown-features-plugins.mdx | 2 +- .../markdown-features-tabs.mdx | 16 +++++++-------- .../i18n/i18n-crowdin.mdx | 4 ++-- .../i18n/i18n-tutorial.md | 2 +- .../typescript-support.md | 4 ++-- 45 files changed, 97 insertions(+), 97 deletions(-) diff --git a/.github/workflows/build-perf.yml b/.github/workflows/build-perf.yml index ad7b3c5c247b..370d8a38c276 100644 --- a/.github/workflows/build-perf.yml +++ b/.github/workflows/build-perf.yml @@ -53,4 +53,4 @@ jobs: - name: Build (warm cache) run: yarn workspace website build --locale en timeout-minutes: 2 - # TODO post a Github comment with build with perf warnings? + # TODO post a GitHub comment with build with perf warnings? diff --git a/.github/workflows/tests-e2e.yml b/.github/workflows/tests-e2e.yml index 7bb9f842ffc6..dabc42f10d52 100644 --- a/.github/workflows/tests-e2e.yml +++ b/.github/workflows/tests-e2e.yml @@ -100,7 +100,7 @@ jobs: working-directory: ../test-website npm: - name: E2E — NPM + name: E2E — npm timeout-minutes: 30 runs-on: ubuntu-latest steps: @@ -114,7 +114,7 @@ jobs: run: yarn - name: Generate test-website project against main branch run: yarn test:build:website -s - - name: Install test-website project with NPM + - name: Install test-website project with npm run: npm install working-directory: ../test-website env: @@ -129,7 +129,7 @@ jobs: working-directory: ../test-website pnpm: - name: E2E — PNPM + name: E2E — pnpm timeout-minutes: 30 runs-on: ubuntu-latest steps: @@ -143,7 +143,7 @@ jobs: run: yarn - name: Generate test-website project against main branch run: yarn test:build:website -s - - name: Install test-website project with PNPM + - name: Install test-website project with pnpm run: | curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm pnpm install diff --git a/CHANGELOG.md b/CHANGELOG.md index f30ba836d46b..036b7aaa491c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -434,7 +434,7 @@ - [#6633](https://github.com/facebook/docusaurus/pull/6633) docs: improve wording of using Markdown file paths ([@BigDataWriter](https://github.com/BigDataWriter)) - [#6624](https://github.com/facebook/docusaurus/pull/6624) docs: add Resoto & Some Engineering Inc. to showcase ([@TheCatLady](https://github.com/TheCatLady)) - [#6611](https://github.com/facebook/docusaurus/pull/6611) docs: fix bad anchor link syntax ([@Josh-Cena](https://github.com/Josh-Cena)) - - [#6591](https://github.com/facebook/docusaurus/pull/6591) docs: improve Github Actions example jobs ([@ebarojas](https://github.com/ebarojas)) + - [#6591](https://github.com/facebook/docusaurus/pull/6591) docs: improve GitHub Actions example jobs ([@ebarojas](https://github.com/ebarojas)) - [#6426](https://github.com/facebook/docusaurus/pull/6426) feat(website): add Tweets section ([@yangshun](https://github.com/yangshun)) - [#6532](https://github.com/facebook/docusaurus/pull/6532) docs: add SAP Cloud SDK to showcase ([@artemkovalyov](https://github.com/artemkovalyov)) - [#6513](https://github.com/facebook/docusaurus/pull/6513) docs: clean up CONTRIBUTING ([@Josh-Cena](https://github.com/Josh-Cena)) @@ -932,7 +932,7 @@ - [#6123](https://github.com/facebook/docusaurus/pull/6123) test: use snapshots for sidebar tests ([@Josh-Cena](https://github.com/Josh-Cena)) - Other - [#6122](https://github.com/facebook/docusaurus/pull/6122) fix(website): fix yarn build:website:fast ([@slorber](https://github.com/slorber)) - - [#6080](https://github.com/facebook/docusaurus/pull/6080) chore: add NPM and PNPM to E2E tests ([@Josh-Cena](https://github.com/Josh-Cena)) + - [#6080](https://github.com/facebook/docusaurus/pull/6080) chore: add npm and pnpm to E2E tests ([@Josh-Cena](https://github.com/Josh-Cena)) - `create-docusaurus`, `docusaurus-cssnano-preset`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-plugin-debug`, `docusaurus-plugin-google-analytics`, `docusaurus-plugin-google-gtag`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-preset-classic`, `docusaurus-remark-plugin-npm2yarn`, `docusaurus-theme-classic`, `docusaurus-theme-common`, `docusaurus-theme-live-codeblock`, `docusaurus-theme-search-algolia`, `docusaurus-theme-translations`, `docusaurus-types`, `docusaurus-utils-common`, `docusaurus-utils-validation`, `docusaurus-utils`, `docusaurus`, `lqip-loader` - [#6092](https://github.com/facebook/docusaurus/pull/6092) misc: ignore some files during npm publish ([@Josh-Cena](https://github.com/Josh-Cena)) @@ -1101,7 +1101,7 @@ Bad npm publish, use beta.13 instead - [#5903](https://github.com/facebook/docusaurus/pull/5903) docs: refer to deployed branch as deployment rather than target ([@Josh-Cena](https://github.com/Josh-Cena)) - [#5902](https://github.com/facebook/docusaurus/pull/5902) fix(website): fix i18n routes for Canny board ([@Josh-Cena](https://github.com/Josh-Cena)) - [#5900](https://github.com/facebook/docusaurus/pull/5900) docs: document global variables in MDX scope ([@Josh-Cena](https://github.com/Josh-Cena)) - - [#4409](https://github.com/facebook/docusaurus/pull/4409) docs: add example for Github Pages deployment; rewrite deployment section ([@polarathene](https://github.com/polarathene)) + - [#4409](https://github.com/facebook/docusaurus/pull/4409) docs: add example for GitHub Pages deployment; rewrite deployment section ([@polarathene](https://github.com/polarathene)) - [#5888](https://github.com/facebook/docusaurus/pull/5888) docs: update GitHub deployment instructions ([@rootwork](https://github.com/rootwork)) - [#5895](https://github.com/facebook/docusaurus/pull/5895) docs: Add juffalow.com to Docusaurus showcase ([@juffalow](https://github.com/juffalow)) - [#5881](https://github.com/facebook/docusaurus/pull/5881) docs: fix wrong code sample in docusaurus-core ([@matthijsgroen](https://github.com/matthijsgroen)) @@ -1128,7 +1128,7 @@ Bad npm publish, use beta.13 instead - [#5919](https://github.com/facebook/docusaurus/pull/5919) misc(workflow): E2E tests should not be run with website changes ([@Josh-Cena](https://github.com/Josh-Cena)) - [#5907](https://github.com/facebook/docusaurus/pull/5907) chore(workflow): merge jobs into one workflow & give each job a name ([@Josh-Cena](https://github.com/Josh-Cena)) - [#5889](https://github.com/facebook/docusaurus/pull/5889) chore(website): enable eslint in website ([@Josh-Cena](https://github.com/Josh-Cena)) - - [#5870](https://github.com/facebook/docusaurus/pull/5870) chore(README): fix broken Github Actions Workflow Status icon ([@HemantSachdeva](https://github.com/HemantSachdeva)) + - [#5870](https://github.com/facebook/docusaurus/pull/5870) chore(README): fix broken GitHub Actions Workflow Status icon ([@HemantSachdeva](https://github.com/HemantSachdeva)) - `docusaurus-module-type-aliases`, `docusaurus-types`, `docusaurus` - [#6064](https://github.com/facebook/docusaurus/pull/6064) refactor(core): fix types for client code ([@Josh-Cena](https://github.com/Josh-Cena)) - `create-docusaurus`, `docusaurus-mdx-loader`, `docusaurus-migrate`, `docusaurus-plugin-client-redirects`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-ideal-image`, `docusaurus-plugin-pwa`, `docusaurus-plugin-sitemap`, `docusaurus-theme-translations`, `docusaurus-utils`, `docusaurus` @@ -3004,7 +3004,7 @@ Starting with this release for a proper work of i18n functionality, you need to - [#3976](https://github.com/facebook/docusaurus/pull/3976) docs(v2): Add AI-Speaker site to showcase page ([@asystentka-jolka](https://github.com/asystentka-jolka)) - [#3974](https://github.com/facebook/docusaurus/pull/3974) docs(v2): doc typo on sidebar admonition ([@slorber](https://github.com/slorber)) - [#3962](https://github.com/facebook/docusaurus/pull/3962) docs(v2): Add migration info doc regarding docs folder location ([@slorber](https://github.com/slorber)) - - [#3950](https://github.com/facebook/docusaurus/pull/3950) docs(v2): update Github entreprise deployment doc ([@samhrncir](https://github.com/samhrncir)) + - [#3950](https://github.com/facebook/docusaurus/pull/3950) docs(v2): update GitHub entreprise deployment doc ([@samhrncir](https://github.com/samhrncir)) - [#3945](https://github.com/facebook/docusaurus/pull/3945) docs(v2): Added information about setting `/` in routeBasePath ([@Siemienik](https://github.com/Siemienik)) - `docusaurus-theme-classic` - [#4356](https://github.com/facebook/docusaurus/pull/4356) polish(v2): [theme-classic] add Chinese translations (zh-Hant & zh-Hans) ([@MisterFISHUP](https://github.com/MisterFISHUP)) @@ -3432,7 +3432,7 @@ Starting with this release for a proper work of i18n functionality, you need to - Other - [#3769](https://github.com/facebook/docusaurus/pull/3769) docs(v2): fix statements background, update footer background ([@Simek](https://github.com/Simek)) - - [#3744](https://github.com/facebook/docusaurus/pull/3744) chore(v2): add build size bot workflow Github CI workflow ([@jcs98](https://github.com/jcs98)) + - [#3744](https://github.com/facebook/docusaurus/pull/3744) chore(v2): add build size bot workflow GitHub CI workflow ([@jcs98](https://github.com/jcs98)) - [#3741](https://github.com/facebook/docusaurus/pull/3741) chore: update yarn lock again ([@slorber](https://github.com/slorber)) - [#3740](https://github.com/facebook/docusaurus/pull/3740) chore: update yarn lock ([@slorber](https://github.com/slorber)) - [#3738](https://github.com/facebook/docusaurus/pull/3738) chore(internal): add yarn deduplicate script, cleanup lock ([@Simek](https://github.com/Simek)) @@ -3550,7 +3550,7 @@ Failed release - Other - [#3576](https://github.com/facebook/docusaurus/pull/3576) docs(v2): removed obsolete "you" identifier ([@christian-bromann](https://github.com/christian-bromann)) - [#3589](https://github.com/facebook/docusaurus/pull/3589) docs(v2): add taro to users ([@honlyHuang](https://github.com/honlyHuang)) - - [#3565](https://github.com/facebook/docusaurus/pull/3565) docs(v2): deployment, add required Github token scope infos ([@russtaylor](https://github.com/russtaylor)) + - [#3565](https://github.com/facebook/docusaurus/pull/3565) docs(v2): deployment, add required GitHub token scope infos ([@russtaylor](https://github.com/russtaylor)) - [#3574](https://github.com/facebook/docusaurus/pull/3574) docs(v2): adding vue-nodegui to users ([@shubhamzanwar](https://github.com/shubhamzanwar)) - [#3556](https://github.com/facebook/docusaurus/pull/3556) Added Axioms to users ([@abhishektiwari](https://github.com/abhishektiwari)) - [#3558](https://github.com/facebook/docusaurus/pull/3558) docs(v2): embedding real source code in MDX as a code block ([@slorber](https://github.com/slorber)) @@ -4489,7 +4489,7 @@ Bad release, check ## 2.0.0-alpha.58 - `docusaurus-theme-search-algolia` - [#2762](https://github.com/facebook/docusaurus/pull/2762) fix(v2): avoid duplication search input in navbar ([@lex111](https://github.com/lex111)) - `lqip-loader` - - [#2693](https://github.com/facebook/docusaurus/pull/2693) fix(v2): add support esModule to lqip-loader ([@ykzts](https://github.com/ykzts)) + - [#2693](https://github.com/facebook/docusaurus/pull/2693) fix(v2): add support ES Module to lqip-loader ([@ykzts](https://github.com/ykzts)) - `docusaurus-init` - [#2751](https://github.com/facebook/docusaurus/pull/2751) fix(v2): fix index page features.length when 0 ([@jdeniau](https://github.com/jdeniau)) @@ -4998,7 +4998,7 @@ Bad release, check ## 2.0.0-alpha.58 - [#2253](https://github.com/facebook/docusaurus/pull/2253) feat(v2): allow specify custom link for logo ([@lex111](https://github.com/lex111)) - [#2255](https://github.com/facebook/docusaurus/pull/2255) feat(v2): add site title to meta title ([@lex111](https://github.com/lex111)) - `docusaurus-plugin-content-pages`, `docusaurus-utils`, `docusaurus` - - [#2221](https://github.com/facebook/docusaurus/pull/2221) feat(v2): allow for Typescript pages and components ([@jonathanrdelgado](https://github.com/jonathanrdelgado)) + - [#2221](https://github.com/facebook/docusaurus/pull/2221) feat(v2): allow for TypeScript pages and components ([@jonathanrdelgado](https://github.com/jonathanrdelgado)) #### :boom: Breaking Change @@ -5623,7 +5623,7 @@ If you are still encountering the error. Please check whether you use `module.ex ## 2.0.0-alpha.24 (2019-07-24) - Remove unused metadata for pages. This minimize number of http request & smaller bundle size. -- Upgrade dependencies of css-loader from 2.x to 3.x. Css modules localIdentName hash now only use the last 4 characters instead of 8. +- Upgrade dependencies of css-loader from 2.x to 3.x. CSS modules localIdentName hash now only use the last 4 characters instead of 8. - Fix broken markdown linking replacement for mdx files - Fix potential security vulnerability because we're exposing the directory structure of the host machine. Instead of absolute path, we use relative path from site directory. Resulting in shorter webpack chunk naming and smaller bundle size. - Use contenthash instead of chunkhash for better long term caching diff --git a/README.md b/README.md index c2fe1a76ae37..310374e7621a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ <a href="#backers" alt="sponsors on Open Collective"><img src="https://opencollective.com/Docusaurus/backers/badge.svg" /></a> <a href="#sponsors" alt="Sponsors on Open Collective"><img src="https://opencollective.com/Docusaurus/sponsors/badge.svg" /></a> <a href="https://www.npmjs.com/package/@docusaurus/core"><img src="https://img.shields.io/npm/v/@docusaurus/core.svg?style=flat" alt="npm version"></a> - <a href="https://github.com/facebook/docusaurus/actions/workflows/tests.yml"><img src="https://github.com/facebook/docusaurus/actions/workflows/tests.yml/badge.svg" alt="Github Actions status"></a> + <a href="https://github.com/facebook/docusaurus/actions/workflows/tests.yml"><img src="https://github.com/facebook/docusaurus/actions/workflows/tests.yml/badge.svg" alt="GitHub Actions status"></a> <a href="CONTRIBUTING.md#pull-requests"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome"></a> <a href="https://discord.gg/docusaurus"><img src="https://img.shields.io/discord/102860784329052160.svg" align="right" alt="Discord Chat" /></a> <a href= "https://github.com/prettier/prettier"><img alt="code style: prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg"></a> diff --git a/admin/publish.md b/admin/publish.md index fef93b58796c..a46ed99e6f06 100644 --- a/admin/publish.md +++ b/admin/publish.md @@ -10,7 +10,7 @@ Get access from the Docusaurus npm admins (@yangshun/@JoelMarcey). You need publish access to **the main Docusaurus repository** (not a fork). -## NPM +## npm Publishing will only work if you are logged into npm with an account with publishing rights to the package. @@ -78,7 +78,7 @@ The `tag:` label prefix is for PRs only. Other labels are not used by the change Generate a GitHub auth token by going to https://github.com/settings/tokens (the only permission needed is `public_repo`). Save the token somewhere for future reference. -Fetch the tags from Github (lerna-changelog looks for commits since last tag by default): +Fetch the tags from GitHub (lerna-changelog looks for commits since last tag by default): ```sh git fetch --tags @@ -163,7 +163,7 @@ npm access ls-packages </pre> </details> -It can happen that some accesses are not granted, as an admin might add you to the @docusaurus NPM organization, but you don't have access to the packages that are not in that organization. +It can happen that some accesses are not granted, as an admin might add you to the @docusaurus npm organization, but you don't have access to the packages that are not in that organization. Please **double-check your permissions on these packages**, otherwise you'll publish a half-release and will have to release a new version. diff --git a/admin/testing-changes-on-Docusaurus-itself.md b/admin/testing-changes-on-Docusaurus-itself.md index 36db02d9a75d..fe9da4c63ae6 100644 --- a/admin/testing-changes-on-Docusaurus-itself.md +++ b/admin/testing-changes-on-Docusaurus-itself.md @@ -17,7 +17,7 @@ yarn start ### VS Code -Use the following code in VSCode to enable breakpoints. Please ensure you have a later version of node for non-legacy debugging. +Use the following code in VS Code to enable breakpoints. Please ensure you have a later version of node for non-legacy debugging. ```json { diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 1ca4627e7006..4358ee020303 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -55,12 +55,12 @@ function findPackageManagerFromUserAgent(): async function askForPackageManagerChoice(): Promise<SupportedPackageManager> { const hasYarn = shell.exec('yarn --version', {silent: true}).code === 0; - const hasPNPM = shell.exec('pnpm --version', {silent: true}).code === 0; + const hasPnpm = shell.exec('pnpm --version', {silent: true}).code === 0; - if (!hasYarn && !hasPNPM) { + if (!hasYarn && !hasPnpm) { return 'npm'; } - const choices = ['npm', hasYarn && 'yarn', hasPNPM && 'pnpm'] + const choices = ['npm', hasYarn && 'yarn', hasPnpm && 'pnpm'] .filter((p): p is string => Boolean(p)) .map((p) => ({title: p, value: p})); @@ -165,7 +165,7 @@ async function copyTemplate( } await fs.copy(path.resolve(templatesDir, template), dest, { - // Symlinks don't exist in published NPM packages anymore, so this is only + // Symlinks don't exist in published npm packages anymore, so this is only // to prevent errors during local testing filter: async (filePath) => !(await fs.lstat(filePath)).isSymbolicLink(), }); @@ -337,7 +337,7 @@ export default async function init( // Docusaurus templates. if (useTS) { if (!(await hasTS(template))) { - logger.error`Template name=${template} doesn't provide the Typescript variant.`; + logger.error`Template name=${template} doesn't provide the TypeScript variant.`; process.exit(1); } template = `${template}${TypeScriptTemplateSuffix}`; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json index d1e019d2e43a..7f74d2280b67 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json @@ -25,7 +25,7 @@ }, { "type": "link", - "label": "Github", + "label": "GitHub", "href": "https://github.com" }, { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap index 2f4d4e94fa34..668d5277e941 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap @@ -34,7 +34,7 @@ exports[`docsVersion first time versioning 1`] = ` }, { "href": "https://github.com", - "label": "Github", + "label": "GitHub", "type": "link", }, { diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 44346d589b45..55f087ee4e7d 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -225,7 +225,7 @@ exports[`simple website content 4`] = ` }, { "href": "https://github.com", - "label": "Github", + "label": "GitHub", "type": "link", }, { @@ -850,7 +850,7 @@ exports[`simple website content: data 1`] = ` }, { \\"type\\": \\"link\\", - \\"label\\": \\"Github\\", + \\"label\\": \\"GitHub\\", \\"href\\": \\"https://github.com\\" }, { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__fixtures__/sidebars/sidebars.json b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__fixtures__/sidebars/sidebars.json index e355c9b3f02a..b9422da7b716 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__fixtures__/sidebars/sidebars.json +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__fixtures__/sidebars/sidebars.json @@ -5,7 +5,7 @@ "foo/baz", { "type": "link", - "label": "Github", + "label": "GitHub", "href": "https://github.com" }, { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap index 42b1cd180df8..8657b009a855 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/__snapshots__/index.test.ts.snap @@ -218,7 +218,7 @@ exports[`loadSidebars sidebars with known sidebar item type 1`] = ` }, { "href": "https://github.com", - "label": "Github", + "label": "GitHub", "type": "link", }, { diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts index 96887b889c5b..c5a09a6be6f6 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts @@ -228,7 +228,7 @@ describe('validateSidebars', () => { `); }); - it('hTML type requires a value', () => { + it('html type requires a value', () => { const sidebars: SidebarsConfig = { sidebar1: [ { @@ -248,7 +248,7 @@ describe('validateSidebars', () => { `); }); - it('hTML type accepts valid values', () => { + it('html type accepts valid values', () => { const sidebars: SidebarsConfig = { sidebar1: [ { diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index d2cb4d7184bf..a333f882b58c 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -145,7 +145,7 @@ describe('themeConfig', () => { { type: 'doc', docId: 'npm', - label: 'NPM', + label: 'npm', }, { to: '/yarn', diff --git a/packages/docusaurus-utils/src/pathUtils.ts b/packages/docusaurus-utils/src/pathUtils.ts index f8380ec87d15..30db78bd7bfb 100644 --- a/packages/docusaurus-utils/src/pathUtils.ts +++ b/packages/docusaurus-utils/src/pathUtils.ts @@ -8,7 +8,7 @@ import path from 'path'; // Based on https://github.com/gatsbyjs/gatsby/pull/21518/files -// MacOS (APFS) and Windows (NTFS) filename length limit = 255 chars, +// macOS (APFS) and Windows (NTFS) filename length limit = 255 chars, // Others = 255 bytes const MAX_PATH_SEGMENT_CHARS = 255; const MAX_PATH_SEGMENT_BYTES = 255; @@ -21,7 +21,7 @@ const isWindows = () => process.platform === 'win32'; export const isNameTooLong = (str: string): boolean => // Not entirely correct: we can't assume FS from OS. But good enough? isMacOs() || isWindows() - ? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // MacOS (APFS) and Windows (NTFS) filename length limit (255 chars) + ? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // macOS (APFS) and Windows (NTFS) filename length limit (255 chars) : Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES; // Other (255 bytes) export function shortName(str: string): string { diff --git a/website/blog/2021-03-09-releasing-docusaurus-i18n.md b/website/blog/2021-03-09-releasing-docusaurus-i18n.md index 8cb0b14116f7..a7efa79d1280 100644 --- a/website/blog/2021-03-09-releasing-docusaurus-i18n.md +++ b/website/blog/2021-03-09-releasing-docusaurus-i18n.md @@ -87,7 +87,7 @@ This feature has not been an easy one, and we would like to thank everyone that - [Claire](https://github.com/clairefro) for adopting Docusaurus 2 on the new Redwood platform and providing many feedbacks - [Massoud](https://github.com/massoudmaboudi) for reviewing my work on LTR and adopting it on Datagit - [Crowdin](https://crowdin.com/) for their support and willingness to improve their translation SaaS -- The Docusaurus community for their patience, and providing many useful feedbacks on Github +- The Docusaurus community for their patience, and providing many useful feedbacks on GitHub Thanks for reading. diff --git a/website/blog/2022-01-24-docusaurus-2021-recap/index.md b/website/blog/2022-01-24-docusaurus-2021-recap/index.md index 7059860326ab..6c4c29800af4 100644 --- a/website/blog/2022-01-24-docusaurus-2021-recap/index.md +++ b/website/blog/2022-01-24-docusaurus-2021-recap/index.md @@ -34,11 +34,11 @@ Our codebase has been polished over time as well. We have improved test coverage ## Trends -### NPM +### npm Docusaurus v2 continues to grow steadily. V2 installation is now 8 times more than v1. In terms of weekly downloads, we have witnessed another three-fold increase (+209.4%), growing from 28,066 in early January to a peak of 86,846 in mid-December. -[![NPM download trend](./img/npm-trend.png)](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core) +[![npm download trend](./img/npm-trend.png)](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core) (Ah, the classic Christmas dip...) diff --git a/website/docs/advanced/plugins.md b/website/docs/advanced/plugins.md index 3e6e9f969f46..2960263eca6e 100644 --- a/website/docs/advanced/plugins.md +++ b/website/docs/advanced/plugins.md @@ -35,7 +35,7 @@ module.exports = { ### Module definition {#module-definition} -You can use a plugin as a module path referencing a separate file or NPM package: +You can use a plugin as a module path referencing a separate file or npm package: ```js title="docusaurus.config.js" module.exports = { diff --git a/website/docs/deployment.mdx b/website/docs/deployment.mdx index d2016ed0d58f..4c315902610c 100644 --- a/website/docs/deployment.mdx +++ b/website/docs/deployment.mdx @@ -522,7 +522,7 @@ jobs: ### Triggering deployment with Travis CI {#triggering-deployment-with-travis-ci} -Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to NPM, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. +Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to npm, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. 1. Go to https://github.com/settings/tokens and generate a new [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/). When creating the token, grant it the `repo` scope so that it has the permissions it needs. 2. Using your GitHub account, [add the Travis CI app](https://github.com/marketplace/travis-ci) to the repository you want to activate. diff --git a/website/docs/guides/creating-pages.md b/website/docs/guides/creating-pages.md index 160b4dbf1dec..f8745e6cbfd7 100644 --- a/website/docs/guides/creating-pages.md +++ b/website/docs/guides/creating-pages.md @@ -115,7 +115,7 @@ This is merely a recommended directory structure, and you will still need to man ::: -By default, any Markdown or Javascript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). +By default, any Markdown or JavaScript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). ```bash my-website diff --git a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx index 085d944ca429..1cdc53d72e72 100644 --- a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx @@ -534,7 +534,7 @@ If you have multiple of these multi-language code tabs, and you want to sync the ### Docusaurus npm2yarn remark plugin {#npm2yarn-remark-plugin} -Displaying CLI commands in both NPM and Yarn is a very common need, for example: +Displaying CLI commands in both npm and Yarn is a very common need, for example: ```bash npm2yarn npm install @docusaurus/remark-plugin-npm2yarn diff --git a/website/docs/guides/markdown-features/markdown-features-plugins.mdx b/website/docs/guides/markdown-features/markdown-features-plugins.mdx index 8033833585b7..7c78af39d8e8 100644 --- a/website/docs/guides/markdown-features/markdown-features-plugins.mdx +++ b/website/docs/guides/markdown-features/markdown-features-plugins.mdx @@ -124,7 +124,7 @@ The writeup below is **not** meant to be a comprehensive guide to creating a plu ::: -For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate NPM package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. +For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. ```js "src/remark/section-prefix.js" const visit = require('unist-util-visit'); diff --git a/website/docs/guides/markdown-features/markdown-features-tabs.mdx b/website/docs/guides/markdown-features/markdown-features-tabs.mdx index 062a9abe54f7..e5364735ffa2 100644 --- a/website/docs/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/docs/guides/markdown-features/markdown-features-tabs.mdx @@ -142,13 +142,13 @@ You may want choices of the same kind of tabs to sync with each other. For examp // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> ``` @@ -156,12 +156,12 @@ You may want choices of the same kind of tabs to sync with each other. For examp <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> </BrowserWindow> <br/> @@ -174,7 +174,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <TabItem value="win" label="Windows"> I am Windows. </TabItem> - <TabItem value="mac" label="MacOS"> + <TabItem value="mac" label="macOS"> I am macOS. </TabItem> <TabItem value="linux" label="Linux"> @@ -187,7 +187,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">I am Windows.</TabItem> - <TabItem value="mac" label="MacOS">I am macOS.</TabItem> + <TabItem value="mac" label="macOS">I am macOS.</TabItem> <TabItem value="linux" label="Linux">I am Linux.</TabItem> </Tabs> </BrowserWindow> @@ -201,7 +201,7 @@ Tab choices with different group IDs will not interfere with each other: // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> // highlight-next-line @@ -215,7 +215,7 @@ Tab choices with different group IDs will not interfere with each other: <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> <Tabs groupId="non-mac-operating-systems"> diff --git a/website/docs/i18n/i18n-crowdin.mdx b/website/docs/i18n/i18n-crowdin.mdx index bed65e157e04..60afe1f10b22 100644 --- a/website/docs/i18n/i18n-crowdin.mdx +++ b/website/docs/i18n/i18n-crowdin.mdx @@ -182,7 +182,7 @@ You should **not commit** it, and it may be a good idea to create a dedicated ** This tutorial uses the CLI version `3.5.2`, but we expect `3.x` releases to keep working. -Install the Crowdin CLI as an NPM package to your Docusaurus site: +Install the Crowdin CLI as an npm package to your Docusaurus site: ```bash npm2yarn npm install @crowdin/cli@3 @@ -468,7 +468,7 @@ module.exports = { if (locale !== DefaultLocale) { return `https://crowdin.com/project/docusaurus-v2/${locale}`; } - // Link to Github for English docs + // Link to GitHub for English docs return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`; }, // highlight-end diff --git a/website/docs/i18n/i18n-tutorial.md b/website/docs/i18n/i18n-tutorial.md index 477b89d5afa9..3d20fa3d865c 100644 --- a/website/docs/i18n/i18n-tutorial.md +++ b/website/docs/i18n/i18n-tutorial.md @@ -437,7 +437,7 @@ On your [static hosting provider](../deployment.mdx): :::caution -This strategy is **not possible** with Github Pages, as it is only possible to **have a single deployment**. +This strategy is **not possible** with GitHub Pages, as it is only possible to **have a single deployment**. ::: diff --git a/website/docs/typescript-support.md b/website/docs/typescript-support.md index 13f6ad57158e..25c36c2c593e 100644 --- a/website/docs/typescript-support.md +++ b/website/docs/typescript-support.md @@ -7,7 +7,7 @@ Docusaurus is written in TypeScript and provides first-class TypeScript support. ## Initialization {#initialization} -Docusaurus supports writing and using TypeScript theme components. If the init template provides a Typescript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. +Docusaurus supports writing and using TypeScript theme components. If the init template provides a TypeScript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. ```bash npx create-docusaurus@latest my-website classic --typescript @@ -104,7 +104,7 @@ module.exports = config; Type annotations are very useful and help your IDE understand the type of config objects! -The best IDEs (VSCode, WebStorm, IntelliJ...) will provide a nice auto-completion experience. +The best IDEs (VS Code, WebStorm, IntelliJ...) will provide a nice auto-completion experience. ::: diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 13343e4c0e44..56da2130b33f 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -30,7 +30,7 @@ import {sortBy} from '@site/src/utils/jsUtils'; * * Example PR: https://github.com/facebook/docusaurus/pull/3976 * - * If you edit this file through the Github interface, you can: + * If you edit this file through the GitHub interface, you can: * - Submit first your users.tsx edit PR * - This will create a branch on your Docusaurus fork (usually "patch-1") * - Go to https://github.com/<username>/docusaurus/tree/<branch>/website/src/data/showcase @@ -281,7 +281,7 @@ const Users: User[] = [ { title: 'Blog Matheus Brunelli', description: - 'Desenvolvimento de software, carreira, dicas de livros e muito Javascript!', + 'Desenvolvimento de software, carreira, dicas de livros e muito JavaScript!', preview: require('./showcase/blogmatheusbrunelli.png'), website: 'https://mrbrunelli.github.io/blog/', source: 'https://github.com/mrbrunelli/blog', @@ -624,7 +624,7 @@ const Users: User[] = [ }, { title: 'FirelordJS', - description: 'Typescript Wrapper for Firestore', + description: 'TypeScript Wrapper for Firestore', preview: require('./showcase/firelordjs.png'), website: 'https://firelordjs.com', source: 'https://github.com/tylim88/FirelordJSDoc', @@ -1008,7 +1008,7 @@ const Users: User[] = [ { title: 'Molecule', description: - 'Molecule is a lightweight Web IDE UI framework built with React.js and inspired by VSCode.', + 'Molecule is a lightweight Web IDE UI framework built with React.js and inspired by VS Code.', preview: require('./showcase/molecule-home.png'), website: 'https://dtstack.github.io/molecule/', source: 'https://github.com/DTStack/molecule/tree/main/website', diff --git a/website/versioned_docs/version-2.0.0-beta.17/advanced/plugins.md b/website/versioned_docs/version-2.0.0-beta.17/advanced/plugins.md index 3e6e9f969f46..2960263eca6e 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/advanced/plugins.md +++ b/website/versioned_docs/version-2.0.0-beta.17/advanced/plugins.md @@ -35,7 +35,7 @@ module.exports = { ### Module definition {#module-definition} -You can use a plugin as a module path referencing a separate file or NPM package: +You can use a plugin as a module path referencing a separate file or npm package: ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.0.0-beta.17/deployment.mdx b/website/versioned_docs/version-2.0.0-beta.17/deployment.mdx index d2016ed0d58f..4c315902610c 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/deployment.mdx +++ b/website/versioned_docs/version-2.0.0-beta.17/deployment.mdx @@ -522,7 +522,7 @@ jobs: ### Triggering deployment with Travis CI {#triggering-deployment-with-travis-ci} -Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to NPM, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. +Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to npm, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. 1. Go to https://github.com/settings/tokens and generate a new [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/). When creating the token, grant it the `repo` scope so that it has the permissions it needs. 2. Using your GitHub account, [add the Travis CI app](https://github.com/marketplace/travis-ci) to the repository you want to activate. diff --git a/website/versioned_docs/version-2.0.0-beta.17/guides/creating-pages.md b/website/versioned_docs/version-2.0.0-beta.17/guides/creating-pages.md index bf4c277d4a15..b7a549589328 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/guides/creating-pages.md +++ b/website/versioned_docs/version-2.0.0-beta.17/guides/creating-pages.md @@ -117,7 +117,7 @@ This is merely a recommended directory structure, and you will still need to man ::: -By default, any Markdown or Javascript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). +By default, any Markdown or JavaScript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). ```bash my-website diff --git a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-code-blocks.mdx b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-code-blocks.mdx index 7934b6ebaafb..8862a7fd50a0 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-code-blocks.mdx @@ -526,7 +526,7 @@ If you have multiple of these multi-language code tabs, and you want to sync the ### Docusaurus npm2yarn remark plugin {#npm2yarn-remark-plugin} -Displaying CLI commands in both NPM and Yarn is a very common need, for example: +Displaying CLI commands in both npm and Yarn is a very common need, for example: ```bash npm2yarn npm install @docusaurus/remark-plugin-npm2yarn diff --git a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-plugins.mdx b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-plugins.mdx index 8033833585b7..7c78af39d8e8 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-plugins.mdx +++ b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-plugins.mdx @@ -124,7 +124,7 @@ The writeup below is **not** meant to be a comprehensive guide to creating a plu ::: -For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate NPM package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. +For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. ```js "src/remark/section-prefix.js" const visit = require('unist-util-visit'); diff --git a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-tabs.mdx index 55ce040ead00..e338dcc5e70e 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.0.0-beta.17/guides/markdown-features/markdown-features-tabs.mdx @@ -142,13 +142,13 @@ You may want choices of the same kind of tabs to sync with each other. For examp // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> ``` @@ -156,12 +156,12 @@ You may want choices of the same kind of tabs to sync with each other. For examp <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> </BrowserWindow> <br/> @@ -174,7 +174,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <TabItem value="win" label="Windows"> I am Windows. </TabItem> - <TabItem value="mac" label="MacOS"> + <TabItem value="mac" label="macOS"> I am macOS. </TabItem> <TabItem value="linux" label="Linux"> @@ -187,7 +187,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">I am Windows.</TabItem> - <TabItem value="mac" label="MacOS">I am macOS.</TabItem> + <TabItem value="mac" label="macOS">I am macOS.</TabItem> <TabItem value="linux" label="Linux">I am Linux.</TabItem> </Tabs> </BrowserWindow> @@ -201,7 +201,7 @@ Tab choices with different group IDs will not interfere with each other: // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> // highlight-next-line @@ -215,7 +215,7 @@ Tab choices with different group IDs will not interfere with each other: <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> <Tabs groupId="non-mac-operating-systems"> diff --git a/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-crowdin.mdx index bed65e157e04..60afe1f10b22 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-crowdin.mdx @@ -182,7 +182,7 @@ You should **not commit** it, and it may be a good idea to create a dedicated ** This tutorial uses the CLI version `3.5.2`, but we expect `3.x` releases to keep working. -Install the Crowdin CLI as an NPM package to your Docusaurus site: +Install the Crowdin CLI as an npm package to your Docusaurus site: ```bash npm2yarn npm install @crowdin/cli@3 @@ -468,7 +468,7 @@ module.exports = { if (locale !== DefaultLocale) { return `https://crowdin.com/project/docusaurus-v2/${locale}`; } - // Link to Github for English docs + // Link to GitHub for English docs return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`; }, // highlight-end diff --git a/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-tutorial.md b/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-tutorial.md index 477b89d5afa9..3d20fa3d865c 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-tutorial.md +++ b/website/versioned_docs/version-2.0.0-beta.17/i18n/i18n-tutorial.md @@ -437,7 +437,7 @@ On your [static hosting provider](../deployment.mdx): :::caution -This strategy is **not possible** with Github Pages, as it is only possible to **have a single deployment**. +This strategy is **not possible** with GitHub Pages, as it is only possible to **have a single deployment**. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.17/typescript-support.md b/website/versioned_docs/version-2.0.0-beta.17/typescript-support.md index 3f9e09716855..abfa0ec42609 100644 --- a/website/versioned_docs/version-2.0.0-beta.17/typescript-support.md +++ b/website/versioned_docs/version-2.0.0-beta.17/typescript-support.md @@ -7,7 +7,7 @@ Docusaurus is written in TypeScript and provides first-class TypeScript support. ## Initialization {#initialization} -Docusaurus supports writing and using TypeScript theme components. If the init template provides a Typescript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. +Docusaurus supports writing and using TypeScript theme components. If the init template provides a TypeScript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. ```bash npx create-docusaurus@latest my-website classic --typescript @@ -104,7 +104,7 @@ module.exports = config; Type annotations are very useful and help your IDE understand the type of config objects! -The best IDEs (VSCode, WebStorm, IntelliJ...) will provide a nice auto-completion experience. +The best IDEs (VS Code, WebStorm, IntelliJ...) will provide a nice auto-completion experience. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md b/website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md index 3e6e9f969f46..2960263eca6e 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md +++ b/website/versioned_docs/version-2.0.0-beta.18/advanced/plugins.md @@ -35,7 +35,7 @@ module.exports = { ### Module definition {#module-definition} -You can use a plugin as a module path referencing a separate file or NPM package: +You can use a plugin as a module path referencing a separate file or npm package: ```js title="docusaurus.config.js" module.exports = { diff --git a/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx b/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx index d2016ed0d58f..4c315902610c 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/deployment.mdx @@ -522,7 +522,7 @@ jobs: ### Triggering deployment with Travis CI {#triggering-deployment-with-travis-ci} -Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to NPM, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. +Continuous integration (CI) services are typically used to perform routine tasks whenever new commits are checked in to source control. These tasks can be any combination of running unit tests and integration tests, automating builds, publishing packages to npm, and deploying changes to your website. All you need to do to automate the deployment of your website is to invoke the `yarn deploy` script whenever your website is updated. The following section covers how to do just that using [Travis CI](https://travis-ci.com/), a popular continuous integration service provider. 1. Go to https://github.com/settings/tokens and generate a new [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/). When creating the token, grant it the `repo` scope so that it has the permissions it needs. 2. Using your GitHub account, [add the Travis CI app](https://github.com/marketplace/travis-ci) to the repository you want to activate. diff --git a/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md b/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md index 160b4dbf1dec..f8745e6cbfd7 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/creating-pages.md @@ -115,7 +115,7 @@ This is merely a recommended directory structure, and you will still need to man ::: -By default, any Markdown or Javascript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). +By default, any Markdown or JavaScript file starting with `_` will be ignored and no routes will be created for that file (see the `exclude` option). ```bash my-website diff --git a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx index 085d944ca429..1cdc53d72e72 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-code-blocks.mdx @@ -534,7 +534,7 @@ If you have multiple of these multi-language code tabs, and you want to sync the ### Docusaurus npm2yarn remark plugin {#npm2yarn-remark-plugin} -Displaying CLI commands in both NPM and Yarn is a very common need, for example: +Displaying CLI commands in both npm and Yarn is a very common need, for example: ```bash npm2yarn npm install @docusaurus/remark-plugin-npm2yarn diff --git a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx index 8033833585b7..7c78af39d8e8 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-plugins.mdx @@ -124,7 +124,7 @@ The writeup below is **not** meant to be a comprehensive guide to creating a plu ::: -For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate NPM package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. +For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST. ```js "src/remark/section-prefix.js" const visit = require('unist-util-visit'); diff --git a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx index 062a9abe54f7..e5364735ffa2 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/guides/markdown-features/markdown-features-tabs.mdx @@ -142,13 +142,13 @@ You may want choices of the same kind of tabs to sync with each other. For examp // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> ``` @@ -156,12 +156,12 @@ You may want choices of the same kind of tabs to sync with each other. For examp <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + C to copy.</TabItem> + <TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem> </Tabs> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem> - <TabItem value="mac" label="MacOS">Use Command + V to paste.</TabItem> + <TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem> </Tabs> </BrowserWindow> <br/> @@ -174,7 +174,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <TabItem value="win" label="Windows"> I am Windows. </TabItem> - <TabItem value="mac" label="MacOS"> + <TabItem value="mac" label="macOS"> I am macOS. </TabItem> <TabItem value="linux" label="Linux"> @@ -187,7 +187,7 @@ For all tab groups that have the same `groupId`, the possible values do not need <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">I am Windows.</TabItem> - <TabItem value="mac" label="MacOS">I am macOS.</TabItem> + <TabItem value="mac" label="macOS">I am macOS.</TabItem> <TabItem value="linux" label="Linux">I am Linux.</TabItem> </Tabs> </BrowserWindow> @@ -201,7 +201,7 @@ Tab choices with different group IDs will not interfere with each other: // highlight-next-line <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> // highlight-next-line @@ -215,7 +215,7 @@ Tab choices with different group IDs will not interfere with each other: <BrowserWindow> <Tabs groupId="operating-systems"> <TabItem value="win" label="Windows">Windows in windows.</TabItem> - <TabItem value="mac" label="MacOS">macOS is macOS.</TabItem> + <TabItem value="mac" label="macOS">macOS is macOS.</TabItem> </Tabs> <Tabs groupId="non-mac-operating-systems"> diff --git a/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx index bed65e157e04..60afe1f10b22 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx +++ b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-crowdin.mdx @@ -182,7 +182,7 @@ You should **not commit** it, and it may be a good idea to create a dedicated ** This tutorial uses the CLI version `3.5.2`, but we expect `3.x` releases to keep working. -Install the Crowdin CLI as an NPM package to your Docusaurus site: +Install the Crowdin CLI as an npm package to your Docusaurus site: ```bash npm2yarn npm install @crowdin/cli@3 @@ -468,7 +468,7 @@ module.exports = { if (locale !== DefaultLocale) { return `https://crowdin.com/project/docusaurus-v2/${locale}`; } - // Link to Github for English docs + // Link to GitHub for English docs return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`; }, // highlight-end diff --git a/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md index 477b89d5afa9..3d20fa3d865c 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md +++ b/website/versioned_docs/version-2.0.0-beta.18/i18n/i18n-tutorial.md @@ -437,7 +437,7 @@ On your [static hosting provider](../deployment.mdx): :::caution -This strategy is **not possible** with Github Pages, as it is only possible to **have a single deployment**. +This strategy is **not possible** with GitHub Pages, as it is only possible to **have a single deployment**. ::: diff --git a/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md b/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md index 13f6ad57158e..25c36c2c593e 100644 --- a/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md +++ b/website/versioned_docs/version-2.0.0-beta.18/typescript-support.md @@ -7,7 +7,7 @@ Docusaurus is written in TypeScript and provides first-class TypeScript support. ## Initialization {#initialization} -Docusaurus supports writing and using TypeScript theme components. If the init template provides a Typescript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. +Docusaurus supports writing and using TypeScript theme components. If the init template provides a TypeScript variant, you can directly initialize a site with full TypeScript support by using the `--typescript` flag. ```bash npx create-docusaurus@latest my-website classic --typescript @@ -104,7 +104,7 @@ module.exports = config; Type annotations are very useful and help your IDE understand the type of config objects! -The best IDEs (VSCode, WebStorm, IntelliJ...) will provide a nice auto-completion experience. +The best IDEs (VS Code, WebStorm, IntelliJ...) will provide a nice auto-completion experience. ::: From 898611d4adcfc82f7acb55a7812d770d89cd0a6d Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 1 Apr 2022 13:41:39 +0800 Subject: [PATCH 113/405] refactor(core): code cleanup (#7084) --- packages/docusaurus-types/src/index.d.ts | 1 - packages/docusaurus/src/client/App.tsx | 2 +- .../index.tsx} | 24 ++++---- .../styles.module.css | 0 .../src/client/exports/BrowserOnly.tsx | 8 +-- .../src/client/exports/Interpolate.tsx | 56 ++++++++--------- .../docusaurus/src/client/exports/Link.tsx | 48 +++++++-------- .../commands/swizzle/__tests__/index.test.ts | 2 +- .../__snapshots__/routes.test.ts.snap | 60 ++++--------------- .../src/server/__tests__/routes.test.ts | 26 ++++---- packages/docusaurus/src/server/brokenLinks.ts | 2 +- packages/docusaurus/src/server/i18n.ts | 5 +- packages/docusaurus/src/server/index.ts | 25 +++----- packages/docusaurus/src/server/routes.ts | 25 ++++---- .../docusaurus/src/server/siteMetadata.ts | 3 +- packages/docusaurus/src/webpack/server.ts | 6 +- 16 files changed, 114 insertions(+), 179 deletions(-) rename packages/docusaurus/src/client/{baseUrlIssueBanner/BaseUrlIssueBanner.tsx => BaseUrlIssueBanner/index.tsx} (87%) rename packages/docusaurus/src/client/{baseUrlIssueBanner => BaseUrlIssueBanner}/styles.module.css (100%) diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 7bc1f119a2ee..7d24b70a47e7 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -227,7 +227,6 @@ export type LoadContext = { */ baseUrl: string; i18n: I18n; - ssrTemplate: string; codeTranslations: CodeTranslations; }; diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 01d74bb1cdd3..206dfb27bd7b 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -12,7 +12,7 @@ import renderRoutes from './exports/renderRoutes'; import {BrowserContextProvider} from './browserContext'; import {DocusaurusContextProvider} from './docusaurusContext'; import PendingNavigation from './PendingNavigation'; -import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner'; +import BaseUrlIssueBanner from './BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; diff --git a/packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx b/packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx similarity index 87% rename from packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx rename to packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx index 59f693931a50..3ddfaa5ed9d7 100644 --- a/packages/docusaurus/src/client/baseUrlIssueBanner/BaseUrlIssueBanner.tsx +++ b/packages/docusaurus/src/client/BaseUrlIssueBanner/index.tsx @@ -74,11 +74,11 @@ function insertBanner() { declare global { interface Window { - __DOCUSAURUS_INSERT_BASEURL_BANNER: boolean; + [InsertBannerWindowAttribute]: boolean; } } -function BaseUrlIssueBannerEnabled() { +function BaseUrlIssueBanner() { const { siteConfig: {baseUrl}, } = useDocusaurusContext(); @@ -92,6 +92,8 @@ function BaseUrlIssueBannerEnabled() { return ( <> {!ExecutionEnvironment.canUseDOM && ( + // Safe to use `ExecutionEnvironment`, because `Head` is purely + // side-effect and doesn't affect hydration <Head> <script>{createInlineScript(baseUrl)}</script> </Head> @@ -103,22 +105,22 @@ function BaseUrlIssueBannerEnabled() { /** * We want to help the users with a bad baseUrl configuration (very common - * error) Help message is inlined, and hidden if JS or CSS is able to load + * error). Help message is inlined, and hidden if JS or CSS is able to load. + * + * This component only inserts the base URL banner for the homepage, to avoid + * polluting every statically rendered page. + * * Note: it might create false positives (ie network failures): not a big deal - * Note: we only inline this for the homepage to avoid polluting all the site's - * pages + * * @see https://github.com/facebook/docusaurus/pull/3621 */ -export default function BaseUrlIssueBanner(): JSX.Element | null { +export default function MaybeBaseUrlIssueBanner(): JSX.Element | null { const { siteConfig: {baseUrl, baseUrlIssueBanner}, } = useDocusaurusContext(); const {pathname} = useLocation(); - - // returns true for the homepage during SRR + // returns true for the homepage during SSR const isHomePage = pathname === baseUrl; - const enabled = baseUrlIssueBanner && isHomePage; - - return enabled ? <BaseUrlIssueBannerEnabled /> : null; + return enabled ? <BaseUrlIssueBanner /> : null; } diff --git a/packages/docusaurus/src/client/baseUrlIssueBanner/styles.module.css b/packages/docusaurus/src/client/BaseUrlIssueBanner/styles.module.css similarity index 100% rename from packages/docusaurus/src/client/baseUrlIssueBanner/styles.module.css rename to packages/docusaurus/src/client/BaseUrlIssueBanner/styles.module.css diff --git a/packages/docusaurus/src/client/exports/BrowserOnly.tsx b/packages/docusaurus/src/client/exports/BrowserOnly.tsx index 025049b782de..16e64ef06d01 100644 --- a/packages/docusaurus/src/client/exports/BrowserOnly.tsx +++ b/packages/docusaurus/src/client/exports/BrowserOnly.tsx @@ -7,16 +7,14 @@ import React, {isValidElement} from 'react'; import useIsBrowser from '@docusaurus/useIsBrowser'; +import type {Props} from '@docusaurus/BrowserOnly'; // Similar comp to the one described here: // https://www.joshwcomeau.com/react/the-perils-of-rehydration/#abstractions export default function BrowserOnly({ children, fallback, -}: { - children: () => JSX.Element; - fallback?: JSX.Element; -}): JSX.Element | null { +}: Props): JSX.Element | null { const isBrowser = useIsBrowser(); if (isBrowser) { @@ -27,7 +25,7 @@ export default function BrowserOnly({ throw new Error(`Docusaurus error: The children of <BrowserOnly> must be a "render function", e.g. <BrowserOnly>{() => <span>{window.location.href}</span>}</BrowserOnly>. Current type: ${isValidElement(children) ? 'React element' : typeof children}`); } - return <>{children()}</>; + return <>{children?.()}</>; } return fallback ?? null; diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx index 076c7b1abc1b..99f0b76e1f09 100644 --- a/packages/docusaurus/src/client/exports/Interpolate.tsx +++ b/packages/docusaurus/src/client/exports/Interpolate.tsx @@ -18,7 +18,6 @@ We don't ship a markdown parser nor a feature-complete i18n library on purpose. More details here: https://github.com/facebook/docusaurus/pull/4295 */ -const ValueRegexp = /\{\w+\}/g; const ValueFoundMarker = '{}'; // does not care much // If all the values are plain strings, then interpolate returns a simple string @@ -39,51 +38,44 @@ export function interpolate<Str extends string, Value extends ReactNode>( ): ReactNode { const elements: (Value | string)[] = []; - const processedText = text.replace(ValueRegexp, (match: string) => { - // remove {{ and }} around the placeholder - const key = match.substring( - 1, - match.length - 1, - ) as ExtractInterpolatePlaceholders<Str>; + const processedText = text.replace( + // eslint-disable-next-line prefer-named-capture-group + /\{(\w+)\}/g, + (match, key: ExtractInterpolatePlaceholders<Str>) => { + const value = values?.[key]; - const value = values?.[key]; - - if (typeof value !== 'undefined') { - const element = isValidElement(value) - ? value - : // For non-React elements: basic primitive->string conversion - String(value); - elements.push(element); - return ValueFoundMarker; - } - return match; // no match? add warning? - }); + if (typeof value !== 'undefined') { + const element = isValidElement(value) + ? value + : // For non-React elements: basic primitive->string conversion + String(value); + elements.push(element); + return ValueFoundMarker; + } + return match; // no match? add warning? + }, + ); // No interpolation to be done: just return the text if (elements.length === 0) { return text; } // Basic string interpolation: returns interpolated string - if (elements.every((el) => typeof el === 'string')) { + if (elements.every((el): el is string => typeof el === 'string')) { return processedText .split(ValueFoundMarker) .reduce<string>( - (str, value, index) => - str.concat(value).concat((elements[index] as string) ?? ''), + (str, value, index) => str.concat(value).concat(elements[index] ?? ''), '', ); } // JSX interpolation: returns ReactNode - return processedText.split(ValueFoundMarker).reduce<ReactNode[]>( - (array, value, index) => [ - ...array, - <React.Fragment key={index}> - {value} - {elements[index]} - </React.Fragment>, - ], - [], - ); + return processedText.split(ValueFoundMarker).map((value, index) => ( + <React.Fragment key={index}> + {value} + {elements[index]} + </React.Fragment> + )); } export default function Interpolate<Str extends string>({ diff --git a/packages/docusaurus/src/client/exports/Link.tsx b/packages/docusaurus/src/client/exports/Link.tsx index 6850f237611f..53da88a7913d 100644 --- a/packages/docusaurus/src/client/exports/Link.tsx +++ b/packages/docusaurus/src/client/exports/Link.tsx @@ -103,35 +103,29 @@ function Link( const IOSupported = ExecutionEnvironment.canUseIntersectionObserver; const ioRef = useRef<IntersectionObserver>(); - const handleIntersection = (el: HTMLAnchorElement, cb: () => void) => { - ioRef.current = new window.IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (el === entry.target) { - // If element is in viewport, stop observing and run callback. - // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API - if (entry.isIntersecting || entry.intersectionRatio > 0) { - ioRef.current!.unobserve(el); - ioRef.current!.disconnect(); - cb(); - } - } - }); - }); - // Add element to the observer. - ioRef.current!.observe(el); - }; + const handleRef = (el: HTMLAnchorElement | null) => { + innerRef.current = el; - const handleRef = (ref: HTMLAnchorElement | null) => { - innerRef.current = ref; - - if (IOSupported && ref && isInternal) { + if (IOSupported && el && isInternal) { // If IO supported and element reference found, set up Observer. - handleIntersection(ref, () => { - if (targetLink != null) { - window.docusaurus.prefetch(targetLink); - } + ioRef.current = new window.IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (el === entry.target) { + // If element is in viewport, stop observing and run callback. + // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API + if (entry.isIntersecting || entry.intersectionRatio > 0) { + ioRef.current!.unobserve(el); + ioRef.current!.disconnect(); + if (targetLink != null) { + window.docusaurus.prefetch(targetLink); + } + } + } + }); }); + // Add element to the observer. + ioRef.current.observe(el); } }; @@ -161,8 +155,8 @@ function Link( const isAnchorLink = targetLink?.startsWith('#') ?? false; const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink; - if (targetLink && isInternal && !isAnchorLink && !noBrokenLinkCheck) { - linksCollector.collectLink(targetLink); + if (!isRegularHtmlLink && !noBrokenLinkCheck) { + linksCollector.collectLink(targetLink!); } return isRegularHtmlLink ? ( diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts index 7faa5c74c91f..0f55edac837d 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/index.test.ts @@ -91,7 +91,7 @@ async function createTestSite() { const siteThemePathPosix = posixPath(siteThemePath); expect(tree(siteThemePathPosix)).toMatchSnapshot('theme dir tree'); - const files = Globby.sync(siteThemePathPosix) + const files = (await Globby(siteThemePathPosix)) .map((file) => path.posix.relative(siteThemePathPosix, file)) .sort(); diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index b895467529bc..80de4e006fca 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -12,22 +12,10 @@ This could lead to non-deterministic routing behavior." exports[`loadRoutes loads flat route config 1`] = ` { "registry": { - "__comp---theme-blog-list-pagea-6-a-7ba": { - "loader": "() => import(/* webpackChunkName: '__comp---theme-blog-list-pagea-6-a-7ba' */ '@theme/BlogListPage')", - "modulePath": "@theme/BlogListPage", - }, - "content---blog-0-b-4-09e": { - "loader": "() => import(/* webpackChunkName: 'content---blog-0-b-4-09e' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true')", - "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true", - }, - "content---blog-7-b-8-fd9": { - "loader": "() => import(/* webpackChunkName: 'content---blog-7-b-8-fd9' */ 'blog/2018-12-14-Happy-First-Birthday-Slash.md')", - "modulePath": "blog/2018-12-14-Happy-First-Birthday-Slash.md", - }, - "metadata---blog-0-b-6-74c": { - "loader": "() => import(/* webpackChunkName: 'metadata---blog-0-b-6-74c' */ 'blog-2018-12-14-happy-first-birthday-slash-d2c.json')", - "modulePath": "blog-2018-12-14-happy-first-birthday-slash-d2c.json", - }, + "__comp---theme-blog-list-pagea-6-a-7ba": "@theme/BlogListPage", + "content---blog-0-b-4-09e": "blog/2018-12-14-Happy-First-Birthday-Slash.md?truncated=true", + "content---blog-7-b-8-fd9": "blog/2018-12-14-Happy-First-Birthday-Slash.md", + "metadata---blog-0-b-6-74c": "blog-2018-12-14-happy-first-birthday-slash-d2c.json", }, "routesChunkNames": { "/blog-599": { @@ -71,34 +59,13 @@ export default [ exports[`loadRoutes loads nested route config 1`] = ` { "registry": { - "__comp---theme-doc-item-178-a40": { - "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-item-178-a40' */ '@theme/DocItem')", - "modulePath": "@theme/DocItem", - }, - "__comp---theme-doc-page-1-be-9be": { - "loader": "() => import(/* webpackChunkName: '__comp---theme-doc-page-1-be-9be' */ '@theme/DocPage')", - "modulePath": "@theme/DocPage", - }, - "content---docs-foo-baz-8-ce-61e": { - "loader": "() => import(/* webpackChunkName: 'content---docs-foo-baz-8-ce-61e' */ 'docs/foo/baz.md')", - "modulePath": "docs/foo/baz.md", - }, - "content---docs-helloaff-811": { - "loader": "() => import(/* webpackChunkName: 'content---docs-helloaff-811' */ 'docs/hello.md')", - "modulePath": "docs/hello.md", - }, - "docsMetadata---docs-routef-34-881": { - "loader": "() => import(/* webpackChunkName: 'docsMetadata---docs-routef-34-881' */ 'docs-b5f.json')", - "modulePath": "docs-b5f.json", - }, - "metadata---docs-foo-baz-2-cf-fa7": { - "loader": "() => import(/* webpackChunkName: 'metadata---docs-foo-baz-2-cf-fa7' */ 'docs-foo-baz-dd9.json')", - "modulePath": "docs-foo-baz-dd9.json", - }, - "metadata---docs-hello-956-741": { - "loader": "() => import(/* webpackChunkName: 'metadata---docs-hello-956-741' */ 'docs-hello-da2.json')", - "modulePath": "docs-hello-da2.json", - }, + "__comp---theme-doc-item-178-a40": "@theme/DocItem", + "__comp---theme-doc-page-1-be-9be": "@theme/DocPage", + "content---docs-foo-baz-8-ce-61e": "docs/foo/baz.md", + "content---docs-helloaff-811": "docs/hello.md", + "docsMetadata---docs-routef-34-881": "docs-b5f.json", + "metadata---docs-foo-baz-2-cf-fa7": "docs-foo-baz-dd9.json", + "metadata---docs-hello-956-741": "docs-hello-da2.json", }, "routesChunkNames": { "/docs/hello-44b": { @@ -159,10 +126,7 @@ export default [ exports[`loadRoutes loads route config with empty (but valid) path string 1`] = ` { "registry": { - "__comp---hello-world-jse-0-f-b6c": { - "loader": "() => import(/* webpackChunkName: '__comp---hello-world-jse-0-f-b6c' */ 'hello/world.js')", - "modulePath": "hello/world.js", - }, + "__comp---hello-world-jse-0-f-b6c": "hello/world.js", }, "routesChunkNames": { "-b2a": { diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index faf37563fd94..1e8062a69632 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -101,7 +101,7 @@ describe('handleDuplicateRoutes', () => { }); describe('loadRoutes', () => { - it('loads nested route config', async () => { + it('loads nested route config', () => { const nestedRouteConfig: RouteConfig = { component: '@theme/DocPage', path: '/docs:route', @@ -135,12 +135,10 @@ describe('loadRoutes', () => { }, ], }; - await expect( - loadRoutes([nestedRouteConfig], '/', 'ignore'), - ).resolves.toMatchSnapshot(); + expect(loadRoutes([nestedRouteConfig], '/', 'ignore')).toMatchSnapshot(); }); - it('loads flat route config', async () => { + it('loads flat route config', () => { const flatRouteConfig: RouteConfig = { path: '/blog', component: '@theme/BlogListPage', @@ -169,17 +167,15 @@ describe('loadRoutes', () => { ], }, }; - await expect( - loadRoutes([flatRouteConfig], '/', 'ignore'), - ).resolves.toMatchSnapshot(); + expect(loadRoutes([flatRouteConfig], '/', 'ignore')).toMatchSnapshot(); }); - it('rejects invalid route config', async () => { + it('rejects invalid route config', () => { const routeConfigWithoutPath = { component: 'hello/world.js', } as RouteConfig; - await expect(loadRoutes([routeConfigWithoutPath], '/', 'ignore')).rejects + expect(() => loadRoutes([routeConfigWithoutPath], '/', 'ignore')) .toThrowErrorMatchingInlineSnapshot(` "Invalid route config: path must be a string and component is required. {\\"component\\":\\"hello/world.js\\"}" @@ -189,21 +185,19 @@ describe('loadRoutes', () => { path: '/hello/world', } as RouteConfig; - await expect(loadRoutes([routeConfigWithoutComponent], '/', 'ignore')) - .rejects.toThrowErrorMatchingInlineSnapshot(` + expect(() => loadRoutes([routeConfigWithoutComponent], '/', 'ignore')) + .toThrowErrorMatchingInlineSnapshot(` "Invalid route config: path must be a string and component is required. {\\"path\\":\\"/hello/world\\"}" `); }); - it('loads route config with empty (but valid) path string', async () => { + it('loads route config with empty (but valid) path string', () => { const routeConfig = { path: '', component: 'hello/world.js', } as RouteConfig; - await expect( - loadRoutes([routeConfig], '/', 'ignore'), - ).resolves.toMatchSnapshot(); + expect(loadRoutes([routeConfig], '/', 'ignore')).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts index c213ca19ef84..c8806fa842af 100644 --- a/packages/docusaurus/src/server/brokenLinks.ts +++ b/packages/docusaurus/src/server/brokenLinks.ts @@ -53,7 +53,7 @@ function getPageBrokenLinks({ // component, but we load route components with string paths. // We don't actually access component here, so it's fine. .map((l) => matchRoutes(routes, l)) - .reduce((prev, cur) => prev.concat(cur)); + .flat(); return matchedRoutes.length === 0; } diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts index e171b21f78aa..b2d5dfe570cc 100644 --- a/packages/docusaurus/src/server/i18n.ts +++ b/packages/docusaurus/src/server/i18n.ts @@ -51,9 +51,8 @@ Note: Docusaurus only support running one locale at a time.`; }; } - const localeConfigs = locales.reduce( - (acc, locale) => ({...acc, [locale]: getLocaleConfig(locale)}), - {}, + const localeConfigs = Object.fromEntries( + locales.map((locale) => [locale, getLocaleConfig(locale)]), ); return { diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index fecb98e3111f..e971d1326313 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -16,7 +16,6 @@ import { import _ from 'lodash'; import path from 'path'; import {loadSiteConfig} from './config'; -import ssrDefaultTemplate from '../webpack/templates/ssr.html.template'; import {loadClientModules} from './clientModules'; import {loadPlugins} from './plugins'; import {loadRoutes} from './routes'; @@ -101,7 +100,6 @@ export async function loadContext( outDir, baseUrl, i18n, - ssrTemplate: siteConfig.ssrTemplate ?? ssrDefaultTemplate, codeTranslations, }; } @@ -122,18 +120,16 @@ export async function load(options: LoadContextOptions): Promise<Props> { outDir, baseUrl, i18n, - ssrTemplate, codeTranslations: siteCodeTranslations, } = context; const {plugins, pluginsRouteConfigs, globalData} = await loadPlugins(context); const clientModules = loadClientModules(plugins); const {headTags, preBodyTags, postBodyTags} = loadHtmlTags(plugins); - const {registry, routesChunkNames, routesConfig, routesPaths} = - await loadRoutes( - pluginsRouteConfigs, - baseUrl, - siteConfig.onDuplicateRoutes, - ); + const {registry, routesChunkNames, routesConfig, routesPaths} = loadRoutes( + pluginsRouteConfigs, + baseUrl, + siteConfig.onDuplicateRoutes, + ); const codeTranslations = { ...(await getPluginsDefaultCodeTranslationMessages(plugins)), ...siteCodeTranslations, @@ -153,8 +149,6 @@ next build. You can clear all build artifacts (including this folder) with the `, ); - // Site config must be generated after plugins - // We want the generated config to have been normalized by the plugins! const genSiteConfig = generate( generatedFilesDir, DEFAULT_CONFIG_FILE_NAME, @@ -174,7 +168,7 @@ export default ${JSON.stringify(siteConfig, null, 2)}; ${clientModules // import() is async so we use require() because client modules can have // CSS and the order matters for loading CSS. - .map((module) => ` require('${escapePath(module)}'),`) + .map((clientModule) => ` require('${escapePath(clientModule)}'),`) .join('\n')} ]; `, @@ -187,10 +181,8 @@ ${clientModules ${Object.entries(registry) .sort((a, b) => a[0].localeCompare(b[0])) .map( - ([key, chunk]) => - ` '${key}': [${chunk.loader}, '${escapePath( - chunk.modulePath, - )}', require.resolveWeak('${escapePath(chunk.modulePath)}')],`, + ([chunkName, modulePath]) => + ` '${chunkName}': [() => import(/* webpackChunkName: '${chunkName}' */ '${modulePath}'), '${modulePath}', require.resolveWeak('${modulePath}')],`, ) .join('\n')}}; `, @@ -256,7 +248,6 @@ ${Object.entries(registry) headTags, preBodyTags, postBodyTags, - ssrTemplate, codeTranslations, }; } diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index 22fb44bbd7fc..6350e2166069 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -29,9 +29,12 @@ type LoadedRoutes = { routesConfig: string; /** @see {ChunkNames} */ routesChunkNames: RouteChunkNames; - /** A map from chunk name to module loaders. */ + /** + * A map from chunk name to module paths. Module paths would have backslash + * escaped already, so they can be directly printed. + */ registry: { - [chunkName: string]: {loader: string; modulePath: string}; + [chunkName: string]: string; }; /** * Collect all page paths for injecting it later in the plugin lifecycle. @@ -195,12 +198,7 @@ function genChunkNames( // This is a leaf node, no need to recurse const modulePath = getModulePath(routeModule); const chunkName = genChunkName(modulePath, prefix, name); - res.registry[chunkName] = { - loader: `() => import(/* webpackChunkName: '${chunkName}' */ '${escapePath( - modulePath, - )}')`, - modulePath, - }; + res.registry[chunkName] = escapePath(modulePath); return chunkName; } if (Array.isArray(routeModule)) { @@ -294,11 +292,11 @@ ${JSON.stringify(routeConfig)}`, * chunk names. * - `registry`, a mapping from chunk names to options for react-loadable. */ -export async function loadRoutes( +export function loadRoutes( routeConfigs: RouteConfig[], baseUrl: string, onDuplicateRoutes: ReportingSeverity, -): Promise<LoadedRoutes> { +): LoadedRoutes { handleDuplicateRoutes(routeConfigs, onDuplicateRoutes); const res: LoadedRoutes = { // To be written by `genRouteCode` @@ -308,11 +306,16 @@ export async function loadRoutes( routesPaths: [normalizeUrl([baseUrl, '404.html'])], }; + // `genRouteCode` would mutate `res` + const routeConfigSerialized = routeConfigs + .map((r) => genRouteCode(r, res)) + .join(',\n'); + res.routesConfig = `import React from 'react'; import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ -${indent(`${routeConfigs.map((r) => genRouteCode(r, res)).join(',\n')},`)} +${indent(routeConfigSerialized)}, { path: '*', component: ComponentCreator('*'), diff --git a/packages/docusaurus/src/server/siteMetadata.ts b/packages/docusaurus/src/server/siteMetadata.ts index 199dbc034a6b..ec855f94d57b 100644 --- a/packages/docusaurus/src/server/siteMetadata.ts +++ b/packages/docusaurus/src/server/siteMetadata.ts @@ -81,8 +81,7 @@ function checkDocusaurusPackagesVersion(siteMetadata: SiteMetadata) { versionInfo.version && versionInfo.version !== docusaurusVersion ) { - // should we throw instead? - // It still could work with different versions + // Should we throw instead? It still could work with different versions logger.error`Invalid name=${plugin} version number=${versionInfo.version}. All official @docusaurus/* packages should have the exact same version as @docusaurus/core (number=${docusaurusVersion}). Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`; diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts index 3adc362a41da..93cb258c3489 100644 --- a/packages/docusaurus/src/webpack/server.ts +++ b/packages/docusaurus/src/webpack/server.ts @@ -14,6 +14,7 @@ import {createBaseConfig} from './base'; import WaitPlugin from './plugins/WaitPlugin'; import LogPlugin from './plugins/LogPlugin'; import {NODE_MAJOR_VERSION, NODE_MINOR_VERSION} from '@docusaurus/utils'; +import ssrDefaultTemplate from './templates/ssr.html.template'; // Forked for Docusaurus: https://github.com/slorber/static-site-generator-webpack-plugin import StaticSiteGeneratorPlugin from '@slorber/static-site-generator-webpack-plugin'; @@ -32,8 +33,7 @@ export default async function createServerConfig({ headTags, preBodyTags, postBodyTags, - ssrTemplate, - siteConfig: {noIndex, trailingSlash}, + siteConfig: {noIndex, trailingSlash, ssrTemplate}, } = props; const config = await createBaseConfig(props, true); @@ -73,7 +73,7 @@ export default async function createServerConfig({ preBodyTags, postBodyTags, onLinksCollected, - ssrTemplate, + ssrTemplate: ssrTemplate ?? ssrDefaultTemplate, noIndex, }, paths: ssgPaths, From c7c0ee4e7cd06cd96cd7538918abced60ecbb66c Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sat, 2 Apr 2022 08:32:26 +0800 Subject: [PATCH 114/405] chore: upgrade dependencies (#7101) --- package.json | 4 +- .../docusaurus-cssnano-preset/package.json | 2 +- packages/docusaurus-mdx-loader/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/docusaurus-plugin-pwa/package.json | 2 +- packages/docusaurus-types/package.json | 2 +- packages/docusaurus-utils/package.json | 2 +- packages/docusaurus/package.json | 4 +- packages/docusaurus/src/client/App.tsx | 2 +- .../src/client/PendingNavigation.tsx | 2 +- ...tcher.ts => clientLifecyclesDispatcher.ts} | 0 packages/docusaurus/src/client/docusaurus.ts | 3 +- website/package.json | 2 +- yarn.lock | 401 +++++++++--------- 17 files changed, 218 insertions(+), 218 deletions(-) rename packages/docusaurus/src/client/{client-lifecycles-dispatcher.ts => clientLifecyclesDispatcher.ts} (100%) diff --git a/package.json b/package.json index 6c2fe7139a60..bc377a1193fb 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@babel/core": "^7.17.8", "@babel/preset-typescript": "^7.16.7", "@crowdin/cli": "^3.7.8", - "@swc/core": "^1.2.161", + "@swc/core": "^1.2.162", "@swc/jest": "^0.2.20", "@testing-library/react-hooks": "^7.0.2", "@types/fs-extra": "^9.0.13", @@ -81,7 +81,7 @@ "@typescript-eslint/parser": "^5.17.0", "concurrently": "^7.0.0", "cross-env": "^7.0.3", - "cspell": "^5.19.3", + "cspell": "^5.19.5", "eslint": "^8.12.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json index 4b9948e77d90..a9f9a60f5aa8 100644 --- a/packages/docusaurus-cssnano-preset/package.json +++ b/packages/docusaurus-cssnano-preset/package.json @@ -13,7 +13,7 @@ "directory": "packages/docusaurus-cssnano-preset" }, "dependencies": { - "cssnano-preset-advanced": "^5.3.1", + "cssnano-preset-advanced": "^5.3.3", "postcss": "^8.4.12", "postcss-sort-media-queries": "^4.2.1" }, diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 366bdf8cf5c7..53045923733a 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -33,7 +33,7 @@ "tslib": "^2.3.1", "unist-util-visit": "^2.0.3", "url-loader": "^4.1.1", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "devDependencies": { "@docusaurus/types": "2.0.0-beta.18", diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json index 4dffa1a94040..ce84f9efee94 100644 --- a/packages/docusaurus-plugin-content-blog/package.json +++ b/packages/docusaurus-plugin-content-blog/package.json @@ -32,7 +32,7 @@ "remark-admonitions": "^1.2.1", "tslib": "^2.3.1", "utility-types": "^3.10.0", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "devDependencies": { "@docusaurus/types": "2.0.0-beta.18", diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index c080891df07f..ef4f5ee27a0e 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -36,7 +36,7 @@ "remark-admonitions": "^1.2.1", "tslib": "^2.3.1", "utility-types": "^3.10.0", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.18", diff --git a/packages/docusaurus-plugin-content-pages/package.json b/packages/docusaurus-plugin-content-pages/package.json index 8cc6de8765f0..742ee2eee7bf 100644 --- a/packages/docusaurus-plugin-content-pages/package.json +++ b/packages/docusaurus-plugin-content-pages/package.json @@ -25,7 +25,7 @@ "fs-extra": "^10.0.1", "remark-admonitions": "^1.2.1", "tslib": "^2.3.1", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "devDependencies": { "@docusaurus/types": "2.0.0-beta.18" diff --git a/packages/docusaurus-plugin-ideal-image/package.json b/packages/docusaurus-plugin-ideal-image/package.json index 18044e5c43ad..a444b98dd566 100644 --- a/packages/docusaurus-plugin-ideal-image/package.json +++ b/packages/docusaurus-plugin-ideal-image/package.json @@ -30,7 +30,7 @@ "react-waypoint": "^10.1.0", "sharp": "^0.30.3", "tslib": "^2.3.1", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "2.0.0-beta.18", diff --git a/packages/docusaurus-plugin-pwa/package.json b/packages/docusaurus-plugin-pwa/package.json index 3150d85f7df8..9ba4396cd74c 100644 --- a/packages/docusaurus-plugin-pwa/package.json +++ b/packages/docusaurus-plugin-pwa/package.json @@ -32,7 +32,7 @@ "core-js": "^3.21.1", "terser-webpack-plugin": "^5.3.1", "tslib": "^2.3.1", - "webpack": "^5.70.0", + "webpack": "^5.70.1", "webpack-merge": "^5.8.0", "workbox-build": "^6.5.2", "workbox-precaching": "^6.5.2", diff --git a/packages/docusaurus-types/package.json b/packages/docusaurus-types/package.json index f708f1ea07c9..e7089ea7b121 100644 --- a/packages/docusaurus-types/package.json +++ b/packages/docusaurus-types/package.json @@ -20,7 +20,7 @@ "history": "^4.9.0", "joi": "^17.6.0", "utility-types": "^3.10.0", - "webpack": "^5.70.0", + "webpack": "^5.70.1", "webpack-merge": "^5.8.0" } } diff --git a/packages/docusaurus-utils/package.json b/packages/docusaurus-utils/package.json index 51435bb08ab7..17fac997a89b 100644 --- a/packages/docusaurus-utils/package.json +++ b/packages/docusaurus-utils/package.json @@ -32,7 +32,7 @@ "shelljs": "^0.8.5", "tslib": "^2.3.1", "url-loader": "^4.1.1", - "webpack": "^5.70.0" + "webpack": "^5.70.1" }, "engines": { "node": ">=14" diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 544e9a85e7b1..4a3d85800443 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -63,7 +63,7 @@ "core-js": "^3.21.1", "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", - "cssnano": "^5.1.5", + "cssnano": "^5.1.7", "del": "^6.0.0", "detect-port": "^1.3.0", "escape-html": "^1.0.3", @@ -98,7 +98,7 @@ "update-notifier": "^5.1.0", "url-loader": "^4.1.1", "wait-on": "^6.0.1", - "webpack": "^5.70.0", + "webpack": "^5.70.1", "webpack-bundle-analyzer": "^4.5.0", "webpack-dev-server": "^4.7.4", "webpack-merge": "^5.8.0", diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 206dfb27bd7b..a970bb3ded35 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -17,7 +17,7 @@ import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; -import './client-lifecycles-dispatcher'; +import './clientLifecyclesDispatcher'; // TODO, quick fix for CSS insertion order import ErrorBoundary from '@docusaurus/ErrorBoundary'; diff --git a/packages/docusaurus/src/client/PendingNavigation.tsx b/packages/docusaurus/src/client/PendingNavigation.tsx index d9a87706a1fa..71ad30b12332 100644 --- a/packages/docusaurus/src/client/PendingNavigation.tsx +++ b/packages/docusaurus/src/client/PendingNavigation.tsx @@ -10,7 +10,7 @@ import {Route, withRouter, type RouteComponentProps} from 'react-router-dom'; import type {RouteConfig} from 'react-router-config'; import nprogress from 'nprogress'; -import clientLifecyclesDispatcher from './client-lifecycles-dispatcher'; +import clientLifecyclesDispatcher from './clientLifecyclesDispatcher'; import preload from './preload'; import normalizeLocation from './normalizeLocation'; import type {Location} from 'history'; diff --git a/packages/docusaurus/src/client/client-lifecycles-dispatcher.ts b/packages/docusaurus/src/client/clientLifecyclesDispatcher.ts similarity index 100% rename from packages/docusaurus/src/client/client-lifecycles-dispatcher.ts rename to packages/docusaurus/src/client/clientLifecyclesDispatcher.ts diff --git a/packages/docusaurus/src/client/docusaurus.ts b/packages/docusaurus/src/client/docusaurus.ts index 1ee1605b1a35..caff0722fb5a 100644 --- a/packages/docusaurus/src/client/docusaurus.ts +++ b/packages/docusaurus/src/client/docusaurus.ts @@ -90,4 +90,5 @@ const docusaurus = { }, }; -export default docusaurus; +// This object is directly mounted onto window, better freeze it +export default Object.freeze(docusaurus); diff --git a/website/package.json b/website/package.json index cfbed1d06b70..8964bd1a3f24 100644 --- a/website/package.json +++ b/website/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@crowdin/cli": "^3.7.8", - "@crowdin/crowdin-api-client": "^1.15.0", + "@crowdin/crowdin-api-client": "^1.15.1", "@docusaurus/core": "2.0.0-beta.18", "@docusaurus/logger": "2.0.0-beta.18", "@docusaurus/plugin-client-redirects": "2.0.0-beta.18", diff --git a/yarn.lock b/yarn.lock index 5974ee3c406f..4b70d12c21a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1325,17 +1325,17 @@ njre "^0.2.0" shelljs "^0.8.4" -"@crowdin/crowdin-api-client@^1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@crowdin/crowdin-api-client/-/crowdin-api-client-1.15.0.tgz#e38eeef43f5e8c1f3918191a271252e7045807d5" - integrity sha512-qoWJZSKp0e3bmGbuBIm7H5nvZL1bGTqXkQlDvhuioGwtDQvqodgQGMqLtNGWd1CQtYwUcGE15Fs+FHMuSgRIlw== +"@crowdin/crowdin-api-client@^1.15.1": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@crowdin/crowdin-api-client/-/crowdin-api-client-1.15.1.tgz#ef2248e95c129a1af34a2a8a84eeec8904fb8d03" + integrity sha512-upbL+ie+Mv02EpekjEIzgjqJwn43YZSBrt+E5LKRStWOWR6NYULSnNxqTsR5OGUZpCUryL2hHUUimqGxFg82wg== dependencies: axios "0.21.3" -"@cspell/cspell-bundled-dicts@^5.19.3": - version "5.19.3" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.3.tgz#826e166eb56f193c2d770575adfbb1557816f1af" - integrity sha512-YAz68AgXTFFtrBUhNJlOQ7KOjUE6ncYt578/esa2GStMJHgJoUtPnOZsE41hh+cVWXqO5yRRI+Qkwub99zLMgQ== +"@cspell/cspell-bundled-dicts@^5.19.5": + version "5.19.5" + resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.19.5.tgz#09906e24a13dd919ba9e19d0b7a93e9ef2383d28" + integrity sha512-qXW99H+S/529cTOtRBTPiTV1Ay+I2+kcF5lfVblSRsij7fBM6d99dB3Fg6oL0i6okRwOUNFAV4qbxgg7zxA3wA== dependencies: "@cspell/dict-ada" "^2.0.0" "@cspell/dict-aws" "^2.0.0" @@ -1377,15 +1377,15 @@ "@cspell/dict-typescript" "^2.0.0" "@cspell/dict-vue" "^2.0.2" -"@cspell/cspell-pipe@^5.19.3": - version "5.19.3" - resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.19.3.tgz#af818c0362786f61ac8741947e1819f94b55ec3b" - integrity sha512-3RKntgGRxYYzoxoH3VBPvnNMYkHKPq0U+U7qogcWxDkgAUgKXlBP0oc2mw96grJQ4HIzOL1vBnaVAWAqteY9Kw== +"@cspell/cspell-pipe@^5.19.5": + version "5.19.5" + resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-5.19.5.tgz#e780d22523d94317f0462683ba61c39a486919a8" + integrity sha512-dNCMYDgjeWKw7KIptjxHu17UfeT3oiqQk6LkSyi3BewUxpnlLLO7EsxR6GRW+RVU/MrPXe7BF9WgF0gO8m+8cQ== -"@cspell/cspell-types@^5.19.3": - version "5.19.3" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.19.3.tgz#37a64db00e33a1c8bb8aa3bf86d503689b3afbf5" - integrity sha512-tub7PW/I6qB6o+ZtlahAZjm5O5cnzj88HRiC8nAbJFpa7q0mrdpFMYhd7ksWtyFLlNbuDkCsfzXGamAhIQnnIw== +"@cspell/cspell-types@^5.19.5": + version "5.19.5" + resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-5.19.5.tgz#10801d6298f60539d244f3256ad5b5e26f3ea5d3" + integrity sha512-tOzCzuQQ4DdgfnI6+FGBPOVL/1JbH0pWtoOinPoU93/pH29XOKGW2I24HLeESzgskfoZGK274wMFQfGp6oJw9g== "@cspell/dict-ada@^2.0.0": version "2.0.0" @@ -2905,10 +2905,10 @@ rollup-plugin-node-polyfills "^0.2.1" rollup-plugin-terser "^7.0.2" -"@netlify/plugins-list@^6.17.0": - version "6.18.0" - resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.18.0.tgz#5338079577db61c9b35d726201ee6723fb9e93f5" - integrity sha512-aDcWLHPVqAOwtS5e/kj2jqWLVdKQrHPc7Wj6nxH6aiTuzp85ELRXW4rPEWrvibio5lbeYaNBhCTw/sHKUVYIcg== +"@netlify/plugins-list@^6.17.0", "@netlify/plugins-list@^6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@netlify/plugins-list/-/plugins-list-6.18.1.tgz#f96396c818b98c6c59c6b081b0484daff76fb4e2" + integrity sha512-4aAF+lpoBYOIVMuTxge2YNjNKdMxnsV1equq0VtknBW6EGJ9yFiTPyL0NU0MXDWTWk7dNu8tS5+Uw7LN7+sgcg== "@netlify/routing-local-proxy-darwin-arm64@^0.34.1": version "0.34.1" @@ -3486,89 +3486,89 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" -"@swc/core-android-arm-eabi@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.161.tgz#3a723984a51705a6360fefc7c7efb5a7681c8f3f" - integrity sha512-SYm08FusdMo70JaKEYE7GpJHVp020iqPL3FjYEmQ+iyhc0Id8RlMeFt7ZtIj0aYHPKudR3GljzG5FVJXmm1Iuw== - -"@swc/core-android-arm64@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.161.tgz#4d9e1b2d6a42ee767fda8ee7d46f059ab001ff0b" - integrity sha512-zk+GgVGKwIO9PsUcLZ7tG1XGGBJ/xyv5Or9/R0rQArBTGS5mvSK4d+9XrItQph8i3ECZhik3PuexmR7us6ysCw== - -"@swc/core-darwin-arm64@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.161.tgz#bdef41c63d905a1da094c6756f09ca3ff19644d1" - integrity sha512-pf65TWy9oFkWCRzRq16Ec6rglurdajWT5tv1E93Kh4izEFLvKN/Mp+8EMnqOcoAn+HEtjzp2R6NosBruV/d1Ww== - -"@swc/core-darwin-x64@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.161.tgz#96980fb8c3207f8305457864241c4a942b4d9903" - integrity sha512-QdgsY+BjYO0ngSIwR/xZn6W3iP0E/+of38Afon3maANDiKzvzsvyZm4IVTznOaxG1ZUJ/q1oKeRV/DcW7QvHiw== - -"@swc/core-freebsd-x64@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.161.tgz#8b41d589a04c1236ab0d6163cca548574925cae4" - integrity sha512-yApHncnlQNQINxxcz+Y+svlrdU3d/yaJ769eoThIQXsZTL0Il3gnhhkjJkMEigLTexpQZQOGjgYnV9HKkpYqkw== - -"@swc/core-linux-arm-gnueabihf@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.161.tgz#4d475d57fdccaab900d88195e2b4e1b990e45e21" - integrity sha512-DGSKqKSBQ42mAMmPhWkfgzXaci4RU0XgmnO1bFVkl8Yw9TaxBBBeCbLIBYJik4DehOOYic9gtXZIfEs90+oc2w== - -"@swc/core-linux-arm64-gnu@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.161.tgz#e528dd661ed85f9069a5792536a2f784cab377f8" - integrity sha512-wdEPjBLuf0bUMafURrUN11MOGs7PHnedWOFAfvyRuNf4HdfwbS2nYDpFCL4mklN8BuprxvRFWfoA+ROigexK4g== - -"@swc/core-linux-arm64-musl@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.161.tgz#928dc578ba5cd8bb26decee62d150c565a09f1f5" - integrity sha512-EPwDDlAIchv1FG1Vc2ArUGsX2b87LSEXHjF59TuOj+oXOANHnFRQa/28wHpeMYN5lHYmyjMplfn37XYLMo8BDw== - -"@swc/core-linux-x64-gnu@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.161.tgz#c13866ef8a1eade5bf9b9b0f0be4b90d69970f10" - integrity sha512-UE+8n2PLCojxywQd1nPbMcus/3zLQjg05Oozrvl1IkHBssk89tk2GhLujUwbFS+MoGFPKAmL+wT+9lXHavK7Og== - -"@swc/core-linux-x64-musl@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.161.tgz#dd171b5357a5e34ece729e4aba528c15cfe4727b" - integrity sha512-mkshCdRhS5s1w1Koph/kS8EJVEmrq+/p4iLsLDozXi1RL16lzk5SYn4ppmzF/Zj9OpgJ+Nzk7kNcZMMJMVIwqw== - -"@swc/core-win32-arm64-msvc@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.161.tgz#e8e7cb5bac7319525ba297e4a2819dafc44f98d6" - integrity sha512-5ZMhPSeFJO+h0Ejoq766S25VvrooUW0RdhfcG2u7OFqhdlTXHlvryL7jdf6tILltmJxNWeAGrNE8YI+ARolTeQ== - -"@swc/core-win32-ia32-msvc@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.161.tgz#938e66e731f2d72b3dcf8af963c36a807f46286b" - integrity sha512-/c+L8bYCjg8pbx3Jbgx9Cns9nlLUpB4CmugfIdlW+2EdncyZyKu+u+D0egnOjvtlxe8BNw0889oH1Lv4p7KuhA== - -"@swc/core-win32-x64-msvc@1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.161.tgz#f95a8ebe77fe35a1b9e87b52628b870a706b43be" - integrity sha512-FXzZXf+kXvqgZFd+dIzD8Pcc22yejm/XNvpGTy9HZHWYLvlif+QSXrNgvX1oyMWZYT+NCVHwebKjS9FTnTMi9w== - -"@swc/core@^1.2.161": - version "1.2.161" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.161.tgz#bbc79daeb33c1436df8eac58994dc0b73480a02f" - integrity sha512-RXv1y2HDqZ4gAjdvqV0KL1Oms8vUkDgXRU5SPOEa3zMzMDNKHvRfoiBk4ZyaGzhGcr0zflqT4EADKgTB8RFNsw== +"@swc/core-android-arm-eabi@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.162.tgz#4c1e252487b4bb09985fe700314862112a63daed" + integrity sha512-mQSuLspB1qBAYXyDP0Da60tPumhwD0CIm7tMjAFiOplEJN+9YKBlZ3EV9Xc1wF5bdWzJpmzmqEdN9FEfOQqlwQ== + +"@swc/core-android-arm64@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.162.tgz#b4b10093361b01f4a05fbd4ff6aa89facbe4a8b8" + integrity sha512-9TuuTrsrxbw1W1xUfcmRuEIKImJC725S/4McSFpoylYRIoHzD1DPpgP4fquU0/fzq7rldVD1tu4tg3xvEL8auw== + +"@swc/core-darwin-arm64@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.162.tgz#f411db74aa8bb082d3290cf7a0062b2597cfe112" + integrity sha512-gWJjD7NqKVxGFSJ4BeTXfBpRRRkxaQcWmmkwoXDQ1tmLRUX6K3V8MXp41mTdg7jJWDyKq4VTN6D8zLQcCUEhmQ== + +"@swc/core-darwin-x64@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.162.tgz#171cdf214424bbdee0a38b8afb459ca15a3e6e6a" + integrity sha512-+3foKCmxiMuPp1UCIPUg3N8CuzFRDPoPEQagz3TKT8W7Bkv9SXeIL8LPuwfH970rIcx1Ie/Q2UWXJwbckVmMHQ== + +"@swc/core-freebsd-x64@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.162.tgz#1ed4dabdf786453e2734ddf5fd28b87a4f458d84" + integrity sha512-YdfQgALPwJ6ZCvfqLlytCvZG/r/ZgBlOa0gaZvMGl6WMpnWgoVPA5OYBA5qzstg/OEWjMu6fldi+lElsvq8v2Q== + +"@swc/core-linux-arm-gnueabihf@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.162.tgz#fbf9c23143ce399568da368be8efe4550ca0fc5f" + integrity sha512-4elULEP2JWvSpEEI7JmhoI25cRQ2/ffBtf3+4vLlcAgJCdCrkYvHJO2fbWlN1fpydj34QabMsOROYS4ff4p0Og== + +"@swc/core-linux-arm64-gnu@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.162.tgz#995b72647822cf5c13b713b12ded888e25598836" + integrity sha512-ZgR1J8H4qI7EuADgHEeDBtiiF8yt6vrznVtaBvEInDPdV9W10QNKsTqhuFkTfOqaHAO2u1+MkZRuvALGahdDaQ== + +"@swc/core-linux-arm64-musl@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.162.tgz#d1dbd5f19202090369cc224a583db7782e6a6d01" + integrity sha512-1Egev+v8wlr7zPaS715sG7flzbGE0OLtcCR7p7oUqD/NbKwlA6czMch5JwNWvdRMjLThTYEeJ/ID+/xG8BqXUg== + +"@swc/core-linux-x64-gnu@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.162.tgz#2bec4d2727d99d7391447d6a380d1aff3bc96fb6" + integrity sha512-LFWV+8h6S3KmzVgHXRYpGYsaytGt+Vrbm8554ugUdzk465JnHyKzw3e6VRcJTxAGgXa+o1qUEkeBg7Wc/WWkmQ== + +"@swc/core-linux-x64-musl@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.162.tgz#2f0f228aef29d1f9f77dab6ca3b2f605494425b9" + integrity sha512-q5insucuYBVCjpDp8/EG3dbt2PFwGAo2vFzofr/lOlOo9p90jCzFRL0+eXg4Ar1YG6BL+T9o5LhFRggY+YHIBg== + +"@swc/core-win32-arm64-msvc@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.162.tgz#6726f1f855340b6b3ceb4b4d6673b89d65571781" + integrity sha512-xzksaPOqB3a8gxLoE0ZMi5w2NX9zzYDylmM3qbCVqft6IZid2XFG2lPFIwxJV1xfW68xMgAe0IECnjp/nQsS8g== + +"@swc/core-win32-ia32-msvc@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.162.tgz#246b875c6b4c38f77f471d581671528514d5c206" + integrity sha512-hUvS7UaSW+h16SSH7GwH571L2GnqWHPsiSKIDUvv1b/lca7dLcCY8RzsKafB/GLU+5EBQIN3nab3nH0vOWRkvw== + +"@swc/core-win32-x64-msvc@1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.162.tgz#ed06ab10518cc77bb1705f579c011a019250cd8f" + integrity sha512-Eb0SehVYWO5TpYeaPAD3T3iIPpgJa1q/rmvgMDvL0hi4UnOJlvj43kC4Dhuor6opLd6fJkCS7gBq9SxtGtb8bQ== + +"@swc/core@^1.2.161", "@swc/core@^1.2.162": + version "1.2.162" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.162.tgz#a40ef92676f9a2eeee9f30389b7e9fdbe103059d" + integrity sha512-MFBmoV2qgGvi5bPX1tH3NLtWV4exa5jTCkC/30mdP5PTwEsxKJ5u+m1fuYOlgzDiBlytx8AihVZy2TmXhWZByw== optionalDependencies: - "@swc/core-android-arm-eabi" "1.2.161" - "@swc/core-android-arm64" "1.2.161" - "@swc/core-darwin-arm64" "1.2.161" - "@swc/core-darwin-x64" "1.2.161" - "@swc/core-freebsd-x64" "1.2.161" - "@swc/core-linux-arm-gnueabihf" "1.2.161" - "@swc/core-linux-arm64-gnu" "1.2.161" - "@swc/core-linux-arm64-musl" "1.2.161" - "@swc/core-linux-x64-gnu" "1.2.161" - "@swc/core-linux-x64-musl" "1.2.161" - "@swc/core-win32-arm64-msvc" "1.2.161" - "@swc/core-win32-ia32-msvc" "1.2.161" - "@swc/core-win32-x64-msvc" "1.2.161" + "@swc/core-android-arm-eabi" "1.2.162" + "@swc/core-android-arm64" "1.2.162" + "@swc/core-darwin-arm64" "1.2.162" + "@swc/core-darwin-x64" "1.2.162" + "@swc/core-freebsd-x64" "1.2.162" + "@swc/core-linux-arm-gnueabihf" "1.2.162" + "@swc/core-linux-arm64-gnu" "1.2.162" + "@swc/core-linux-arm64-musl" "1.2.162" + "@swc/core-linux-x64-gnu" "1.2.162" + "@swc/core-linux-x64-musl" "1.2.162" + "@swc/core-win32-arm64-msvc" "1.2.162" + "@swc/core-win32-ia32-msvc" "1.2.162" + "@swc/core-win32-x64-msvc" "1.2.162" "@swc/jest@^0.2.20": version "0.2.20" @@ -5093,7 +5093,7 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.1.3, array-includes@^3.1.4: +array-includes@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== @@ -5955,9 +5955,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: - version "1.0.30001322" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz#2e4c09d11e1e8f852767dab287069a8d0c29d623" - integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== + version "1.0.30001323" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz#a451ff80dec7033016843f532efda18f02eec011" + integrity sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA== caseless@~0.12.0: version "0.12.0" @@ -6160,9 +6160,9 @@ class-utils@^0.3.5: static-extend "^0.1.1" clean-css@^5.2.2, clean-css@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.4.tgz#982b058f8581adb2ae062520808fb2429bd487a4" - integrity sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.0.tgz#ad3d8238d5f3549e83d5f87205189494bc7cbb59" + integrity sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ== dependencies: source-map "~0.6.0" @@ -7004,41 +7004,41 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -cspell-gitignore@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.19.3.tgz#c27780dc1b43cb48705dc3695c3875f001d7b038" - integrity sha512-Q67uHcf0qNgOoanRLhatapjWpLiftT+MuLIyAaSLe5eNVzQurQIc+UnXhtaslkVyOTqQt4NJFqLgtf5ZSGz1bg== +cspell-gitignore@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-5.19.5.tgz#42e1fbdeabb7bfce073a111d1d77f22dd31253d7" + integrity sha512-Wj16pnPmx7PGd2PcVAEsxWnTtfY4qNzUBtfTqo5VEd23WME6SgEtffxm4eSRpHYZmmDclir+Tbb9yQAsZajDeQ== dependencies: - cspell-glob "^5.19.3" + cspell-glob "^5.19.5" find-up "^5.0.0" -cspell-glob@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.19.3.tgz#f6b423523a0c2d77d244ecfc7c48ef320f4d122a" - integrity sha512-qp2Oe/euzTu3e0zZrQxHuTrqRo418tYfh4CnCa+DKU6lWKKcF4zCEhOGJHPsYak8SFIXZ4ZE360wHFxB/JDutQ== +cspell-glob@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-5.19.5.tgz#a25ef16ed91b876bd9764dbedf5ac3ae101bf071" + integrity sha512-fnrUNLNY9CMsr5J1wRPoGpx7aastD05wEZ/NL+Xd7uEmuU+R7gViOjyOPlUMFH+YARwY0youHRiobkl7pJNngw== dependencies: - micromatch "^4.0.4" + micromatch "^4.0.5" -cspell-io@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.19.3.tgz#89ab249dc53206651a7833399a83b04a7d8a8a63" - integrity sha512-dE9eBvHgIJ11DelWtyehMU3W3bCpcB+0nS6uOZJ2d8fDu13m5BebpLrXZ2dKfY4cjksJUhRPatt14uwQSeUp2A== +cspell-io@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-5.19.5.tgz#e44eeda1b8083b666f4ab9940e0d167b4fa2040a" + integrity sha512-R6q1Dor6mfs1VBpuXVlcm/Vvr96GclO/BtNDK/8ppcm22Ct1VF24MG2itoYO7296dOgR1H4HkndvvEgx3p8fzw== -cspell-lib@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.19.3.tgz#6efc9ee5620d427e2f20c000b60a3b3d0ce6cd4c" - integrity sha512-peMJggwJpxCXKZZ0DuHyDtZmf66POKaHf5Im8LGEyMKFARUIq6O2WvaUGggYjyRe3Ng/f5G+EYTcIHbF9pZYcg== +cspell-lib@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-5.19.5.tgz#653242ec9b06005f478d8f8f0fdb00f4c6c1dadd" + integrity sha512-6HOJ7O+vDYzJs49fHZI5xzsL5TxeR7WsfjWvx1BwgRs1rHdA9/8KFZFX2DJazKRGm+kL1kBO0VJlaF0tvVsjzw== dependencies: - "@cspell/cspell-bundled-dicts" "^5.19.3" - "@cspell/cspell-pipe" "^5.19.3" - "@cspell/cspell-types" "^5.19.3" + "@cspell/cspell-bundled-dicts" "^5.19.5" + "@cspell/cspell-pipe" "^5.19.5" + "@cspell/cspell-types" "^5.19.5" clear-module "^4.1.2" comment-json "^4.2.2" configstore "^5.0.1" cosmiconfig "^7.0.1" - cspell-glob "^5.19.3" - cspell-io "^5.19.3" - cspell-trie-lib "^5.19.3" + cspell-glob "^5.19.5" + cspell-io "^5.19.5" + cspell-trie-lib "^5.19.5" fast-equals "^3.0.0" find-up "^5.0.0" fs-extra "^10.0.1" @@ -7049,27 +7049,26 @@ cspell-lib@^5.19.3: vscode-languageserver-textdocument "^1.0.4" vscode-uri "^3.0.3" -cspell-trie-lib@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.19.3.tgz#0a0f8d9300f95188f2f2b1831bd7fea2e9c9d6ee" - integrity sha512-Io8EB7E1pmttHzZvgvPEF0b87qlq8G5uA4B+sbqCxrUf5l4JDcK/UYLih0+rekLTbv4Q68zqgCTASvqxgqnoAg== +cspell-trie-lib@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-5.19.5.tgz#e18125c3f56b280109face14c28f7137b3469895" + integrity sha512-yNOmd7uzLiu5UDpbIfJlORx8rJZltLz/ebostAV7UC3wzrOIQgS8xKoFfqiE0iWxIMwmV9eyydVcyzh5grx0gg== dependencies: - "@cspell/cspell-pipe" "^5.19.3" + "@cspell/cspell-pipe" "^5.19.5" fs-extra "^10.0.1" gensequence "^3.1.1" -cspell@^5.19.3: - version "5.19.3" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.19.3.tgz#0f2c6cf529fb3f0b721b380f81b04e9c22272c05" - integrity sha512-JJBH8iqtHYmxqLQZ+7GAMTVvc6SAoHVgn1tdYknOI2/uxAbZVH29eaxINY7JfjwPuxPPVAvttRetBAIRiu6ZYw== +cspell@^5.19.5: + version "5.19.5" + resolved "https://registry.yarnpkg.com/cspell/-/cspell-5.19.5.tgz#5f3bad212d11509534982a1d64c6bf6592be2ee8" + integrity sha512-LFKWBBOY6s1SYJcMlWmFP2ml3kxgzUcUCOY4JYDCAzA088gbBEiSN8sM0X6MhobsMJx4MchxjwveXFRP+1umyA== dependencies: - "@cspell/cspell-pipe" "^5.19.3" + "@cspell/cspell-pipe" "^5.19.5" chalk "^4.1.2" commander "^9.1.0" - comment-json "^4.2.2" - cspell-gitignore "^5.19.3" - cspell-glob "^5.19.3" - cspell-lib "^5.19.3" + cspell-gitignore "^5.19.5" + cspell-glob "^5.19.5" + cspell-lib "^5.19.5" fast-json-stable-stringify "^2.1.0" file-entry-cache "^6.0.1" fs-extra "^10.0.1" @@ -7080,7 +7079,7 @@ cspell@^5.19.3: strip-ansi "^6.0.1" vscode-uri "^3.0.3" -css-declaration-sorter@^6.0.3: +css-declaration-sorter@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02" integrity sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg== @@ -7159,33 +7158,33 @@ css-what@2.1: integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== css-what@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.0.1.tgz#3be33be55b9f302f710ba3a9c3abc1e2a63fc7eb" - integrity sha512-z93ZGFLNc6yaoXAmVhqoSIb+BduplteCt1fepvwhBUQK6MNE4g6fgjpuZKJKp0esUe+vXWlIkwZZjNWoOKw0ZA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.1.tgz#f4fa7006aab67e354289b3efd512c93a272b3874" - integrity sha512-kfCknalY5VX/JKJ3Iri5/5rhZmQIqkbqgXsA6oaTnfA4flY/tt+w0hMxbExr0/fVuJL8w56j211op+pkQoNzoQ== +cssnano-preset-advanced@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.3.tgz#848422118d7a62b5b29a53edc160f58c7f7f7539" + integrity sha512-AB9SmTSC2Gd8T7PpKUsXFJ3eNsg7dc4CTZ0+XAJ29MNxyJsrCEk7N1lw31bpHrsQH2PVJr21bbWgGAfA9j0dIA== dependencies: autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.5" + cssnano-preset-default "^5.2.7" postcss-discard-unused "^5.1.0" postcss-merge-idents "^5.1.1" postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.5: - version "5.2.5" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.5.tgz#267ded811a3e1664d78707f5355fcd89feeb38ac" - integrity sha512-WopL7PzN7sos3X8B54/QGl+CZUh1f0qN4ds+y2d5EPwRSSc3jsitVw81O+Uyop0pXyOfPfZxnc+LmA8w/Ki/WQ== +cssnano-preset-default@^5.2.7: + version "5.2.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.7.tgz#791e3603fb8f1b46717ac53b47e3c418e950f5f3" + integrity sha512-JiKP38ymZQK+zVKevphPzNSGHSlTI+AOwlasoSRtSVMUU285O7/6uZyd5NbW92ZHp41m0sSHe6JoZosakj63uA== dependencies: - css-declaration-sorter "^6.0.3" + css-declaration-sorter "^6.2.2" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" postcss-colormin "^5.3.0" @@ -7194,7 +7193,7 @@ cssnano-preset-default@^5.2.5: postcss-discard-duplicates "^5.1.0" postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" - postcss-merge-longhand "^5.1.3" + postcss-merge-longhand "^5.1.4" postcss-merge-rules "^5.1.1" postcss-minify-font-values "^5.1.0" postcss-minify-gradients "^5.1.1" @@ -7220,12 +7219,12 @@ cssnano-utils@^3.1.0: resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@^5.0.6, cssnano@^5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.5.tgz#5f3f519538c7f1c182c527096892243db3e17397" - integrity sha512-VZO1e+bRRVixMeia1zKagrv0lLN1B/r/u12STGNNUFxnp97LIFgZHQa0JxqlwEkvzUyA9Oz/WnCTAFkdEbONmg== +cssnano@^5.0.6, cssnano@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.7.tgz#99858bef6c76c9240f0cdc9239570bc7db8368be" + integrity sha512-pVsUV6LcTXif7lvKKW9ZrmX+rGRzxkEdJuVJcp5ftUjWITgwam5LMZOgaTvUrWPkcORBey6he7JKb4XAJvrpKg== dependencies: - cssnano-preset-default "^5.2.5" + cssnano-preset-default "^5.2.7" lilconfig "^2.0.3" yaml "^1.10.2" @@ -7971,9 +7970,9 @@ ejs@^3.1.6: jake "^10.6.1" electron-to-chromium@^1.4.84: - version "1.4.100" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.100.tgz#da82de8a19a47ea3dcdf141dde85355942fbc4e7" - integrity sha512-pNrSE2naf8fizl6/Uxq8UbKb8hU9EiYW4OzCYswosXoLV5NTMOUVKECNzDaHiUubsPq/kAckOzZd7zd8S8CHVw== + version "1.4.103" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a" + integrity sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg== elegant-spinner@^1.0.1: version "1.0.1" @@ -9050,9 +9049,9 @@ flatten@^1.0.2: integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== flow-parser@0.*: - version "0.174.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.174.1.tgz#bb81e17fe45a1e64d9752090e819a6744a539fa0" - integrity sha512-nDMOvlFR+4doLpB3OJpseHZ7uEr3ENptlF6qMas/kzQmNcLzMwfQeFX0gGJ/+em7UdldB/nGsk55tDTOvjbCuw== + version "0.175.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.175.0.tgz#622c2e1dadeed0cc3d25779b143a0935bf515983" + integrity sha512-9XG5JGOjhODF+OQF5ufCw8XiGi+8B46scjr3Q49JxN7IDRdT2W+1AOuvKKd6j766/5E7qSuCn/dsq1y3hihntg== flush-write-stream@^2.0.0: version "2.0.0" @@ -11839,11 +11838,11 @@ jsprim@^1.2.2: verror "1.10.0" "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + version "3.2.2" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz#6ab1e52c71dfc0c0707008a91729a9491fe9f76c" + integrity sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw== dependencies: - array-includes "^3.1.3" + array-includes "^3.1.4" object.assign "^4.1.2" junk@^3.1.0: @@ -13277,16 +13276,16 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== netlify-cli@^9.13.6: - version "9.13.6" - resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.13.6.tgz#b86984ada9c3194588296bc113e541fe371e98eb" - integrity sha512-6S+uWGZSroD+2Y+RQj0a5bcsjpNCPrJBt2nJHHg0SnGiSCAkf/h2aRUTrFHiyDB/CDWE9brswggxDvGqdSAEAg== + version "9.16.1" + resolved "https://registry.yarnpkg.com/netlify-cli/-/netlify-cli-9.16.1.tgz#4fb26042df27e134f118d032a261000b500fba53" + integrity sha512-f7WZ4iaFppmQBRjL9dZPg+4Ao1DLqzdSdk4oj+LYa+GbUltj5EoUrNyfwL4WU6pekoIITOaBf5XoMqsAP32t1Q== dependencies: "@netlify/build" "^26.5.1" "@netlify/config" "^17.0.19" "@netlify/framework-info" "^9.0.2" "@netlify/local-functions-proxy" "^1.1.1" "@netlify/plugin-edge-handlers" "^3.0.7" - "@netlify/plugins-list" "^6.17.0" + "@netlify/plugins-list" "^6.18.1" "@netlify/routing-local-proxy" "^0.34.1" "@netlify/zip-it-and-ship-it" "^5.9.0" "@octokit/rest" "^18.0.0" @@ -13515,9 +13514,9 @@ node-forge@^1: integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.2: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + version "4.4.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" + integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== node-gyp@^5.0.2: version "5.1.1" @@ -14821,10 +14820,10 @@ postcss-merge-idents@^5.1.1: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.3.tgz#a49e2be6237316e3b55e329e0a8da15d1f9f47ab" - integrity sha512-lX8GPGvZ0iGP/IboM7HXH5JwkXvXod1Rr8H8ixwiA372hArk0zP4ZcCy4z4Prg/bfNlbbTf0KCOjCF9kKnpP/w== +postcss-merge-longhand@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz#0f46f8753989a33260efc47de9a0cdc571f2ec5c" + integrity sha512-hbqRRqYfmXoGpzYKeW0/NCZhvNyQIlQeWVSao5iKWdyx7skLvCfQFGIUsP9NUs3dSbPac2IC4Go85/zG+7MlmA== dependencies: postcss-value-parser "^4.2.0" stylehacks "^5.1.0" @@ -15003,9 +15002,9 @@ postcss-safe-parser@^6.0.0: integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" - integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -18367,9 +18366,9 @@ type-fest@^1.0.2: integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== type-fest@^2.0.0, type-fest@^2.11.2, type-fest@^2.5.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.1.tgz#d2be8f50bf5f8f0a5fd916d29bf3e98c17e960be" - integrity sha512-AiknQSEqKVGDDjtZqeKrUoTlcj7FKhupmnVUgz6KoOKtvMwRGE6hUNJ/nVear+h7fnUPO1q/htSkYKb1pyntkQ== + version "2.12.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.2.tgz#80a53614e6b9b475eb9077472fb7498dc7aa51d0" + integrity sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ== type-is@~1.6.18: version "1.6.18" @@ -18808,9 +18807,9 @@ use-composed-ref@^1.0.0: integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw== use-isomorphic-layout-effect@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" - integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" + integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== use-latest@^1.0.0: version "1.2.0" @@ -19161,10 +19160,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5, webpack@^5.70.0: - version "5.70.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" - integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== +webpack@^5, webpack@^5.70.1: + version "5.71.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.71.0.tgz#b01fcf379570b8c5ee06ca06c829ca168c951884" + integrity sha512-g4dFT7CFG8LY0iU5G8nBL6VlkT21Z7dcYDpJAEJV5Q1WLb9UwnFbrem1k7K52ILqEmomN7pnzWFxxE6SlDY56A== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" From 85f47fd8f7c4170d8e4f95cbaeadef9ef025a9f5 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Sun, 3 Apr 2022 15:16:30 +0800 Subject: [PATCH 115/405] fix(core): preserve Interpolate children semantics (#7103) * fix(core): preserve Interpolate children semantics * fix * fix again --- .../src/client/exports/Interpolate.tsx | 64 ++++++----------- .../exports/__tests__/Interpolate.test.tsx | 2 +- .../__snapshots__/Interpolate.test.tsx.snap | 70 ++++++++----------- .../_pages tests/error-boundary-tests.tsx | 4 ++ 4 files changed, 54 insertions(+), 86 deletions(-) diff --git a/packages/docusaurus/src/client/exports/Interpolate.tsx b/packages/docusaurus/src/client/exports/Interpolate.tsx index 99f0b76e1f09..dbb7a14c7768 100644 --- a/packages/docusaurus/src/client/exports/Interpolate.tsx +++ b/packages/docusaurus/src/client/exports/Interpolate.tsx @@ -9,7 +9,6 @@ import React, {isValidElement, type ReactNode} from 'react'; import type { InterpolateProps, InterpolateValues, - ExtractInterpolatePlaceholders, } from '@docusaurus/Interpolate'; /* @@ -18,8 +17,6 @@ We don't ship a markdown parser nor a feature-complete i18n library on purpose. More details here: https://github.com/facebook/docusaurus/pull/4295 */ -const ValueFoundMarker = '{}'; // does not care much - // If all the values are plain strings, then interpolate returns a simple string export function interpolate<Str extends string>( text: Str, @@ -36,46 +33,26 @@ export function interpolate<Str extends string, Value extends ReactNode>( text: Str, values?: InterpolateValues<Str, Value>, ): ReactNode { - const elements: (Value | string)[] = []; - - const processedText = text.replace( - // eslint-disable-next-line prefer-named-capture-group - /\{(\w+)\}/g, - (match, key: ExtractInterpolatePlaceholders<Str>) => { - const value = values?.[key]; - - if (typeof value !== 'undefined') { - const element = isValidElement(value) - ? value - : // For non-React elements: basic primitive->string conversion - String(value); - elements.push(element); - return ValueFoundMarker; + // eslint-disable-next-line prefer-named-capture-group + const segments = text.split(/(\{\w+\})/).map((seg, index) => { + // Odd indices (1, 3, 5...) of the segments are (potentially) interpolatable + if (index % 2 === 1) { + const value = values?.[seg.slice(1, -1) as keyof typeof values]; + if (value !== undefined) { + return value; } - return match; // no match? add warning? - }, - ); - - // No interpolation to be done: just return the text - if (elements.length === 0) { - return text; - } - // Basic string interpolation: returns interpolated string - if (elements.every((el): el is string => typeof el === 'string')) { - return processedText - .split(ValueFoundMarker) - .reduce<string>( - (str, value, index) => str.concat(value).concat(elements[index] ?? ''), - '', - ); + // No match: add warning? There's no way to "escape" interpolation though + } + return seg; + }); + if (segments.some((seg) => isValidElement(seg))) { + return segments + .map((seg, index) => + isValidElement(seg) ? React.cloneElement(seg, {key: index}) : seg, + ) + .filter((seg) => seg !== ''); } - // JSX interpolation: returns ReactNode - return processedText.split(ValueFoundMarker).map((value, index) => ( - <React.Fragment key={index}> - {value} - {elements[index]} - </React.Fragment> - )); + return segments.join(''); } export default function Interpolate<Str extends string>({ @@ -83,9 +60,10 @@ export default function Interpolate<Str extends string>({ values, }: InterpolateProps<Str>): JSX.Element { if (typeof children !== 'string') { - console.warn('Illegal <Interpolate> children', children); throw new Error( - 'The Docusaurus <Interpolate> component only accept simple string values', + `The Docusaurus <Interpolate> component only accept simple string values. Received: ${ + isValidElement(children) ? 'React element' : typeof children + }`, ); } return <>{interpolate(children, values)}</>; diff --git a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx index fdf1033103de..ac9d430955c7 100644 --- a/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/Interpolate.test.tsx @@ -130,7 +130,7 @@ describe('<Interpolate>', () => { </Interpolate>, ), ).toThrowErrorMatchingInlineSnapshot( - `"The Docusaurus <Interpolate> component only accept simple string values"`, + `"The Docusaurus <Interpolate> component only accept simple string values. Received: React element"`, ); }); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap index 9136a8e12d29..0674ed24de49 100644 --- a/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap +++ b/packages/docusaurus/src/client/exports/__tests__/__snapshots__/Interpolate.test.tsx.snap @@ -8,62 +8,48 @@ exports[`<Interpolate> acceptance test 1`] = ` <span> today </span>, - "? Another {unprovidedValue}!", + "? Another ", + "{unprovidedValue}", + "!", ] `; exports[`interpolate acceptance test 1`] = ` [ - <React.Fragment> - Hello - Sébastien - </React.Fragment>, - <React.Fragment> - how are you - <span> - today - </span> - </React.Fragment>, - <React.Fragment> - ? Another {unprovidedValue}! - </React.Fragment>, + "Hello ", + "Sébastien", + " how are you ", + <span> + today + </span>, + "? Another ", + "{unprovidedValue}", + "!", ] `; exports[`interpolate placeholders with JSX values 1`] = ` [ - <React.Fragment> - Hello - <b> - Sébastien - </b> - </React.Fragment>, - <React.Fragment> - how are you - <span> - today - </span> - </React.Fragment>, - <React.Fragment> - ? - </React.Fragment>, + "Hello ", + <b> + Sébastien + </b>, + " how are you ", + <span> + today + </span>, + "?", ] `; exports[`interpolate placeholders with mixed vales 1`] = ` [ - <React.Fragment> - Hello - Sébastien - </React.Fragment>, - <React.Fragment> - how are you - <span> - today - </span> - </React.Fragment>, - <React.Fragment> - ? - </React.Fragment>, + "Hello ", + "Sébastien", + " how are you ", + <span> + today + </span>, + "?", ] `; diff --git a/website/_dogfooding/_pages tests/error-boundary-tests.tsx b/website/_dogfooding/_pages tests/error-boundary-tests.tsx index 2edbd8ff5331..a669c7f2afb3 100644 --- a/website/_dogfooding/_pages tests/error-boundary-tests.tsx +++ b/website/_dogfooding/_pages tests/error-boundary-tests.tsx @@ -7,6 +7,7 @@ import React from 'react'; import Layout from '@theme/Layout'; +import Interpolate from '@docusaurus/Interpolate'; import ErrorBoundaryTestButton from '@site/src/components/ErrorBoundaryTestButton'; @@ -22,6 +23,9 @@ export default function ErrorBoundaryTests(): JSX.Element { Crash inside layout </ErrorBoundaryTestButton> </div> + <Interpolate values={{foo: <span>FooFoo</span>, bar: <b>BarBar</b>}}> + {'{foo} is {bar}'} + </Interpolate> </main> </Layout> </> From 4194925da9593425270325dd36bb1145f2aed383 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Mon, 4 Apr 2022 10:02:16 +0800 Subject: [PATCH 116/405] docs: add a note about additional languages needing to be Prism component names (#7110) --- .../markdown-features/markdown-features-code-blocks.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx index 1cdc53d72e72..bb586e9ce13a 100644 --- a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx +++ b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx @@ -83,6 +83,12 @@ Some popular languages like Java, C#, or PHP are not enabled by default. To add syntax highlighting for any of the other [Prism-supported languages](https://prismjs.com/#supported-languages), define it in an array of additional languages. +:::note + +Each additional language has to be a valid Prism component name. For example, Prism would map the _language_ `cs` to `csharp`, but only `prism-csharp.js` exists as a _component_, so you need to use `additionalLanguages: ['csharp']`. You can look into `node_modules/prismjs/components` to find all components (languages) available. + +::: + For example, if you want to add highlighting for the PowerShell language: ```js title="docusaurus.config.js" From e610a4ac002e561b8adee5558b178168a2e26742 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Tue, 5 Apr 2022 14:09:19 +0800 Subject: [PATCH 117/405] test: improve test coverage (#7113) --- jest.config.mjs | 1 + .../__snapshots__/codeBlockUtils.test.ts.snap | 81 +++++++++++++++---- .../utils/__tests__/codeBlockUtils.test.ts | 59 +++++++++++++- .../src/utils/codeBlockUtils.ts | 40 ++++----- .../src/__tests__/emitUtils.test.ts | 18 ++++- packages/docusaurus-utils/src/emitUtils.ts | 12 ++- .../{configs => config}/configAsync.config.js | 0 .../createConfig.config.js | 0 .../createConfigAsync.config.js | 0 .../incomplete.config.js} | 0 .../wrong.config.js} | 0 .../simple-site/docusaurus.config.js | 3 + .../simple-site/i18n/en/code.json | 6 ++ .../__snapshots__/config.test.ts.snap | 10 ++- .../__snapshots__/siteMetadata.test.ts.snap | 15 ++++ .../src/server/__tests__/config.test.ts | 13 +-- .../src/server/__tests__/siteMetadata.test.ts | 32 +++++++- 17 files changed, 232 insertions(+), 58 deletions(-) rename packages/docusaurus/src/server/__tests__/__fixtures__/{configs => config}/configAsync.config.js (100%) rename packages/docusaurus/src/server/__tests__/__fixtures__/{configs => config}/createConfig.config.js (100%) rename packages/docusaurus/src/server/__tests__/__fixtures__/{configs => config}/createConfigAsync.config.js (100%) rename packages/docusaurus/src/server/__tests__/__fixtures__/{bad-site/docusaurus.config.js => config/incomplete.config.js} (100%) rename packages/docusaurus/src/server/__tests__/__fixtures__/{wrong-site/docusaurus.config.js => config/wrong.config.js} (100%) create mode 100644 packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json create mode 100644 packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap diff --git a/jest.config.mjs b/jest.config.mjs index 7163875c4149..479ebd5948b3 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -25,6 +25,7 @@ const ignorePatterns = [ '/packages/docusaurus-theme-classic/lib-next', '/packages/docusaurus-theme-common/lib', '/packages/docusaurus-migrate/lib', + '/jest', ]; export default { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap index 97a8976893e6..bca094fc9ec4 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap @@ -74,40 +74,69 @@ bbbbb", } `; -exports[`parseLines respects language 1`] = ` +exports[`parseLines respects language: html 1`] = ` { - "code": "# highlight-next-line -aaaaa -bbbbb", - "highlightLines": [], + "code": "aaaa +{/* highlight-next-line */} +bbbbb +dddd", + "highlightLines": [ + 0, + 3, + ], } `; -exports[`parseLines respects language 2`] = ` +exports[`parseLines respects language: js 1`] = ` { - "code": "/* highlight-next-line */ + "code": "# highlight-next-line aaaaa bbbbb", "highlightLines": [], } `; -exports[`parseLines respects language 3`] = ` +exports[`parseLines respects language: jsx 1`] = ` { - "code": "// highlight-next-line -aaaa -/* highlight-next-line */ + "code": "aaaa bbbbb -ccccc <!-- highlight-next-line --> dddd", "highlightLines": [ - 4, + 0, + 1, + ], +} +`; + +exports[`parseLines respects language: md 1`] = ` +{ + "code": "--- +aaa: boo +--- + +aaaa + +<div> +foo +</div> + +bbbbb +dddd + +\`\`\`js +// highlight-next-line +console.log(\\"preserved\\"); +\`\`\`", + "highlightLines": [ + 1, + 7, + 11, ], } `; -exports[`parseLines respects language 4`] = ` +exports[`parseLines respects language: none 1`] = ` { "code": "aaaa bbbbb @@ -121,3 +150,27 @@ dddd", ], } `; + +exports[`parseLines respects language: py 1`] = ` +{ + "code": "/* highlight-next-line */ +aaaaa +bbbbb", + "highlightLines": [], +} +`; + +exports[`parseLines respects language: py 2`] = ` +{ + "code": "// highlight-next-line +aaaa +/* highlight-next-line */ +bbbbb +ccccc +<!-- highlight-next-line --> +dddd", + "highlightLines": [ + 4, + ], +} +`; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts index bc4e77b0d1d9..f2ddc02bb669 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts @@ -140,7 +140,7 @@ bbbbb`, '', 'js', ), - ).toMatchSnapshot(); + ).toMatchSnapshot('js'); expect( parseLines( `/* highlight-next-line */ @@ -149,7 +149,7 @@ bbbbb`, '', 'py', ), - ).toMatchSnapshot(); + ).toMatchSnapshot('py'); expect( parseLines( `// highlight-next-line @@ -163,7 +163,7 @@ dddd`, '', 'py', ), - ).toMatchSnapshot(); + ).toMatchSnapshot('py'); expect( parseLines( `// highlight-next-line @@ -177,6 +177,57 @@ dddd`, '', '', ), - ).toMatchSnapshot(); + ).toMatchSnapshot('none'); + expect( + parseLines( + `// highlight-next-line +aaaa +{/* highlight-next-line */} +bbbbb +<!-- highlight-next-line --> +dddd`, + '', + 'jsx', + ), + ).toMatchSnapshot('jsx'); + expect( + parseLines( + `// highlight-next-line +aaaa +{/* highlight-next-line */} +bbbbb +<!-- highlight-next-line --> +dddd`, + '', + 'html', + ), + ).toMatchSnapshot('html'); + expect( + parseLines( + `--- +# highlight-next-line +aaa: boo +--- + +aaaa + +<div> +{/* highlight-next-line */} +foo +</div> + +bbbbb +<!-- highlight-next-line --> +dddd + +\`\`\`js +// highlight-next-line +console.log("preserved"); +\`\`\` +`, + '', + 'md', + ), + ).toMatchSnapshot('md'); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index cc28c5d21feb..46277defbf84 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -141,29 +141,29 @@ export function parseLines( for (let lineNumber = 0; lineNumber < lines.length; ) { const line = lines[lineNumber]!; const match = line.match(directiveRegex); - if (match !== null) { - const directive = match.slice(1).find((item) => item !== undefined); - switch (directive) { - case 'highlight-next-line': - highlightRange += `${lineNumber},`; - break; - - case 'highlight-start': - highlightBlockStart = lineNumber; - break; - - case 'highlight-end': - highlightRange += `${highlightBlockStart!}-${lineNumber - 1},`; - break; - - default: - break; - } - lines.splice(lineNumber, 1); - } else { + if (!match) { // lines without directives are unchanged lineNumber += 1; + continue; } + const directive = match.slice(1).find((item) => item !== undefined); + switch (directive) { + case 'highlight-next-line': + highlightRange += `${lineNumber},`; + break; + + case 'highlight-start': + highlightBlockStart = lineNumber; + break; + + case 'highlight-end': + highlightRange += `${highlightBlockStart!}-${lineNumber - 1},`; + break; + + default: + break; + } + lines.splice(lineNumber, 1); } const highlightLines = rangeParser(highlightRange); code = lines.join('\n'); diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index e5f975abb9f0..236d9c224dc8 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -11,7 +11,7 @@ import path from 'path'; import fs from 'fs-extra'; describe('readOutputHTMLFile', () => { - it('trailing slash undefined', async () => { + it('reads both files with trailing slash undefined', async () => { await expect( readOutputHTMLFile( '/file', @@ -41,7 +41,7 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toBe('folder\n'); }); - it('trailing slash true', async () => { + it('reads only folder with trailing slash true', async () => { await expect( readOutputHTMLFile( '/folder', @@ -57,7 +57,7 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toBe('folder\n'); }); - it('trailing slash false', async () => { + it('reads only file trailing slash false', async () => { await expect( readOutputHTMLFile( '/file', @@ -73,6 +73,18 @@ describe('readOutputHTMLFile', () => { ).then(String), ).resolves.toBe('file\n'); }); + // Can it ever happen? + it('throws if file does not exist', async () => { + await expect( + readOutputHTMLFile( + '/nonExistent', + path.join(__dirname, '__fixtures__/build-snap'), + undefined, + ).then(String), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Expected output HTML file to be found at <PROJECT_ROOT>/packages/docusaurus-utils/src/__tests__/__fixtures__/build-snap/nonExistent/index.html."`, + ); + }); }); describe('generate', () => { diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index 89680f92ad08..b0c9a3ab27b7 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -83,18 +83,16 @@ export async function readOutputHTMLFile( outDir, `${permalink.replace(/\/$/, '')}.html`, ); - if (trailingSlash) { - return fs.readFile(withTrailingSlashPath); - } else if (trailingSlash === false) { - return fs.readFile(withoutTrailingSlashPath); - } const HTMLPath = await findAsyncSequential( - [withTrailingSlashPath, withoutTrailingSlashPath], + [ + trailingSlash !== false && withTrailingSlashPath, + trailingSlash !== true && withoutTrailingSlashPath, + ].filter((p): p is string => Boolean(p)), fs.pathExists, ); if (!HTMLPath) { throw new Error( - `Expected output HTML file to be found at ${withTrailingSlashPath}`, + `Expected output HTML file to be found at ${withTrailingSlashPath}.`, ); } return fs.readFile(HTMLPath); diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js similarity index 100% rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js similarity index 100% rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js similarity index 100% rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/bad-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/incomplete.config.js similarity index 100% rename from packages/docusaurus/src/server/__tests__/__fixtures__/bad-site/docusaurus.config.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/incomplete.config.js diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/wrong-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/wrong.config.js similarity index 100% rename from packages/docusaurus/src/server/__tests__/__fixtures__/wrong-site/docusaurus.config.js rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/wrong.config.js diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js index 994e27fa637a..a67a70d52870 100644 --- a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js @@ -22,4 +22,7 @@ module.exports = { ], '@docusaurus/plugin-content-pages', ], + clientModules: [ + 'foo.js' + ] }; diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json new file mode 100644 index 000000000000..768c5072a6ab --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json @@ -0,0 +1,6 @@ +{ + "foo": { + "message": "bar", + "description": "foo for bar" + } +} diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap index 914b41fe1cdf..abaaab349c57 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap @@ -34,7 +34,7 @@ exports[`loadSiteConfig website with valid async config 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js", } `; @@ -72,7 +72,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js", } `; @@ -110,7 +110,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = ` "titleDelimiter": "|", "url": "https://docusaurus.io", }, - "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js", + "siteConfigPath": "<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js", } `; @@ -119,7 +119,9 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = ` "siteConfig": { "baseUrl": "/", "baseUrlIssueBanner": true, - "clientModules": [], + "clientModules": [ + "foo.js", + ], "customFields": {}, "favicon": "img/docusaurus.ico", "i18n": { diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap new file mode 100644 index 000000000000..667dc1216ad9 --- /dev/null +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`loadSiteMetadata warns about plugin version mismatch 1`] = ` +{ + "docusaurusVersion": "<CURRENT_VERSION>", + "pluginVersions": { + "docusaurus-plugin-content-docs": { + "name": "@docusaurus/plugin-content-docs", + "type": "package", + "version": "1.0.0", + }, + }, + "siteVersion": "random-version", +} +`; diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 7c3fb39b800b..12b4be64152f 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -9,7 +9,7 @@ import path from 'path'; import {loadSiteConfig} from '../config'; describe('loadSiteConfig', () => { - const siteDir = path.join(__dirname, '__fixtures__', 'configs'); + const siteDir = path.join(__dirname, '__fixtures__', 'config'); it('website with valid siteConfig', async () => { const config = await loadSiteConfig({ @@ -49,7 +49,8 @@ describe('loadSiteConfig', () => { it('website with incomplete siteConfig', async () => { await expect( loadSiteConfig({ - siteDir: path.join(__dirname, '__fixtures__', 'bad-site'), + siteDir, + customConfigFilePath: 'incomplete.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot(` "\\"url\\" is required @@ -60,7 +61,8 @@ describe('loadSiteConfig', () => { it('website with useless field (wrong field) in siteConfig', async () => { await expect( loadSiteConfig({ - siteDir: path.join(__dirname, '__fixtures__', 'wrong-site'), + siteDir, + customConfigFilePath: 'wrong.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot(` "These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js. @@ -72,10 +74,11 @@ describe('loadSiteConfig', () => { it('website with no siteConfig', async () => { await expect( loadSiteConfig({ - siteDir: path.join(__dirname, '__fixtures__', 'nonExisting'), + siteDir, + customConfigFilePath: 'nonExistent.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Config file at \\"<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/nonExisting/docusaurus.config.js\\" not found."`, + `"Config file at \\"<PROJECT_ROOT>/packages/docusaurus/src/server/__tests__/__fixtures__/config/nonExistent.config.js\\" not found."`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts index b12e0a7e172c..12c62dcd54cd 100644 --- a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts +++ b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts @@ -5,7 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {getPluginVersion} from '../siteMetadata'; +import {jest} from '@jest/globals'; +import {getPluginVersion, loadSiteMetadata} from '../siteMetadata'; import path from 'path'; describe('getPluginVersion', () => { @@ -33,3 +34,32 @@ describe('getPluginVersion', () => { await expect(getPluginVersion('/', '/')).resolves.toEqual({type: 'local'}); }); }); + +describe('loadSiteMetadata', () => { + it('warns about plugin version mismatch', async () => { + const consoleMock = jest + .spyOn(console, 'error') + .mockImplementation(() => {}); + await expect( + loadSiteMetadata({ + plugins: [ + { + name: 'docusaurus-plugin-content-docs', + version: { + type: 'package', + version: '1.0.0', + name: '@docusaurus/plugin-content-docs', + }, + }, + ], + siteDir: path.join(__dirname, '__fixtures__/siteMetadata'), + }), + ).resolves.toMatchSnapshot(); + // cSpell:ignore mdocusaurus + expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(` + "[ERROR] Invalid docusaurus-plugin-content-docs version 1.0.0. + All official @docusaurus/* packages should have the exact same version as @docusaurus/core (<CURRENT_VERSION>). + Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?" + `); + }); +}); From bd70cfc1d74baca53b0370c1e109e2df2aba570f Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Wed, 6 Apr 2022 17:20:41 +0800 Subject: [PATCH 118/405] refactor(create): mention that the edit links can be removed (#7118) --- .../create-docusaurus/templates/classic/docusaurus.config.js | 5 ++++- .../templates/facebook/docusaurus.config.js | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/create-docusaurus/templates/classic/docusaurus.config.js b/packages/create-docusaurus/templates/classic/docusaurus.config.js index 58deac51c392..5cf4b168d330 100644 --- a/packages/create-docusaurus/templates/classic/docusaurus.config.js +++ b/packages/create-docusaurus/templates/classic/docusaurus.config.js @@ -27,11 +27,14 @@ const config = { docs: { sidebarPath: require.resolve('./sidebars.js'), // Please change this to your repo. - editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, blog: { showReadingTime: true, // Please change this to your repo. + // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, diff --git a/packages/create-docusaurus/templates/facebook/docusaurus.config.js b/packages/create-docusaurus/templates/facebook/docusaurus.config.js index f63126e2fe5e..d140034e07f5 100644 --- a/packages/create-docusaurus/templates/facebook/docusaurus.config.js +++ b/packages/create-docusaurus/templates/facebook/docusaurus.config.js @@ -32,12 +32,14 @@ const config = { docs: { sidebarPath: require.resolve('./sidebars.js'), // Please change this to your repo. + // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, blog: { showReadingTime: true, // Please change this to your repo. + // Remove this to remove the "edit this page" links. editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', }, From 103ea046613c20c37f09ae3290a1d66bcd2e97ba Mon Sep 17 00:00:00 2001 From: ApsarasX <pyyzcwg2833@outlook.com> Date: Wed, 6 Apr 2022 21:44:07 +0800 Subject: [PATCH 119/405] feat(sitemap): add ignorePatterns option (#6979) Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- .../src/__tests__/createSitemap.test.ts | 27 +++++++++++++++++++ .../src/__tests__/options.test.ts | 14 ++++++++++ .../src/createSitemap.ts | 11 +++++--- .../docusaurus-plugin-sitemap/src/index.ts | 4 +-- .../docusaurus-plugin-sitemap/src/options.ts | 10 ++++--- .../src/plugin-sitemap.d.ts | 14 +++++++--- packages/docusaurus-utils/src/globUtils.ts | 7 ++++- website/docs/api/plugins/plugin-sitemap.md | 2 ++ website/docusaurus.config.js | 3 +++ 9 files changed, 78 insertions(+), 14 deletions(-) diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index c041bff79b6b..193002e4bef1 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -19,6 +19,7 @@ describe('createSitemap', () => { { changefreq: EnumChangefreq.DAILY, priority: 0.7, + ignorePatterns: [], }, ); expect(sitemap).toContain( @@ -42,11 +43,34 @@ describe('createSitemap', () => { { changefreq: EnumChangefreq.DAILY, priority: 0.7, + ignorePatterns: [], }, ); expect(sitemap).not.toContain('404'); }); + it('excludes patterns configured to be ignored', async () => { + const sitemap = await createSitemap( + { + url: 'https://example.com', + } as DocusaurusConfig, + ['/', '/search/', '/tags/', '/search/foo', '/tags/foo/bar'], + { + changefreq: EnumChangefreq.DAILY, + priority: 0.7, + ignorePatterns: [ + // Shallow ignore + '/search/', + // Deep ignore + '/tags/**', + ], + }, + ); + expect(sitemap).not.toContain('/search/</loc>'); + expect(sitemap).toContain('/search/foo'); + expect(sitemap).not.toContain('/tags'); + }); + it('keep trailing slash unchanged', async () => { const sitemap = await createSitemap( { @@ -57,6 +81,7 @@ describe('createSitemap', () => { { changefreq: EnumChangefreq.DAILY, priority: 0.7, + ignorePatterns: [], }, ); @@ -76,6 +101,7 @@ describe('createSitemap', () => { { changefreq: EnumChangefreq.DAILY, priority: 0.7, + ignorePatterns: [], }, ); @@ -95,6 +121,7 @@ describe('createSitemap', () => { { changefreq: EnumChangefreq.DAILY, priority: 0.7, + ignorePatterns: [], }, ); diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts index e53a2adc6ba9..5e38548b699d 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts @@ -27,6 +27,7 @@ describe('validateOptions', () => { const userOptions = { changefreq: 'yearly', priority: 0.9, + ignorePatterns: ['/search/**'], }; expect(testValidate(userOptions)).toEqual({ ...defaultOptions, @@ -49,4 +50,17 @@ describe('validateOptions', () => { `"\\"changefreq\\" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`, ); }); + + it('rejects bad ignorePatterns inputs', () => { + expect(() => + testValidate({ignorePatterns: '/search'}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"ignorePatterns\\" must be an array"`, + ); + expect(() => + testValidate({ignorePatterns: [/^\/search/]}), + ).toThrowErrorMatchingInlineSnapshot( + `"\\"ignorePatterns[0]\\" must be a string"`, + ); + }); }); diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts index 2d6afbcb68c6..8df3581badd1 100644 --- a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts +++ b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts @@ -6,25 +6,28 @@ */ import {SitemapStream, streamToPromise} from 'sitemap'; -import type {Options} from '@docusaurus/plugin-sitemap'; +import type {PluginOptions} from '@docusaurus/plugin-sitemap'; import type {DocusaurusConfig} from '@docusaurus/types'; import {applyTrailingSlash} from '@docusaurus/utils-common'; +import {createMatcher} from '@docusaurus/utils'; export default async function createSitemap( siteConfig: DocusaurusConfig, routesPaths: string[], - options: Options, + options: PluginOptions, ): Promise<string> { const {url: hostname} = siteConfig; if (!hostname) { throw new Error('URL in docusaurus.config.js cannot be empty/undefined.'); } - const {changefreq, priority} = options; + const {changefreq, priority, ignorePatterns} = options; + + const ignoreMatcher = createMatcher(ignorePatterns); const sitemapStream = new SitemapStream({hostname}); routesPaths - .filter((route) => !route.endsWith('404.html')) + .filter((route) => !route.endsWith('404.html') && !ignoreMatcher(route)) .forEach((routePath) => sitemapStream.write({ url: applyTrailingSlash(routePath, { diff --git a/packages/docusaurus-plugin-sitemap/src/index.ts b/packages/docusaurus-plugin-sitemap/src/index.ts index 0a6651029917..2b77da6e0b24 100644 --- a/packages/docusaurus-plugin-sitemap/src/index.ts +++ b/packages/docusaurus-plugin-sitemap/src/index.ts @@ -7,13 +7,13 @@ import fs from 'fs-extra'; import path from 'path'; -import type {Options} from '@docusaurus/plugin-sitemap'; +import type {PluginOptions} from '@docusaurus/plugin-sitemap'; import createSitemap from './createSitemap'; import type {LoadContext, Plugin} from '@docusaurus/types'; export default function pluginSitemap( context: LoadContext, - options: Options, + options: PluginOptions, ): Plugin<void> { return { name: 'docusaurus-plugin-sitemap', diff --git a/packages/docusaurus-plugin-sitemap/src/options.ts b/packages/docusaurus-plugin-sitemap/src/options.ts index e7d7972153a5..e5f2053931c0 100644 --- a/packages/docusaurus-plugin-sitemap/src/options.ts +++ b/packages/docusaurus-plugin-sitemap/src/options.ts @@ -7,12 +7,13 @@ import {Joi} from '@docusaurus/utils-validation'; import {EnumChangefreq} from 'sitemap'; -import type {Options} from '@docusaurus/plugin-sitemap'; +import type {Options, PluginOptions} from '@docusaurus/plugin-sitemap'; import type {OptionValidationContext} from '@docusaurus/types'; -export const DEFAULT_OPTIONS: Options = { +export const DEFAULT_OPTIONS: PluginOptions = { changefreq: EnumChangefreq.WEEKLY, priority: 0.5, + ignorePatterns: [], }; const PluginOptionSchema = Joi.object({ @@ -24,6 +25,9 @@ const PluginOptionSchema = Joi.object({ .valid(...Object.values(EnumChangefreq)) .default(DEFAULT_OPTIONS.changefreq), priority: Joi.number().min(0).max(1).default(DEFAULT_OPTIONS.priority), + ignorePatterns: Joi.array() + .items(Joi.string()) + .default(DEFAULT_OPTIONS.ignorePatterns), trailingSlash: Joi.forbidden().messages({ 'any.unknown': 'Please use the new Docusaurus global trailingSlash config instead, and the sitemaps plugin will use it.', @@ -33,7 +37,7 @@ const PluginOptionSchema = Joi.object({ export function validateOptions({ validate, options, -}: OptionValidationContext<Options, Options>): Options { +}: OptionValidationContext<Options, PluginOptions>): PluginOptions { const validatedOptions = validate(PluginOptionSchema, options); return validatedOptions; } diff --git a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts index 7f16b96a4c94..6f175bd1f7a1 100644 --- a/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts +++ b/packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts @@ -7,10 +7,16 @@ import type {EnumChangefreq} from 'sitemap'; -export type Options = { - id?: string; +export type PluginOptions = { /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ - changefreq?: EnumChangefreq; + changefreq: EnumChangefreq; /** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ - priority?: number; + priority: number; + /** + * A list of glob patterns; matching route paths will be filtered from the + * sitemap. Note that you may need to include the base URL in here. + */ + ignorePatterns: string[]; }; + +export type Options = Partial<PluginOptions>; diff --git a/packages/docusaurus-utils/src/globUtils.ts b/packages/docusaurus-utils/src/globUtils.ts index b70ed4cd53d3..67af9051eeae 100644 --- a/packages/docusaurus-utils/src/globUtils.ts +++ b/packages/docusaurus-utils/src/globUtils.ts @@ -31,11 +31,16 @@ type Matcher = (str: string) => boolean; * A very thin wrapper around `Micromatch.makeRe`. * * @see {@link createAbsoluteFilePathMatcher} - * @param patterns A list of glob patterns. + * @param patterns A list of glob patterns. If the list is empty, it defaults to + * matching none. * @returns A matcher handle that tells if a file path is matched by any of the * patterns. */ export function createMatcher(patterns: string[]): Matcher { + if (patterns.length === 0) { + // `/(?:)/.test("foo")` is `true` + return () => false; + } const regexp = new RegExp( patterns.map((pattern) => Micromatch.makeRe(pattern).source).join('|'), ); diff --git a/website/docs/api/plugins/plugin-sitemap.md b/website/docs/api/plugins/plugin-sitemap.md index 6c8bd87d32c1..c8aec5da3079 100644 --- a/website/docs/api/plugins/plugin-sitemap.md +++ b/website/docs/api/plugins/plugin-sitemap.md @@ -39,6 +39,7 @@ Accepted fields: | --- | --- | --- | --- | | `changefreq` | `string` | `'weekly'` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) | | `priority` | `number` | `0.5` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) | +| `ignorePatterns` | `string[]` | `[]` | A list of glob patterns; matching route paths will be filtered from the sitemap. Note that you may need to include the base URL in here. | </APITable> @@ -68,6 +69,7 @@ Most Docusaurus users configure this plugin through the preset options. const config = { changefreq: 'weekly', priority: 0.5, + ignorePatterns: ['/tags/**'], }; ``` diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 775ada764646..5c7e1c0dec81 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -338,6 +338,9 @@ const config = { trackingID: 'UA-141789564-1', } : undefined, + sitemap: { + ignorePatterns: ['/tests/**'], + }, }), ], ], From 49424f50579be95027519c98e2a91d1a1af2c181 Mon Sep 17 00:00:00 2001 From: mehdim <elmasaoudimahdi@gmail.com> Date: Wed, 6 Apr 2022 20:17:06 -0400 Subject: [PATCH 120/405] docs: correct plugin example filename (#7026) * Correect Wrong file name The file name inside the my-plugin folder is index.js . * Update plugins.md Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/docs/advanced/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/advanced/plugins.md b/website/docs/advanced/plugins.md index 2960263eca6e..152f8ffebd11 100644 --- a/website/docs/advanced/plugins.md +++ b/website/docs/advanced/plugins.md @@ -51,7 +51,7 @@ module.exports = { Then in the folder `my-plugin`, you can create an `index.js` such as this: -```js title="my-plugin.js" +```js title="my-plugin/index.js" module.exports = async function myPlugin(context, options) { // ... return { From c669c103f9c3d20b1daee60ed2ee332a3c07a0b6 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Thu, 7 Apr 2022 03:33:52 +0300 Subject: [PATCH 121/405] refactor(website): minor fixes and improvements (#7119) * refactor(website): minor fixes and improvements * Some fixes * Round all the corners in browser window * Add rounded bottom corners to browser window --- website/docs/typescript-support.md | 6 +---- website/docusaurus.config.js | 4 ++-- .../src/components/BrowserWindow/index.tsx | 5 ++++- .../BrowserWindow/styles.module.css | 10 +++++++-- website/src/components/Tweet/index.tsx | 22 +++++++++---------- .../src/components/Tweet/styles.module.css | 7 ++++-- website/src/data/tweets.tsx | 4 ++-- website/src/pages/index.tsx | 6 ++--- website/src/pages/styles.module.css | 18 +++++++++------ 9 files changed, 47 insertions(+), 35 deletions(-) diff --git a/website/docs/typescript-support.md b/website/docs/typescript-support.md index 25c36c2c593e..8bd87a1f8960 100644 --- a/website/docs/typescript-support.md +++ b/website/docs/typescript-support.md @@ -112,11 +112,7 @@ The best IDEs (VS Code, WebStorm, IntelliJ...) will provide a nice auto-completi By default, the Docusaurus TypeScript config does not type-check JavaScript files. -The `// @ts-check` comment ensures the config file is properly type-checked when running: - -```bash npm2yarn -npx tsc -``` +The `// @ts-check` comment ensures the config file is properly type-checked when running `npx tsc`. ::: diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 5c7e1c0dec81..ff88fba0232e 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -59,7 +59,7 @@ const isI18nStaging = process.env.I18N_STAGING === 'true'; const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging; const TwitterSvg = - '<svg style="fill: #1DA1F2; vertical-align: middle;" width="16" height="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>'; + '<svg style="fill: #1DA1F2; vertical-align: middle; margin-left: 3px;" width="16" height="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>'; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -360,7 +360,7 @@ const config = { }, announcementBar: { id: 'announcementBar-2', // Increment on change - content: `⭐️ If you like Docusaurus, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebook/docusaurus">GitHub</a> and follow us on <a target="_blank" rel="noopener noreferrer" href="https://twitter.com/docusaurus" >Twitter</a> ${TwitterSvg}`, + content: `⭐️ If you like Docusaurus, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebook/docusaurus">GitHub</a> and follow us on <a target="_blank" rel="noopener noreferrer" href="https://twitter.com/docusaurus">Twitter ${TwitterSvg}</a>`, }, prism: { // We need to load markdown again so that YAML is loaded before MD diff --git a/website/src/components/BrowserWindow/index.tsx b/website/src/components/BrowserWindow/index.tsx index 58d6b74cba1e..26f315356c9f 100644 --- a/website/src/components/BrowserWindow/index.tsx +++ b/website/src/components/BrowserWindow/index.tsx @@ -6,6 +6,7 @@ */ import React, {type ReactNode} from 'react'; +import clsx from 'clsx'; import styles from './styles.module.css'; @@ -28,7 +29,9 @@ export default function BrowserWindow({ <span className={styles.dot} style={{background: '#fbbe3c'}} /> <span className={styles.dot} style={{background: '#58cb42'}} /> </div> - <div className={styles.browserWindowAddressBar}>{url}</div> + <div className={clsx(styles.browserWindowAddressBar, 'text--truncate')}> + {url} + </div> <div className={styles.browserWindowMenuIcon}> <div> <span className={styles.bar} /> diff --git a/website/src/components/BrowserWindow/styles.module.css b/website/src/components/BrowserWindow/styles.module.css index 2931c9c20f6d..9793395e2dce 100644 --- a/website/src/components/BrowserWindow/styles.module.css +++ b/website/src/components/BrowserWindow/styles.module.css @@ -7,8 +7,7 @@ .browserWindow { border: 3px solid var(--ifm-color-emphasis-200); - border-top-left-radius: var(--ifm-global-radius); - border-top-right-radius: var(--ifm-global-radius); + border-radius: var(--ifm-global-radius); box-shadow: var(--ifm-global-shadow-lw); margin-bottom: var(--ifm-leading); } @@ -77,5 +76,12 @@ } .browserWindowBody { + background-color: var(--ifm-background-color); + border-bottom-left-radius: inherit; + border-bottom-right-radius: inherit; padding: 1rem; } + +.browserWindowBody *:last-child { + margin-bottom: 0; +} diff --git a/website/src/components/Tweet/index.tsx b/website/src/components/Tweet/index.tsx index f6feb496fcc3..415f1e21bffe 100644 --- a/website/src/components/Tweet/index.tsx +++ b/website/src/components/Tweet/index.tsx @@ -40,20 +40,20 @@ export default function Tweet({ height="48" loading="lazy" /> - <div className="avatar__intro"> - <div className={styles.tweet}> - <div> - <strong>{name}</strong>{' '} - <span className={styles.tweetMeta}>@{handle}</span> - </div> - </div> - <div className="margin-bottom--sm">{content}</div> - <a className={clsx(styles.tweetMeta, styles.tweetDate)} href={url}> - {date} - </a> + <div className={clsx('avatar__intro', styles.tweetMeta)}> + <strong className="avatar__name">{name}</strong> + <span>@{handle}</span> </div> </div> </div> + + <div className={clsx('card__body', styles.tweet)}>{content}</div> + + <div className="card__footer"> + <a className={clsx(styles.tweetMeta, styles.tweetDate)} href={url}> + {date} + </a> + </div> </div> ); } diff --git a/website/src/components/Tweet/styles.module.css b/website/src/components/Tweet/styles.module.css index 3b58e7b81a42..b20b2495d019 100644 --- a/website/src/components/Tweet/styles.module.css +++ b/website/src/components/Tweet/styles.module.css @@ -9,7 +9,10 @@ font-size: 15px; } -.tweetMeta, -.tweetMeta:hover { +.tweetMeta { color: var(--ifm-color-emphasis-700); } + +.tweetMeta strong { + color: var(--ifm-font-color-base); +} diff --git a/website/src/data/tweets.tsx b/website/src/data/tweets.tsx index 157bc0fb0e67..a449ea40dcc3 100644 --- a/website/src/data/tweets.tsx +++ b/website/src/data/tweets.tsx @@ -37,7 +37,7 @@ const TWEETS: TweetItem[] = [ name: 'Maël', date: 'Jan 20, 2021', avatar: - 'https://pbs.twimg.com/profile_images/1311259425949261825/7hPZqoJd_400x400.jpg', + 'https://pbs.twimg.com/profile_images/1497225853931040769/5mXZAHFR_400x400.jpg', content: ( <> I've used Docusaurus for two websites this year, and I've been @@ -179,7 +179,7 @@ const TWEETS: TweetItem[] = [ name: 'swyx', date: 'Jul 23, 2021', avatar: - 'https://pbs.twimg.com/profile_images/1456506127961640962/iM2Hf8du_400x400.jpg', + 'https://pbs.twimg.com/profile_images/1510319731466993664/tGoqnzGK_400x400.jpg', content: ( <> Happy to share Temporal's first open source sponsorship — of{' '} diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 77bb4637642e..bda99a912f92 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -54,7 +54,7 @@ function HeroBanner() { <Translate>Get Started</Translate> </Link> <Link className="button button--info" to="https://docusaurus.new"> - <Translate>Playground</Translate> + <Translate>Try a Demo</Translate> </Link> <span className={styles.indexCtasGitHubButtonWrapper}> <iframe @@ -194,8 +194,8 @@ function Feature({ <img className={styles.featureImage} alt={feature.title} - width={feature.image.width} - height={feature.image.height} + width={Math.floor(feature.image.width)} + height={Math.floor(feature.image.height)} src={withBaseUrl(feature.image.src)} loading="lazy" /> diff --git a/website/src/pages/styles.module.css b/website/src/pages/styles.module.css index 3f6fff2e0f90..5291055dbd0e 100644 --- a/website/src/pages/styles.module.css +++ b/website/src/pages/styles.module.css @@ -106,6 +106,7 @@ float: right; margin-top: 20px; padding: 0 20px 20px; + height: auto; } .indexCtas { @@ -171,17 +172,20 @@ } } -.tweetsSection { - margin-top: -2rem; +.tweetsSection > :global(.col) > * { + margin-bottom: 2rem; } -.tweetsSection > :global(.col) { - padding-top: 2rem; - margin-top: -2rem; +@media (max-width: 996px) { + .tweetsSection > :global(.col:last-child) > *:last-child { + margin-bottom: 0; + } } -.tweetsSection > :global(.col) > * { - margin-top: 2rem; +@media (min-width: 997px) { + .tweetsSection > :global(.col) > *:last-child { + margin-bottom: 0; + } } /* Used to test CSS insertion order */ From 2c61bf25688cc9943d393cfd294ff5e72c63e7bf Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 7 Apr 2022 13:26:21 +0800 Subject: [PATCH 122/405] refactor(showcase): enforce descriptions with maximum length of 120 characters (#7123) * refactor(showcase): enforce descriptions to have maximum 120 characters * update --- website/src/data/__tests__/user.test.ts | 9 +- website/src/data/users.tsx | 122 +++++++++++++----------- 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index c0d072119350..1cd0f4ebe529 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -45,12 +45,17 @@ expect.extend({ }); describe('users data', () => { - it.each(sortedUsers)('$title', async (user) => { + it.each(sortedUsers)('$title', (user) => { Joi.attempt( user, Joi.object<User>({ title: Joi.string().required(), - description: Joi.string().required(), + description: Joi.string() + .required() + .max(120) + .message( + 'Please constrain your description text to maximum 120 characters.', + ), website: Joi.string() .pattern(/^https?:\/\//) .message('') diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 56da2130b33f..1ac00e201376 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -20,13 +20,15 @@ import {sortBy} from '@site/src/utils/jsUtils'; * * Instructions: * - Add your site in the json array below + * - `title` is your project's name (no need for the "Docs" suffix) + * - A short (≤120 characters) description of your project + * - Use relevant tags to categorize your site (read the tag descriptions below) * - Add a local image preview (decent screenshot of your Docusaurus site) - * - Use relevant tags to qualify your site (read the tag descriptions below) * - The image MUST be added to the GitHub repository, and use `require("img")` * - The image has to have minimum width 640 and an aspect of no wider than 2:1 - * - Open a PR and check for reported CI errors * - If your website is open-source, add your source link. The link should open * to a directory containing the `docusaurus.config.js` file + * - Open a PR and check for reported CI errors * * Example PR: https://github.com/facebook/docusaurus/pull/3976 * @@ -38,7 +40,7 @@ import {sortBy} from '@site/src/utils/jsUtils'; * * Please help us maintain this showcase page data: * - Update sites with wrong data - * - Ensure site tags remains correct over time + * - Ensure site tags remain correct over time * - Remove sites not using Docusaurus anymore * - Add missing Docusaurus sites (if the site owner agreed) */ @@ -254,9 +256,8 @@ const Users: User[] = [ tags: ['opensource', 'large'], }, { - title: 'Blink Shell Docs', - description: - 'Documentation for Blink Shell a professional, desktop grade terminal for iOS', + title: 'Blink Shell', + description: 'A professional, desktop grade terminal for iOS', preview: require('./showcase/blinkshell.png'), website: 'https://docs.blink.sh/', source: 'https://github.com/blinksh/docs', @@ -313,8 +314,8 @@ const Users: User[] = [ tags: ['opensource'], }, { - title: 'Butterfly Documentation', - description: 'The documentation of the note taking app Linwood Butterfly', + title: 'Butterfly', + description: 'The note taking app Linwood Butterfly', preview: require('./showcase/docs-butterfly.png'), website: 'https://docs.butterfly.linwood.dev', source: 'https://github.com/LinwoodCloud/Butterfly/tree/develop/docs', @@ -394,7 +395,8 @@ const Users: User[] = [ description: 'Set up a modern web app by running one command', preview: require('./showcase/create-react-app.png'), website: 'https://facebook.github.io/create-react-app/', - source: 'https://github.com/facebook/create-react-app/tree/main/docusaurus/website', + source: + 'https://github.com/facebook/create-react-app/tree/main/docusaurus/website', tags: ['opensource', 'meta'], }, { @@ -539,7 +541,7 @@ const Users: User[] = [ tags: ['product'], }, { - title: 'Eightshift Docs', + title: 'Eightshift', description: 'All the tools you need to start building a modern WordPress project, using all the latest development tools.', preview: require('./showcase/eightshift-docs.png'), @@ -550,7 +552,7 @@ const Users: User[] = [ { title: 'Enarx', description: - 'Open source framework for running applications in TEEs (Trusted Execution Environments) based on WebAssembly, allowing developers to deploy architecture-independent applications', + 'Open source framework for running applications in TEEs (Trusted Execution Environments) based on WebAssembly.', preview: require('./showcase/enarx.png'), website: 'https://enarx.dev/', source: 'https://github.com/enarx/enarx.github.io', @@ -744,14 +746,13 @@ const Users: User[] = [ tags: ['opensource'], }, { - title: 'hCaptcha.com Docs', + title: 'hCaptcha', description: 'hCaptcha.com anti-bot service docs', preview: require('./showcase/hcaptcha.png'), website: 'https://docs.hcaptcha.com/', source: null, tags: ['product'], }, - { title: 'Hermes', description: 'JavaScript engine optimized for React Native', @@ -804,7 +805,7 @@ const Users: User[] = [ { title: 'StackQL', description: - 'StackQL is a data centric approach to provisioning, querying, and managing cloud infrastructure and SaaS resources across multiple clouds.', + 'A data centric approach to provision, querying, and management of cloud infra and SaaS across multiple clouds.', preview: require('./showcase/stackql.png'), website: 'https://stackql.io/', source: null, @@ -813,7 +814,7 @@ const Users: User[] = [ { title: 'SeaORM - 🐚 An async & dynamic ORM for Rust', description: - 'SeaORM is a relational ORM to help you build web services in Rust with the familiarity of dynamic languages.', + 'A relational ORM to help you build web services in Rust with the familiarity of dynamic languages.', preview: require('./showcase/SeaORM.png'), website: 'https://www.sea-ql.org/SeaORM/', source: 'https://github.com/SeaQL/seaql.github.io', @@ -822,7 +823,7 @@ const Users: User[] = [ { title: 'Ionic', description: - 'Ionic is an open source UI toolkit for building performant, high-quality mobile and desktop apps using web technologies.', + 'An open source UI toolkit for building performant, high-quality mobile and desktop apps using web technologies.', preview: require('./showcase/ionic.png'), website: 'https://ionicframework.com/docs', source: 'https://github.com/ionic-team/ionic-docs', @@ -847,7 +848,7 @@ const Users: User[] = [ { title: 'Jest', description: - 'Jest is a delightful JavaScript Testing Framework with a focus on simplicity.', + 'A delightful JavaScript Testing Framework with a focus on simplicity.', preview: require('./showcase/jest.png'), website: 'https://jestjs.io/', source: 'https://github.com/facebook/jest/tree/master/website', @@ -981,7 +982,7 @@ const Users: User[] = [ { title: 'Mia-Platform', description: - "Mia-Platform is the simplest way to develop and operate modern applications on Kubernetes. Don't waste time to set up your platform, just push the code!", + 'The simplest way to develop and operate modern applications on Kubernetes.', preview: require('./showcase/mia-platform.png'), website: 'https://docs.mia-platform.eu/', source: null, @@ -1008,7 +1009,7 @@ const Users: User[] = [ { title: 'Molecule', description: - 'Molecule is a lightweight Web IDE UI framework built with React.js and inspired by VS Code.', + 'A lightweight Web IDE UI framework built with React.js and inspired by VS Code.', preview: require('./showcase/molecule-home.png'), website: 'https://dtstack.github.io/molecule/', source: 'https://github.com/DTStack/molecule/tree/main/website', @@ -1020,22 +1021,22 @@ const Users: User[] = [ 'Create beautiful immersive React.js animations using shared components', preview: require('./showcase/motion-layout.png'), website: 'https://motion-layout.azurewebsites.net', - source: 'https://github.com/jeffersonlicet/react-motion-layout/tree/master/website', + source: + 'https://github.com/jeffersonlicet/react-motion-layout/tree/master/website', tags: ['opensource'], }, { title: 'moja global', description: - 'A non-profit, collaborative open source project to accurately and affordably estimate greenhouse gas emissions and removals from the AFOLU sector', + 'A non-profit project to accurately and affordably estimate greenhouse gas emissions and removals from the AFOLU sector', preview: require('./showcase/mojaglobal.png'), website: 'https://community.moja.global/', source: 'https://github.com/moja-global/community-website', tags: ['opensource', 'large', 'i18n', 'design'], }, { - title: 'nanos world documentation', - description: - 'nanos world is the next-generation multiplayer open world sandbox game.', + title: 'nanos world', + description: 'The next-generation multiplayer open world sandbox game.', preview: require('./showcase/nanos-world.png'), website: 'https://docs.nanos.world/', source: 'https://github.com/nanos-world/docs', @@ -1100,9 +1101,9 @@ const Users: User[] = [ tags: ['opensource', 'design', 'product'], }, { - title: 'Ory Documentation', + title: 'Ory', description: - 'Ory is an open source ecosystem and a cloud offering authentication, authorization, access control, and delegation (OAuth2 & OpenID Connect) services and APIs.', + 'Authentication, authorization, access control, and delegation (OAuth2 & OpenID Connect) services and APIs', preview: require('./showcase/ory.png'), website: 'https://www.ory.sh/docs', source: 'https://github.com/ory/docs/', @@ -1156,7 +1157,8 @@ const Users: User[] = [ 'A design-system-driven UI framework that helps developer build beautiful and accessible mobile apps right out of the box', preview: require('./showcase/pearl-ui.png'), website: 'https://docs.pearl-ui.dev/', - source: 'https://github.com/agrawal-rohit/pearl-ui/tree/main/documentationwebsite', + source: + 'https://github.com/agrawal-rohit/pearl-ui/tree/main/documentationwebsite', tags: ['opensource', 'design', 'product'], }, { @@ -1173,13 +1175,14 @@ const Users: User[] = [ description: 'Pipeline UI Documentation', preview: require('./showcase/pipeline-ui.png'), website: 'https://www.pipeline-ui.com/', - source: 'https://github.com/headline-design/pipeline-ui/tree/main/design-site', + source: + 'https://github.com/headline-design/pipeline-ui/tree/main/design-site', tags: ['opensource'], }, { - title: 'Plausible Analytics Docs', + title: 'Plausible Analytics', description: - 'Plausible Analytics is a simple, open source, lightweight (< 1 KB) and privacy-friendly alternative to Google Analytics. ', + 'A simple, open source, lightweight (< 1 KB) and privacy-friendly alternative to Google Analytics', preview: require('./showcase/plausible.png'), website: 'https://plausible.io/docs', source: 'https://github.com/plausible/docs', @@ -1247,7 +1250,8 @@ const Users: User[] = [ description: 'A performant type-checker for Python 3', preview: require('./showcase/pyre.png'), website: 'https://pyre-check.org', - source: 'https://github.com/facebook/pyre-check/tree/main/documentation/website', + source: + 'https://github.com/facebook/pyre-check/tree/main/documentation/website', tags: ['opensource', 'meta'], }, { @@ -1300,7 +1304,8 @@ const Users: User[] = [ 'Unopinionated Accessible React Tree Component with Multi-Select and Drag-And-Drop', preview: require('./showcase/react-complex-tree.png'), website: 'https://rct.lukasbach.com/', - source: 'https://github.com/lukasbach/react-complex-tree/tree/main/packages/docs', + source: + 'https://github.com/lukasbach/react-complex-tree/tree/main/packages/docs', tags: ['opensource'], }, { @@ -1308,7 +1313,8 @@ const Users: User[] = [ description: 'React components for Leaflet maps', preview: require('./showcase/react-leaflet.png'), website: 'https://react-leaflet.js.org/', - source: 'https://github.com/PaulLeCam/react-leaflet/tree/master/packages/website', + source: + 'https://github.com/PaulLeCam/react-leaflet/tree/master/packages/website', tags: ['opensource'], }, { @@ -1331,10 +1337,11 @@ const Users: User[] = [ { title: 'React Native Boilerplate', description: - 'A React Native project template for building solid applications through separation of concerns between the UI, state management and business logic.', + 'A template for building solid applications with separation of concerns between UI, state management, and business logic.', preview: require('./showcase/reactnativeboilerplate.png'), website: 'https://thecodingmachine.github.io/react-native-boilerplate/', - source: 'https://github.com/thecodingmachine/react-native-boilerplate/tree/master/documentation', + source: + 'https://github.com/thecodingmachine/react-native-boilerplate/tree/master/documentation', tags: ['opensource'], }, { @@ -1342,7 +1349,8 @@ const Users: User[] = [ description: 'Cross Platform React Native UI Toolkit', preview: require('./showcase/react-native-elements.png'), website: 'https://react-native-training.github.io/react-native-elements/', - source: 'https://github.com/react-native-elements/react-native-elements/tree/next/website', + source: + 'https://github.com/react-native-elements/react-native-elements/tree/next/website', tags: ['opensource'], }, { @@ -1350,7 +1358,8 @@ const Users: User[] = [ description: 'The missing React Native UI Kit for iOS.', preview: require('./showcase/react-native-ios-kit.png'), website: 'https://callstack.github.io/react-native-ios-kit', - source: 'https://github.com/callstack/react-native-ios-kit/tree/master/website', + source: + 'https://github.com/callstack/react-native-ios-kit/tree/master/website', tags: ['opensource'], }, { @@ -1377,7 +1386,8 @@ const Users: User[] = [ description: 'Helps you to write better tests with less effort.', preview: require('./showcase/react-native-testing-library.png'), website: 'https://callstack.github.io/react-native-testing-library/', - source: 'https://github.com/callstack/react-native-testing-library/tree/main/website', + source: + 'https://github.com/callstack/react-native-testing-library/tree/main/website', tags: ['opensource'], }, { @@ -1426,7 +1436,8 @@ const Users: User[] = [ description: 'Build redux logic, without getting nervous 😬', preview: require('./showcase/redux-cool.png'), website: 'https://redux-cool.js.org/', - source: 'https://github.com/Ruben-Arushanyan/redux-cool/tree/master/website', + source: + 'https://github.com/Ruben-Arushanyan/redux-cool/tree/master/website', tags: ['opensource'], }, { @@ -1439,7 +1450,8 @@ const Users: User[] = [ }, { title: 'Reddit Image Fetcher', - description: 'A JavaScript package for fetching reddit images, memes, wallpapers and more', + description: + 'A JavaScript package for fetching reddit images, memes, wallpapers and more', preview: require('./showcase/reddit-image-fetcher.png'), website: 'https://arifszn.github.io/reddit-image-fetcher', source: null, @@ -1508,7 +1520,8 @@ const Users: User[] = [ description: 'The library to build browser based 3D models with code.', preview: require('./showcase/replicad.png'), website: 'https://replicad.xyz/', - source: 'https://github.com/sgenoud/replicad/tree/main/packages/replicad-docs', + source: + 'https://github.com/sgenoud/replicad/tree/main/packages/replicad-docs', tags: ['opensource'], }, { @@ -1572,8 +1585,7 @@ const Users: User[] = [ }, { title: 'Sapphire', - description: - 'Sapphire is a next-gen object-oriented Discord.js bot framework.', + description: 'A next-gen object-oriented Discord.js bot framework.', preview: require('./showcase/sapphire.png'), website: 'https://www.sapphirejs.dev', source: 'https://github.com/sapphiredev/website', @@ -1601,11 +1613,12 @@ const Users: User[] = [ description: 'A javascript router for front-end microservices', preview: require('./showcase/single-spa.png'), website: 'https://single-spa.js.org/', - source: 'https://github.com/single-spa/single-spa.js.org/tree/master/website', + source: + 'https://github.com/single-spa/single-spa.js.org/tree/master/website', tags: ['opensource', 'large', 'versioning', 'i18n'], }, { - title: 'Shabad OS Docs', + title: 'Shabad OS', description: 'Browse the latest docs, including tutorial guides, sample code, product articles, and API references', preview: require('./showcase/shabados.png'), @@ -1653,7 +1666,8 @@ const Users: User[] = [ 'Drop-in replacement for embed-friendly websites (and à la carte APIs for detecting and parsing them)', preview: require('./showcase/social-embed.png'), website: 'https://social-embed.git-pull.com/', - source: 'https://github.com/social-embed/social-embed/tree/master/packages/site', + source: + 'https://github.com/social-embed/social-embed/tree/master/packages/site', tags: ['opensource'], }, { @@ -1803,7 +1817,7 @@ const Users: User[] = [ { title: 'Tremor', description: - 'An early-stage event processing system for unstructured data with rich support for structural pattern-matching, filtering and transformation.', + 'Early-stage event processing system for unstructured data with structural pattern-matching, filtering and transformation', preview: require('./showcase/tremor.png'), website: 'https://www.tremor.rs/', source: 'https://github.com/tremor-rs/tremor-www', @@ -1858,7 +1872,7 @@ const Users: User[] = [ tags: ['opensource'], }, { - title: 'Warrant Docs', + title: 'Warrant', description: 'APIs and devtools for implementing authorization and access control.', preview: require('./showcase/warrant.png'), @@ -1887,7 +1901,7 @@ const Users: User[] = [ { title: 'Webiny', description: - 'Serverless Application Framework and CMS - Build Full-Stack applications, GraphQL APIs, Websites & Microservices on top of the serverless infrastructure.', + 'Serverless application framework and CMS for building full-stack applications, GraphQL APIs, websites & microservices.', preview: require('./showcase/webiny.png'), website: 'https://www.webiny.com/docs/', source: 'https://github.com/webiny/docs.webiny.com', @@ -1903,7 +1917,7 @@ const Users: User[] = [ }, { title: 'WoodpeckerCI', - description: 'Woodpecker is a simple CI engine with great extensibility.', + description: 'A simple CI engine with great extensibility.', preview: require('./showcase/woodpecker.png'), website: 'https://woodpecker-ci.org/', source: 'https://github.com/woodpecker-ci/woodpecker/tree/master/docs', @@ -1912,7 +1926,7 @@ const Users: User[] = [ { title: 'KubeVela', description: - "KubeVela is a modern application engine that adapts to your application's needs, not the other way around.", + "A modern application engine that adapts to your application's needs, not the other way around.", preview: require('./showcase/kubevela.png'), website: 'https://kubevela.io/', source: 'https://github.com/oam-dev/kubevela.io', @@ -2015,7 +2029,7 @@ const Users: User[] = [ { title: 'Matej Jellus', description: - 'IT enthusiast that loves to write code, try new things and share knowledge. If not sitting in front of computer, then I am playing badminton, riding bike or hiking.', + 'IT enthusiast that loves to write code, try new things and share knowledge.', preview: require('./showcase/juffalow.png'), website: 'https://juffalow.com/', source: null, @@ -2024,7 +2038,7 @@ const Users: User[] = [ { title: 'SigNoz', description: - 'Open source Application Performance Monitoring (APM) & Observability tool. SigNoz helps developers monitor their applications & troubleshoot problems, an open-source alternative to DataDog, NewRelic, etc. 🔥 💻', + 'Open source Application Performance Monitoring (APM), observability, and troubleshooting tool', preview: require('./showcase/signoz.png'), website: 'https://signoz.io/', source: null, @@ -2033,7 +2047,7 @@ const Users: User[] = [ { title: 'Dime.Scheduler', description: - 'Stop puzzling and start planning with Dime.Scheduler, the resource and project planning solution for the Microsoft Dynamics product suite.', + 'The resource and project planning solution for the Microsoft Dynamics product suite. Stop puzzling and start planning.', preview: require('./showcase/dimeschedulersdk.png'), website: 'https://sdk.dimescheduler.com', source: 'https://github.com/dime-scheduler/sdk-dotnet/tree/master/docs', From 3cdd038d28217bb589641c710017ad6fababdb7c Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 7 Apr 2022 16:27:28 +0800 Subject: [PATCH 123/405] docs: multiple documentation improvements (#7126) --- website/docs/advanced/routing.md | 4 +- website/docs/guides/creating-pages.md | 8 +- .../markdown-features-intro.mdx | 18 +- website/docs/using-plugins.md | 176 +++++++++--------- 4 files changed, 109 insertions(+), 97 deletions(-) diff --git a/website/docs/advanced/routing.md b/website/docs/advanced/routing.md index 9aca36f249bb..82c85b7aae12 100644 --- a/website/docs/advanced/routing.md +++ b/website/docs/advanced/routing.md @@ -257,14 +257,14 @@ If you put some HTML pages under the `static` folder, they will be copied to the <BrowserWindow> -- <Link data-noBrokenLinkCheck="true" to="/pure-html">/pure-html</Link> +- [/pure-html](/pure-html) - [pathname:///pure-html](pathname:///pure-html) </BrowserWindow> :::tip -The first link will trigger a "broken links detected" check during the production build. +The first link will **not** trigger a "broken links detected" check during the production build, because the respective file actually exists. Nevertheless, when you click on the link, a "page not found" will be displayed until you refresh. ::: diff --git a/website/docs/guides/creating-pages.md b/website/docs/guides/creating-pages.md index f8745e6cbfd7..cdf100cdf9a9 100644 --- a/website/docs/guides/creating-pages.md +++ b/website/docs/guides/creating-pages.md @@ -7,11 +7,7 @@ sidebar_label: Pages In this section, we will learn about creating pages in Docusaurus. -This is useful for creating **one-off standalone pages** like a showcase page, playground page, or support page. - -The functionality of pages is powered by `@docusaurus/plugin-content-pages`. - -You can use React components, or Markdown. +The `@docusaurus/plugin-content-pages` plugin empowers you to create **one-off standalone pages** like a showcase page, playground page, or support page. You can use React components, or Markdown. :::note @@ -69,7 +65,7 @@ You can also create TypeScript pages with the `.tsx` extension (`helloReact.tsx` Create a file `/src/pages/helloMarkdown.md`: -```mdx title="/src/pages/helloMarkdown.md" +```md title="/src/pages/helloMarkdown.md" --- title: my hello page title description: my hello page description diff --git a/website/docs/guides/markdown-features/markdown-features-intro.mdx b/website/docs/guides/markdown-features/markdown-features-intro.mdx index 77bb79d0fda1..afefc966a2ed 100644 --- a/website/docs/guides/markdown-features/markdown-features-intro.mdx +++ b/website/docs/guides/markdown-features/markdown-features-intro.mdx @@ -2,7 +2,7 @@ id: introduction title: Markdown Features sidebar_label: Introduction -description: Docusaurus uses GitHub Flavored Markdown (GFM). Find out more about Docusaurus-specific features when writing Markdown. +description: Docusaurus uses MDX. Find out more about Docusaurus-specific features when writing Markdown. slug: /markdown-features --- @@ -22,7 +22,7 @@ This section assumes you are using the official Docusaurus content plugins. Markdown is a syntax that enables you to write formatted content in a readable syntax. -The [standard Markdown syntax](https://daringfireball.net/projects/markdown/syntax) is supported, and we use [MDX](https://mdxjs.com/) as the parsing engine, which can do much more than just parsing Markdown, like rendering React components inside your documents. +We use [MDX](https://mdxjs.com/) as the parsing engine, which can do much more than just parsing [standard Markdown syntax](https://daringfireball.net/projects/markdown/syntax), like rendering React components inside your documents as well. ```md ### My Doc Section @@ -35,7 +35,7 @@ Hello world message with some **bold** text, some _italic_ text, and a [link](/) ```mdx-code-block <BrowserWindow> -<h2>My Doc Section</h2> +<h3>My Doc Section</h3> Hello world message with some **bold** text, some _italic_ text and a [link](/) @@ -44,6 +44,18 @@ Hello world message with some **bold** text, some _italic_ text and a [link](/) </BrowserWindow> ``` +<details> + +<summary>Markdown is declarative</summary> + +Some may assume a 1-1 correlation between Markdown and HTML, e.g., `![Preview](/img/docusaurus.png)` will always become `<img src="/img/docusaurus.png" alt="Preview" />`, as-is. However, _that is not the case_. + +The Markdown syntax `![message](url)` only declaratively tells Docusaurus that an image needs to be inserted here, but we may do other things like transforming a [file path to URL path](./markdown-features-assets.mdx#images), so the generated markup may differ from the output of other Markdown renderers, or a naïve hand-transcription to the equivalent JSX/HTML code. + +In general, you should only assume the _semantics_ of the markup (` ``` ` fences become [code blocks](./markdown-features-code-blocks.mdx); `>` becomes [quotes](#quotes), etc.), but not the actual compiled output. + +</details> + ## Quotes {#quotes} Markdown quotes are beautifully styled: diff --git a/website/docs/using-plugins.md b/website/docs/using-plugins.md index ac47fa25feb2..d845e4bbe6f2 100644 --- a/website/docs/using-plugins.md +++ b/website/docs/using-plugins.md @@ -29,18 +29,18 @@ module.exports = { Docusaurus can also load plugins from your local directory, with something like the following: ```js title="docusaurus.config.js" -const path = require('path'); - module.exports = { // ... // highlight-next-line - plugins: [path.resolve(__dirname, '/path/to/docusaurus-local-plugin')], + plugins: ['./src/plugins/docusaurus-local-plugin'], }; ``` +Paths should be absolute or relative to the config file. + ## Configuring plugins {#configuring-plugins} -For the most basic usage of plugins, you can provide just the plugin name or the absolute path to the plugin. +For the most basic usage of plugins, you can provide just the plugin name or the path to the plugin. However, plugins can have options specified by wrapping the name and an options object in a two-member tuple inside your config. This style is usually called "Babel Style". @@ -114,7 +114,7 @@ At most one plugin instance can be the "default plugin instance", by omitting th ## Using themes {#using-themes} -Themes are loaded in the exact same way as plugins—the line between them is blurry. From the consumer perspective, the `themes` and `plugins` entries are interchangeable when installing and configuring a plugin. The only nuance is that themes are loaded after plugins, and it's possible for [a theme to override a plugin's default theme components](./swizzling.md#theme-aliases). +Themes are loaded in the exact same way as plugins. From the consumer perspective, the `themes` and `plugins` entries are interchangeable when installing and configuring a plugin. The only nuance is that themes are loaded after plugins, and it's possible for [a theme to override a plugin's default theme components](./swizzling.md#theme-aliases). :::tip @@ -132,6 +132,76 @@ module.exports = { ## Using presets {#using-presets} +Presets are bundles of plugins and themes. For example, instead of letting you register and configure `@docusaurus/plugin-content-docs`, `@docusaurus/plugin-content-blog`, etc. one after the other in the config file, we have `@docusaurus/preset-classic` preset allows you to configure them in one centralized place. + +### `@docusaurus/preset-classic` {#docusauruspreset-classic} + +The classic preset is shipped by default to new Docusaurus websites created with [`create-docusaurus`](./installation.md#scaffold-project-website). It contains the following themes and plugins: + +- [`@docusaurus/theme-classic`](./api/themes/theme-configuration.md) +- [`@docusaurus/theme-search-algolia`](./api/themes/theme-search-algolia.md) +- [`@docusaurus/plugin-content-docs`](./api/plugins/plugin-content-docs.md) +- [`@docusaurus/plugin-content-blog`](./api/plugins/plugin-content-blog.md) +- [`@docusaurus/plugin-content-pages`](./api/plugins/plugin-content-pages.md) +- [`@docusaurus/plugin-debug`](./api/plugins/plugin-debug.md) +- [`@docusaurus/plugin-google-analytics`](./api/plugins/plugin-google-analytics.md) +- [`@docusaurus/plugin-google-gtag`](./api/plugins/plugin-google-gtag.md) +- [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) + +The classic preset will relay each option entry to the respective plugin/theme. + +```js title="docusaurus.config.js" +module.exports = { + presets: [ + [ + '@docusaurus/preset-classic', + { + // Debug defaults to true in dev, false in prod + debug: undefined, + // Will be passed to @docusaurus/theme-classic. + theme: { + customCss: [require.resolve('./src/css/custom.css')], + }, + // Will be passed to @docusaurus/plugin-content-docs (false to disable) + docs: {}, + // Will be passed to @docusaurus/plugin-content-blog (false to disable) + blog: {}, + // Will be passed to @docusaurus/plugin-content-pages (false to disable) + pages: {}, + // Will be passed to @docusaurus/plugin-content-sitemap (false to disable) + sitemap: {}, + // Will be passed to @docusaurus/plugin-google-gtag (only enabled when explicitly specified) + gtag: {}, + // Will be passed to @docusaurus/plugin-google-analytics (only enabled when explicitly specified) + googleAnalytics: {}, + }, + ], + ], +}; +``` + +In addition to these plugins and themes, `@docusaurus/theme-classic` adds [`remark-admonitions`](https://github.com/elviswolcott/remark-admonitions) as a remark plugin to `@docusaurus/plugin-content-blog` and `@docusaurus/plugin-content-docs`. + +The `admonitions` key will be passed as the [options](https://github.com/elviswolcott/remark-admonitions#options) to `remark-admonitions`. Passing `false` will prevent the plugin from being added to MDX. + +```js title="docusaurus.config.js" +module.exports = { + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + // options for remark-admonitions + admonitions: {}, + }, + }, + ], + ], +}; +``` + +### Installing presets {#installing-presets} + A preset is usually an npm package, so you install them like other npm packages using npm. ```bash npm2yarn @@ -148,21 +218,21 @@ module.exports = { }; ``` -To load presets from your local directory, specify how to resolve them: +Preset paths can be relative to the config file: ```js title="docusaurus.config.js" -const path = require('path'); - module.exports = { // ... // highlight-next-line - presets: [path.resolve(__dirname, '/path/to/docusaurus-local-preset')], + presets: ['./src/presets/docusaurus-local-preset')], }; ``` -Presets are a shorthand function to add plugins and themes to your Docusaurus config. For example, you can specify a preset that includes the following themes and plugins: +### Creating presets {#creating-presets} + +A preset is a function with the same shape as the [plugin constructor](./api/plugin-methods/README.md#plugin-constructor). It should return an object of `{ plugins: PluginConfig[], themes: PluginConfig[] }`, in the same as how they are accepted in the site config. For example, you can specify a preset that includes the following themes and plugins: -```js title="/path/to/docusaurus-local-preset" +```js title="src/presets/docusaurus-preset-multi-docs.js" module.exports = function preset(context, opts = {}) { return { themes: [['docusaurus-theme-awesome', opts.theme]], @@ -177,14 +247,14 @@ module.exports = function preset(context, opts = {}) { }; ``` -then in your Docusaurus config, you may configure the preset instead: +Then in your Docusaurus config, you may configure the preset: ```js title="docusaurus.config.js" module.exports = { presets: [ // highlight-start [ - path.resolve(__dirname, '/path/to/docusaurus-local-preset'), + './src/presets/docusaurus-preset-multi-docs.js', { theme: {hello: 'world'}, docs1: {path: '/docs'}, @@ -212,79 +282,13 @@ module.exports = { This is especially useful when some plugins and themes are intended to be used together. You can even link their options together, e.g. pass one option to multiple plugins. -### `@docusaurus/preset-classic` {#docusauruspreset-classic} - -The classic preset is shipped by default to new Docusaurus website created with [`create-docusaurus`](./installation.md#scaffold-project-website). It is a set of plugins and themes. - -| Themes | Plugins | -| --- | --- | -| [`@docusaurus/theme-classic`](./api/themes/theme-configuration.md) | [`@docusaurus/plugin-content-docs`](./api/plugins/plugin-content-docs.md) | -| [`@docusaurus/theme-search-algolia`](./api/themes/theme-search-algolia.md) | [`@docusaurus/plugin-content-blog`](./api/plugins/plugin-content-blog.md) | -| | [`@docusaurus/plugin-content-pages`](./api/plugins/plugin-content-pages.md) | -| | [`@docusaurus/plugin-debug`](./api/plugins/plugin-debug.md) | -| | [`@docusaurus/plugin-google-analytics`](./api/plugins/plugin-google-analytics.md) | -| | [`@docusaurus/plugin-google-gtag`](./api/plugins/plugin-google-gtag.md) | -| | [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) | - -To specify plugin options individually, you can provide the necessary fields to certain plugins, i.e. `customCss` for `@docusaurus/theme-classic`, pass them in the preset field, like this: - -```js title="docusaurus.config.js" -module.exports = { - presets: [ - [ - '@docusaurus/preset-classic', - { - // Debug defaults to true in dev, false in prod - debug: undefined, - // Will be passed to @docusaurus/theme-classic. - theme: { - customCss: [require.resolve('./src/css/custom.css')], - }, - // Will be passed to @docusaurus/plugin-content-docs (false to disable) - docs: {}, - // Will be passed to @docusaurus/plugin-content-blog (false to disable) - blog: {}, - // Will be passed to @docusaurus/plugin-content-pages (false to disable) - pages: {}, - // Will be passed to @docusaurus/plugin-content-sitemap (false to disable) - sitemap: {}, - // Will be passed to @docusaurus/plugin-google-gtag (only enabled when explicitly specified) - gtag: {}, - // Will be passed to @docusaurus/plugin-google-analytics (only enabled when explicitly specified) - googleAnalytics: {}, - }, - ], - ], -}; -``` - -In addition to these plugins and themes, `@docusaurus/theme-classic` adds [`remark-admonitions`](https://github.com/elviswolcott/remark-admonitions) as a remark plugin to `@docusaurus/plugin-content-blog` and `@docusaurus/plugin-content-docs`. - -The `admonitions` key will be passed as the [options](https://github.com/elviswolcott/remark-admonitions#options) to `remark-admonitions`. Passing `false` will prevent the plugin from being added to MDX. - -```js title="docusaurus.config.js" -module.exports = { - presets: [ - [ - '@docusaurus/preset-classic', - { - docs: { - // options for remark-admonitions - admonitions: {}, - }, - }, - ], - ], -}; -``` - ## Module shorthands {#module-shorthands} -Docusaurus supports shorthands for plugins, themes, and presets. When it sees a plugin / theme / preset name, it tries to load one of the following, in that order: +Docusaurus supports shorthands for plugins, themes, and presets. When it sees a plugin/theme/preset name, it tries to load one of the following, in that order: -- `[name]` -- `@docusaurus/[moduleType]-[name]` -- `docusaurus-[moduleType]-[name]`, +- `[name]` (like `content-docs`) +- `@docusaurus/[moduleType]-[name]` (like `@docusaurus/plugin-content-docs`) +- `docusaurus-[moduleType]-[name]` (like `docusaurus-plugin-content-docs`) where `moduleType` is one of `'preset'`, `'theme'`, `'plugin'`, depending on which field the module name is declared in. The first module name that's successfully found is loaded. @@ -304,10 +308,10 @@ If the name is scoped (beginning with `@`), the name is first split into scope a scope name ``` -If the name is not specified, `{scope}/docusaurus-{type}` is loaded. Otherwise, the following are attempted: +If there is no name (like `@jquery`), `[scope]/docusaurus-[moduleType]` (i.e. `@jquery/docusaurus-plugin`) is loaded. Otherwise, the following are attempted: -- `[scope]/[name]` -- `[scope]/docusaurus-[moduleType]-[name]` +- `[scope]/[name]` (like `@jquery/content-docs`) +- `[scope]/docusaurus-[moduleType]-[name]` (like `@jquery/docusaurus-plugin-content-docs`) Below are some examples, for a plugin registered in the `plugins` field. Note that unlike [ESLint](https://eslint.org/docs/user-guide/configuring/plugins#configuring-plugins) or [Babel](https://babeljs.io/docs/en/options#name-normalization) where a consistent naming convention for plugins is mandated, Docusaurus permits greater naming freedom, so the resolutions are not certain, but follows the priority defined above. From 90ee1447ba94da69f625b2a373090eb47d0ba171 Mon Sep 17 00:00:00 2001 From: Pierre-Gilles Leymarie <pierregilles.leymarie@gmail.com> Date: Thu, 7 Apr 2022 10:53:24 +0100 Subject: [PATCH 124/405] fix(theme-classic): shrink title size on mobile (#7004) --- .../src/theme/BlogPostItem/styles.module.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/styles.module.css index 612fb71f5843..824f0de78af7 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/styles.module.css @@ -9,6 +9,15 @@ font-size: 3rem; } +/** + Blog post title should be smaller on smaller devices +**/ +@media (max-width: 576px) { + .blogPostTitle { + font-size: 2rem; + } +} + .blogPostData { font-size: 0.9rem; } From b230e8a54562303b4047538f48cc3d7e415d7a93 Mon Sep 17 00:00:00 2001 From: Karl Ward <imagevuex@gmail.com> Date: Thu, 7 Apr 2022 17:16:05 +0700 Subject: [PATCH 125/405] docs: add Files Gallery website to showcase (#7125) * Update users.tsx Product website built with Docusaurus! Thanks. www.files.gallery * Added preview image for Files Gallery PNG / 2560 x 1280 * optimize image Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/src/data/showcase/files-gallery.png | Bin 0 -> 40100 bytes website/src/data/users.tsx | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 website/src/data/showcase/files-gallery.png diff --git a/website/src/data/showcase/files-gallery.png b/website/src/data/showcase/files-gallery.png new file mode 100644 index 0000000000000000000000000000000000000000..ad7d4dd15831471cdf07364ee2e4127d2708e199 GIT binary patch literal 40100 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 literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index 1ac00e201376..f2831377a659 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -583,6 +583,15 @@ const Users: User[] = [ source: 'https://github.com/1084350607/blog', tags: ['opensource', 'personal', 'i18n'], }, + { + title: 'Files Gallery', + description: + 'Single-file PHP app that can be dropped into any folder, instantly creating a gallery of files and folders.', + preview: require('./showcase/files-gallery.png'), + website: 'https://www.files.gallery/', + source: null, + tags: ['product', 'design'], + }, { title: 'KayaFolio', description: From 529d853ab86b25691acd5df11a4810fb73c5643d Mon Sep 17 00:00:00 2001 From: Lukas Bach <lukasbach@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:18:17 +0200 Subject: [PATCH 126/405] docs: add Synergies to showcase (#7127) * docs(showcase): add synergies * docs(showcase): add synergies preview file * optimize image Co-authored-by: Joshua Chen <sidachen2003@gmail.com> --- website/src/data/showcase/synergies.png | Bin 0 -> 22617 bytes website/src/data/users.tsx | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 website/src/data/showcase/synergies.png diff --git a/website/src/data/showcase/synergies.png b/website/src/data/showcase/synergies.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf2cad351faa7c6e732f69d54795541f63dda4d GIT binary patch literal 22617 zcmb5UQ;aT57p?oYZQHhO+s10!wr$(Cdv&k2ZQHhu^ZhwFcPBg9S2OjDQI%9(%&MB1 zk&5yXaM0M$0000^N>WrA000gE0DuG`LH;8+D14m%1yFM#IUxX`F&^g25bVD(kh8Lc zFraP*_Z$EK0Vv9<iqW$QGO!8KFbn+t{*qHO3keA_vI|qtu;>TY(6I>6u?gw<S5eb* zQqr>0F!30MHOrev@bC%|k<w65vr^J>2n!2SG4PSoa?vpH5m53Fkg-tE@sLt7Qcy95 z_s$Ygu#r;GF>{ND^~{h`bI`L25Ro#No12j`3K#^{;u2Aj(D24hZ2az|aPUh-^v}yH z$i<AVMhz|L8CtV*3h~LA5)qTBc$BN_nDL3oe6A%hGjlVu3uyUN2umsODQTHnI@vjS z@(2mPett`-D_4#thD9Yc&Ze@7D`F6HYN#tn$!hxe1^WfX*jQQJFT|5GiE)bQoS&VG zX_(P5uqm5+p<$EA7&_HXCew4v$w-O1cmxy_m1k$={C?e!8QaX8*_};B$7ELfq<cO- zK5??~iWwWR@Tqll^@T)P&d$yo{?S)ZGuYnUFYbvk&{dI8cMR>EGzm-di!1SRb+Jsy z*KiJUu+mi5(~QY>M!{ha*9l2!iK1eaRkAbn@ijhw{s}GU72y)FG}Y9U7M14_tm=>S zsqL<)Zq(uz?=`S&)-|P}qzr5w;ZpG2yLx34vaTxh&F+Y?ODiwQaLsM-GYYUT9!zwJ zadHnyk5$mHh-{c&-t|anH&zu-F85xjb}IQ7qVFHqH@#gy8XKFE-PqDTI6N9%6P6O| zloMg*YpavvqZJtz_B<7uRncYpM@~XZu&#ey&nZXFvV3^s>Y~rjwY+6@AS&8Mm5r0l z#4cc{H8`j!(8eQXqs@C{VwRReFS%yQDYvfd?|51J+S2hudzn{nO9dMvQ?ZIx^87*T z%t=aOa-_SRgNsf_vRPHMp_!|Rd|ZU2hl{*vYObb<nUs#VoQ|fbs<Uo3G7{SFS*8#R z+vn}^;bNz!s)v(^td_lKxM5a(RhcZWjIdVPaGs5pb(~E=sYjN)ytuoLVr+73$idpQ zmU~Z2X_{_Oqo!-~TxY}i!Ma7LbY5#xd33<z$)aJ<q)q&IkV$o_Q$=`7eAiY^h38Oc zy{gz|OcMY=2#^vLQuWxl%Ideqc}E*%%QD%cC<B%-mP(BYn_tuK2qtH->n|g6Qa5OE z#AQb}8rzs5f;7U#aZ9m)qzlD$OZ1-eik64j!3Vby5n(I=#d}GrZR#%|{S~zIvP9rB zp(0Jt|J<=Z(v)rsM_!e`dTlkCzU8o|WqrJVecf3M5hh(QjDUlMhtI<;K@s9+1t<&z z%Y&Xb0C+t=(76cD5%C<J4$6-LN(P<#0t1sl3C|Ny@j2l>QvNd~0KP1q4u+%4&qWj9 zEunraTwGEBq<BRj$N{8Ig2-Hik)rUD#1N#3V?a_z0i^!}xCx^F10YF~|AGHJ{{#Pd z{saGc{_iKn6@WA)02CI4ydw#vfIsV3MU#Z@QiQ*m24iOT%UEF%!V)1opMMbG$Ak^} zXpw>-rvFeTN|%ED%rb-s3+F=tG%8g&v!p8rB3%#y2W2Drm8^KjGqB^T#t3X6A>8j@ zmVx$@Nj&x=9qGt$r@{^FyYP)mN6pP<%EO;a5|$1JBUvx`sOBek^)cJoIb50a`15aE zr(0NlO+GH3$1*2R!Rd2(P!Psf(ZK~$;IDjc%0ZZ=6qiZuWa($l&I#TTB`pXI^D~G5 z?qsF-{N8t0j|d|aF19|zJ-ohUr#X^L<%B!$%3D=iK3~*i*V8olXy_OWb_)D{&uaS& zGpT_&PmlG`3eNK&JcXa90Wne?{BDNWxeB?OT3K_uq=<Ji)SXdH-)}JnZA$bWpNH^! zV}rSWYWaLMJ-K{uCk9@w7H$Pl_3K*}#yEI3dq16CW?$WUZb2N5vU~H4^0zkIzppkW zX50Rxt<Ki%`mpkN``xa+jsRtr(AV3?N&!V_mp0{`Q6NUBIFZ$B*M8)wP~SvPN|=;y zhY$!z!$$yi{^Wjt9xkWu`uW@*4;ZwcZj|)+-<M<bwtp8med`MZJY%HW3v>&-z9H;x z>udX;*ILkUXz<@UkG~E91@>||q9o}8RZ~jgVbGX+FX|n|d%{ibHOVe&yzJ-8DtE=% zuII7?K>~j6o>Tv|cE;z`@csFDDfBok_eO;KJ(-{U{C$9SxA*nwMd&LO(9hKMcKtm$ z^dCU}x}=dmwmUxAcx)|)0N?ZDBFxyyXitK)j&#wKKv3lvt__*HRqru0b2n8*J0ERs zlPuvGci=&8=uE$8?Dhn0u<5L`<|y{vuSbZ(&3{sy>)r9X<8?DWw(sp?`aBw0m@()o z2mkl?eb~J^`B6a1$Kg3{$60HQV)Ig_Sfl>;FuZY@fq!%9Z@QZupYA#qWUs%PgO3z% z`U3Ky42?4skVg*cu(Q=HH%{WC8F_Xf#YF3uW=NsK_zp@*WE1WQ9Vj}|fRa`mGtq#X zF(`P66j4NCvEj%7?TIVx<N-XT=o@P?XE88BQZg+v7e43%dkpr%qL;D)>7Itq?VtEp z^$ctcGDFQ<y>tf&ZK=z9QSK<)jFP(YgGkPlq$@sWLDs$rmmJIHB1-z;XENvJgW#6A zHf?RK#i<M*xW90J65GXqT#$MKdqWzMCQsSG<N+uqVx6iJ7-VGBF2<l*)WYPMQ^$t- zi=-Z?c&bpqCR&4*M35Rqm?^VTO+K=`h&c0WDkJ%XNEf9jn{!A|IJ3UrOe4W$SGYzb z9i6@bdRyO4f>f<U>f}l1mW_%?r;Nb>30m1#L`o_(lI-yexZV1dtZVUqy7sNw&*U_J z->L`0*?JAlu+`|GAdju#2v=$~qMcX?uIQFGoAz4Ye2Vq!&8th*JGbrL=Oc8j!1w*+ z(S;Rr_9!<i+VHrXe3*s)raL$M?gPU3&h4TG;aP3hIUr=Gi$S38>6CJEBVY`L!fRoC z>B<3p9V#gj@?vcNY}WqTnznX<)r&_X7!J&2l+A<wI?IB<vKViK>0ncX_1l$Gt-|7r zO=K||Vz)ZAK_>D|UW9QxFfs=vTDny+QHgqKv<kpOisxw~_P@7y*ctnA6OmB}kCQ2F zy&(V`q1Z25o#d6IH4{yyjK;%K<|??=6?07lwI;a|XEVlVVstl`AJ}hLn$>Gf3}S5W zIg7PM25Zb}Oxy>Fx@%;HYp}iwYplJYf!^SCUi<)KLF6&*_~y#YsnXUTPbGD=5eGg5 z0U01hNJblJ^LIx^Am>dF@D7=5UC6Jaux)e|i4s=e@gp_!Y+YTs{oR0q*+XqxUd$_0 zK*)O8!e9MxbGY&)KFpm;5kSu)Jm<#?{8%(RfIcuZu&OpsE;cfhA0mW$ZN@=I*q9kk zp>9($@6Zt-Q`$$Mr^^*cS!icGkO2dzb_JSp$zqF{w35PbwE3xlF@O)l>ZE_?Wc_kV zuv_ujtxt_pfq(nq+Up~{sO=0mByt6h(9s>yVIDCrS9Jvn>*gZ71=+yrxdIk46RC34 z?CM*Hf{(lMs+)+kI&D4+jkQXCT%%v#!rwN7dNrS_n*DC@3<9xm0kTz{$25#+W^}`; zwUUpV!x+A04WJOR-vrE=r=i@dDWSsXR99afl;I2LoWB@*q0+U<4(^$P^F{?ezw@%$ zNXi3t6sbJuGIKa#oCQ|x(t!IOCL%^PG%7d=xmdqc^Z|tUq3>h}5Q8lq%uu0G`{>1@ zdrIztLIgUhT0S6!Aduxx2_2B&?Ri%^WyuqgHD{{XuClw#ZV6vnt>k@1Z7G1hw4jP> zE&aP?z4AzSh@UZH*=l1Rrb}SMv`m5v?t(=yM#%b+EWC=udt1OlhA5zC5&rE35C-aM z$%eK%J7Ys%HzRxI=&DbPI#j9p%R$7}1x1wpcm)vbvDt8yd;tt5asZ|torY?imUHL> zkWq@b^6)nH0$nL8Q{3?wHG?|$8%tKL474LAS$!3Jj(|*(dT8lSRP~l!J*rTm_ks_k zcj=Ua4qRwK(p8f&D(sk6*Q#~CRgU=qI_)SyyrWd!`fR-r1-jr3Q*P6*xV9xQ1!^=- z`Z%5Y=~+Fe@3n;fvJ0mC5Ab88uF^T%8D;<j3+yzbyI$enZ%yDGjsP@B1%Tl^oS3#- znscykZz4b7TAlT*+GSOh!QK@}_Cyy4aim`8;#u1r>Ti}5W##L@<U4%9%sn_~B{csB zzzDmYFe<fldU?1sDB>&fRN40*#tRTqAFchMNo*5xEm2}ue)>297o)>9`>jG}2FgPi zORr;pE3b`cCpiF;t6-YPhjMUv0v&$^_rYtxwtPry)ZJ-6mJ)*Z128})FB_>x<kx&? z_3JvS^Ge%5mSU^vryBL%PEO+IMuI_eSO5ZVv1hH9@NLIx;*BQ|?;RU9RD${1<=^b? z)+nc|g_~cWd#3$Y&4?w&JP3DHo;FNM3z8;7({NFh5*#huC%^z`yjpzUIu$t!(R4X9 zh$N^*3w4;GhMJ}*h}w}|R25DNJ5kz)G!;>9j$iyPDCHQ8s8RW|<8;RnRxb#9sH}S9 zl;J9q>valt=F4TK+xd36wNo~L{<B5LuF&-x=GATN<t5jzvj<_b&l3sgT=0u7yqX1a z1&`L-RJ2FC`PFGNHZKo_!fU2&nWvClV|R6B<rROrkAu@~Zp9rdi`r%q$=rAI9e>WV z;&%DUthAQ-w5~ALVuRDnb#%qHra+JErrS6A=9-Ny{W>^LCpISvMf?FsaDxCB7XSC| zB3%N(T_e@<qMAi`OFw=U336!()P!MavTx53eIs_4z5eROqkFHf@+B><;$Z@adil~3 z28+i2m9kCG&el|q$ad-GnR6dppW-oXpWSZxuw~ZO8|opQ0MMl6Xw6Dj@y6EMF%-ef z&5=b>b>UVm>ej#{*mQN%+$qw<Yd)Jsl1YcBBHgW)s*S7bM!!wB;dDL;kd#1E<~mbU zmsrV-^EHM54o69Ogb?&zAtO0wQ^@^#&C_0a#J>*Q>|6pxdbqH}JuL&6Dc^P8+SRyo zk15~C<V8<70{(b@2;eYx$6l_t_t;MQr~y;8=gQM^0Rexl{29@ph1}B_+qWrYc=ECX z4LLrL3wg<leYxz3J;mA9925cUQtN_Wg$*`w6(vW5JjW`6+1S>ncV`$O^|c)^@L<K! z{^IK2dGWSL!P*)fAprSYVjtrCMe9pWZ>BRv1&$CV3ZMi<3>5|_K@viT0*Vj?QK5lE z|AYV2080PU07Z)bX+WZd|7rh&NdIs6|I_}@i&gM~Fp4^qf`dA&a~RX~+!H<Yb`j4$ zN)iIM*LaWH^_E!*HIW7q4Wv=~i2Otp;(TNe2}aS5Om%@K-0hrHU2j(Zy_0#wc(C}$ zE)v3(C@Wv&{uLj?21d>Z2OzI^z7p$9bDM&i*f|=m$m*wY^}H<XFGl6GDjR7<>P;V- z{zax3uNfOhH$5g90byYmxSXWFgJ$=ePo?|$Aifl-D^qW^F|g|m(BeTLAtdOb@N;SZ zyhx|&MOS6ha}(iz;o(d@G3`Z+)W`6CrQ{715ip#D;$h2b#IvDd7&Pw_pdWH{L4aiT z2||j4*My1u4w+*<Aw3fxQ46hS9Hj#1iC3wZ$4Gn5YEO+gzz%<hC>Z?r9`iQH-CIVJ zEkFyW%YCxzUisNa-=_UCoqBWQpF%_6PdB6L>S1l~=I*~x0!(x<BY=CwuXq7^5m9`+ z6t@^mf(ERl4Gyt*9OZMfR2BEMVrlI*>c{6`<#4Ae3Mg+*J$KrC_H7_THN5=y85~R{ zw(V6_8j5`cVLW(9R}Jd(^bTG?%cf3%9e71!tuQ3wkL+LZopo|(-fL~{=~?!er%4x; zJkRrV<{28C+`3tF<cG-IWV{fSnZ{Ng60cci`NDA>t@C{{5P%gwJsVoyZ$_ueNk0Aa zc2>pYz!pB*$C?ubKec!**|HR)RmPUJh7mn1M}u~vacBQwgf#M}?TlfZ4A6^&Pzswj z_Cpb%wmpV&e_ofo9FE*suWI{V{C0QMOCJ>vpW`jz^EN)sVzj~V=ymwAYyTmfLuCXQ zL0{-@+^@@ev*<8gz^%uN9u*IF3-Dxo?!%SK$8R1POg6}-DX&{>d?U;VE22A3!$Tx5 zE^SmYV+21KbQaN@n0QDhnLo!Myh{g1Bt`(c8%>M2?RcYYdav{7W%2Qul)B#!o#8QZ zihs#`^HF=`Yt#rnksR-l)3J-5<%35D8s)Jbsag6n_0wDk<Xnf&Y#Aa7F;!T>U^!#? zG?~#7M#!b0T{#oCriy|(bHP6v2Pb7MMAQ0#Q_=s2g}tlERZ!jEHK?oCX#TfX4{4SN zut^orgbM%=e5Wq$7(=Pc`cG|)ATR(DyS?tRY{3BUY!ua6-1?w%kh0n&2sIwC%CumN zhAB7!Mf#i8@Kn%!rLx-oulGxnt4KKAdpy8hxp6vXv?Bmru$|^STjN10B4Kq_hYB!d z_zJ;eCu%V77xn0Kd2>cc*FFgpT)<n)=f!e$s{2rRX*y*9BGBr4edKT1inF!J=?%+) zF*?vS_nrqU0O>A}EfqBO3M6g-3Az9Y9N^mn^xsjyfg7L#u8IH?#w%N4C0sH<HV;Yw zOVFo#8XO=!Wg&P;r(;#nqotG1fQ@@OHMBoK0Zj;V+Is5$Py~Jcmh1UsMCfCfyQx1# zDsX^OyMu$SKXX(-yXm9kbC?hpIC1mmoHdjoC#qFvQwD^=6*vxE-By*{%`2Qy0McTG zKur3y?|NYkyq=}S1qc3>2H_GS`i1bM142edrFgo_dXW8d96WX!<2(3KhT|<3u1nTA z)~6Qg+9w&36>g)J9b77g6D&zc@#8bU(E_Ddz<CbyN9X`^={fl<OA|~q_#6_QR)vnh zNDfoDk@zg(41zEoLir&@nl_w{Hh$26oIiKK`3ZR%4QNw<DX3%g03!MlU2biS*Y_#= zpRem?C<yzlkmBO_S@zw!YHy!Cqb8Hr=Z=m~ve?}qSF_-m$DNVc%RKxpJq{xfPPS!% zHf=@fWEB;d@emTOP66Ec-hBDXrXQd+Gn5Wq#@q#wyWBh5vs@nQoNRmqKSsV~fs`ES zs~mhA=AL|fjX}I*6&O9kn_sAcl=m(+qP(l)CJf)k#1b;Qw<L``Ajn>_qg4=~A}IN3 z1>um_OH-hF^7i1sh?8{F89drUS1t=sV0pQH$o+2VOdS?r-tm$>Cy_!uoJ6NK1t={3 zjneAR0o;985@e=<7Wa@m2(qpV7SN5){!3^N93=fhJu>cVl=)>RG0l1IJ!F71SRDp} z9yKL(Vv}Gyv_8EzpA{?~f+_=_^4}zNUD0eFF#50*)ggLu4g(tMB63P6I{fu3C4VpN zAD}Vtq6+Fn5!~xNGSE0si0dykFfDRm$2;o%O0{E6bH+rjwL`ED8K9?o=HVm^Q0*D+ z7$}9$l+4&0#c;$=Gh=-VqFJaHHj8jZHbxi;bzWe4e#7+1;RebQPDz_xl|8@wp#2BI z{SDWJ4PoiHXzIbz6re>BF$UqxdsGkJ;n2L+;V0-PRSiSu<fS=9!c@jEJ(LEDc{p5Y z6cl8VZ8hQZ5(z9eR@79s{$;<O(iCfe8NRn0Bf6H4wfG~8dG8Y}QW9O01nC-o-1)vE zNfMr)w0`%EwK!H%I=?_`4Q&9TnRH1jnb>eB*|1nB*zmr8U8x|d^zd+!YDEt3U-+qE z#Vw!XPKRap1^>0Sodov3w0UD0j6^7TC~_?0u<{;dL?WUVNq>_KHVBQhJD4)mp3cLm zFxx0qJ@lx-(R|R|goXrP8vPQxLh08&d~$1#$f)7A84CaCe``qB3QHAsR7NX~h4=Up z{Pzs3Xx+4(EV>H+FdE5rzUek6{^30Rn&A^^X0>fwYzR4Q3?{aSEAY%Zod?g0Piy2I z?Hv8P^;+D8ox<AnADMXf;nbjP)z(r^KWzEO2#X5Sm;8tTIYE8;;ao~Sa4|dE5AD#U zZqMJ#^y8zdu;_KL26T7r|J&PF8ui7<Eg8CaOZKY($&HOL)>bFplBniy;;Pt*J<s-y zIS)j5!r}EP{Kr+G+k3%f$8(0+|3_$&fWF=D6-QyQ^d{}&!!C>11ziRc)(0zAU5voD zFj8EtcD^idRcGgOUf<2F{Bd}eUgRlyE?S~lZ8JXm^hmi+yH|HC^ca|;w?9~ZW;*i$ zfqEIhODzDQ>~A=;OFsFNBdeC;m9>h`VK4AkWfUP`Z;~)zpmjCnV<kWE5`?X1?A1_8 z_-f}hdJX*DQ9#BI@`FGT7q2QBP;y1%I-MxAIU&70v7RcVa5zzcpQ3Y0v0-)V%G<p; z?c%bcpqtIf#q{gDcXB2e{&_ixm(DPMY_ob%l}{(p6X)yN=<0SUCUdzqb7o`tD}QUb zS}Y;=YMvk0y5^>zyW?29Z2(n0e!=jB;l#C`La=<yRn3k7n3@E-3$U6{r96TZH1`jj zl$!|UeG^MoyY+jo;bNVtjxUB#<<32;;s%gAF|c~)>icwiH+1v{@LC+A5K`>MFC2AF zxTD?55nu;AT@apYKiAg1Y0PM=gVSgbUN1Ti?D|{T^se6gjI!;Y_>6wNqRHX$UC&IC zfN(I#%YHp#00_(P-@9m!@q0I|@@oCK-ME+9QGEHhH+9~rtGpW7+}!unJZvV}cz8Mw zH~fskWfM{#SAueq+3eZnk7SmAI1rpdeP&+DQq)9Xf9ynNFq~4~m9ZK$$KLm=Q#af4 z+2RF?pGV;W`anbMELn8ZH?C-@(#+rklq|EQ%Rp3=wH5K+I;-7?{$aEw#+q8ri{LxB z9sw~#*-+=mlfCCft6YnCuU1yQ!1Yq#2|=DbArah0E5dbv7tfX-;t(ThQgxIsEjgEs zI9;SrxKxSnE~@Cv`#9EJs<vP1YPn7iYooI-upR|?@h??hFCcw5rZ-Na9bk`kv1?GG z{ta(Wh=zH-5Y{8Yn>Y^e5sY{qjL-S+u0Ljkb#CH?m`5)y;>P+SN~6SdaiXI9H{x%* z*5>c1G8zX)lR70OLB7?-uc97QQ7LU&CqrhJvPW)Kf8F_fF1W=+N14*Dhuy|UW9vv| z`$AkKV+3EV$~YMpA`#puIiQY-nt@S#VlL_wy9_ffmEF{CnhsOlHIUF^qKZZovr-*G zv(U009fDk{td-I*F2aA@A|VW!rM@W04QYS_pu(Rw2nteY$vwGt0|p<EUsR`?esBwF zYmU$;FoF^@M4#$3EXS5@=*lMN<e2;y7_Z3s_Y%BH*m)&=upvkg7L*CLTFn+L3y9cH zCy~iu%mZJc00<z{nKyTgF?i)z4MGhU^eEbvai{vHyFfK#dWO2+t%yEj%K+7Egcfrw ztJ)S8kU+(9n57>%Fb1h6JH>=Y8Q5L16h09!gEC1BOjyYXEnP0Jm=H8C1?|CB`~+QM zM;Mxwml_0gqo_>A2ws}W1X@?akY&@Z6-AWGT}H~-+JnlN5VL;C3bRuL+NQ)kza3u$ zE20ES->-<NjHzA$FS0iPt5!2xFacA#a_HU&`}jhNp0Wl_{jb3DtztA3_iKd&4xBB? zjfQ{t04{Gd$xFde5o!mm9sc|LabWg}Qr?miXVwHg2ui{BD{XNrcbc^6{30V|iar(2 z)Lvi<S3hnSYG_!Ly_t(jbIw!T)~52&kUAq`*U;+TFdPUkgfsz8E_J{nQ+tfGjE_vj z;*53hLI);O2VYG$YkWik(<S^|UWS(k>y4aeyBl$8XaT%5XsPdG`pv{08num0WgT`a z{vEvJ&9=}BTIytw@Xk2&?Awb~2v3X%+kSLe?7*MPZzP-FcXoCL#H#5GlOrPlG3RLs zY}mkoPYEZ5)X|LdBmtLY&|jE{6Ow_6Ym2%t4VaZoT4>b8c!EeOZmPko&;o>)5Y#-J zGBR?4$cMYj;sQmi;arkKnlL)q0iwjLYz1WoOyWbw#6YF`9$I7W<M|1#L{k)RAt?h^ zq44lXjQmn?VazZt>UR+Y9ikPjSX9o~JZy&1?Hk#g!Yvim6%jS0=j`K-nQi!RfbBsK zR{?2w*-O3NROvjyycM@voxl}k<`hh@^dAFfGCO=EpwB@3)0~M(*>OMU-jLC=yo?lG zmcC5Jh<E}BL#AHFr~|3B@kweNXIaa!vdm_^@m$E3p08oc11!{_w2+96MNf&vNGfu1 zq|o3&JU69F1qp?t)weQplT8hAN^VTh+KL<|qIKy0Q6{Qt1kBO0{n{#<g`R$;#gaNl zIG2^BNJtsXr`d38yOg^F7ZF@?H3A&F^f$HDF6BmPn$Fg(6D_SF)|^wN7H2__hBR!& z7ZllRBQ{CEW?*_j&k+AOpq9R^cCuCiyDi&zg&lh}Z%)q|2V|B2F-K1Uu^0GGgn_W$ zs4V$>2W+p2<e%qdoO}ST1E%{E*wh<GAGyI~)S?&wxCWR>g1b*PGJCb2A;NM<Ac|Df zbc9X=d<5douu5g@xZf&;;BQfxIojUUhoY4kGb1YOjO>PkcNJXXbw);{LOiA-gkb>d z(idvH)Y(2#0_K|Ur<bfQvTFEizy~=&Q4bsv!RFp#hhGg03hL(Ps-36@O}1YKE~mze zsX~0`t33(5qV|lMOD>m6|IHzSrbD~+)Nov9`^wJ6$ZGF1=1A3cvp{^02Oe<%SbV4M z)};BgV94aPwZF}dpBaJ2!1o1^0DPZl`MU{HKyI4N+&(~(5S0q)3G@^n09P@L1%&v_ zw%f4pXC5&HAATkXxMDR%E<&EG8L1TcnG67EMt2m<>$3ID7-&HjNu&aDT$4Z>afok= zAT$|04p6-;sA37t8DGGLGmq#2a3}V`$Q{!Q`+S6A^>ym+ig*qVrTec)wjfm?RqKkM z4i!C>Kh-zAIbBCp0*m^_9UT6)1>Lp<KL<mr*8;ju>CLr?5&5NWpYEL#f5b+M;>~n^ zre~f<MHBzrzc;pJuMeE8Ejx~G!*#ANL*cNK!mAoYQ;y(9Ku*M4q>2$Q@O0C1UDp~K z-=j-T!~w~^pGJ_q#<SljZ<kq#(rbII>XT`Bt7{c1r<PpCZz0s45_Ee=Exz`!L?=|) z0_(zUk0-s)Y;rv2Hsp7``rdx-ghTn&f86s=XYL)IG<M>66KK5l<awX$@Ai&=%V?}b z01I-S#%^&LNdw)H0d%3z8`N3@u<VF>uSiAvNTJCAPvk&rQK=BAr!YpfmuLWL^oFV1 zSB^q7Ix_Txzl0Cc+rS<Nf$BBR;<knxzyl(6Cw+8S!UQ#_5REo!kwKP1Q}@RC$c>&9 z&9{lf=OtiWN8z4-vrmmFjx<_b+fkZsw103`Um#cG0+#guk<@?6?7z(n#ZPjiu+!Ue z_0&6hK<s)P&B-7B9RBg^?5_Y;T!(t^ae2I{ug;n^AnvGm&Q7b^Lm0V<=k39&aTMTn zK5@LkfCj`uBhsKe>Oyp`tporvs^=BhQ2^+5w>VKifb5kkZVpU9y(A#Qx-ZCEDZ<G3 zAe=D(@t;b7nqCV^0@D(HMA(Y`j#wU$P{g{U-(&Y#wg|7q$LF5XrF$j7B_}*G>!V2^ zqE({Uk}$51qqM;Z7kjTCtW7T#91<Wj2LzzC-V~cC+lOZ4Jwp)XdE){}xB`1zt*_r~ zwu?8Oe*QvR^$+6d%Dk<k^J(KPzc?r>Wji+AjEdH{t;K_1#-*&;Y_Yc<zN6+5$B?-j zbq5dDZ8NEdwKKf|AGPT=R<>{W$MXlW3{1y?ffEy!Js1XjGQF&QZzIuP|8E)K?O>4X zrBH#kUDcQIGsp0l)MGEG-?Tw>lK+^GyM(W?`v2<%;GzToh@kniVx{xZIyRx91>aTE z0m0)!_k%XP;Ghe@vdHr-op3o<M-XMfd+hV2!c$vnAE)Coat5r;%{)<xyq+_k<D{T% z$!AwE<hM}T^$w`z{A`2;dlz0d7-4U1sP+6b!x~e0xX4|Pig3oGR+u#8MTP}sSFGZ2 z=sjyhh=IvyMH^`6i~)j}AvBCgxl<`?G1%GLR!!^aXEE#%#(gw8>1(yz9{7;8nq<b| zgeFIuA-<c7@{q#nK7NCFPW=p@dQ%$$Vqsr_8AJkeHxDgsV#G`=!x-IIkqZzYo1Rfz zm}iKSg1neCCc3iTCKWZ^dPYxyV+P^FNU@?tev#oUyo0v`bR5D-jDk8*8;ZgA0qlQJ z@4P(~bWA7*;SMBQ2IuiLFX*9LWQZ*g0_;tlfEmRg6j&%72troJB1P$rqE_1^h(#K? zkSL~VAXJqpXOaD_Rv7S_$IhkWGEl*(-;XmREn<~9C6WE_a>Ggr8iBd>qz)3Lg{mvH zi&JZ~rHrK@YOq}^Dc_D$8SO$VhHJj|6N){A9GuZ<P2IFW6aP{=F=j~K3un|M9EF-i z<Pe!Vk=%R+F~c@)V6j%1ps`Be&&+i>MH4bg^R?&@zABkOZ(Rcd!N^g!(EEcP`_YKf zGI4xY+*eVGFtr(@+{ln}CqRBiwLxpsQWz;J8!a$Kk!Gm9I=V8|GwV>%X;UF+#tX$} zJ;H=D#V{MrNRiOr^Ars&TU8&FCKB8dA)KTZ=(KYKrxa+8mlo^ArU%ux+{5~?rtvGw zN|q8YqP#=(8q|4CrOVBSmFsQvT%ZH$tq=!H&6u5C>~Kk#r7-0YFyQZ~0QBTA7HjHV zZg?!CyX^C1OyeB4&`dBeZ>Rta6u|RxcldgSPS!fO@HDk=UM&9c)U@*9(>-|VQULlW z&PTEs4U5d>e(@+~$N}I^28&EpNk>w#Mjr`JjC)p;i3-qD1dzSt(<QKWW!8>6<-#yM zNu42<N5zV3!7|hV_Y*C(Pe&3HB^)#)VdU23e7bi?AKQ;WwtxE&gI*R>%O$EMykp{I zF~kP;03yCJ^%(B2iCG+<v&@wDp`9<}3Nvr9{ObD2R{{8h0%2BEk7=Hay|#1CB**89 z(JM*2NYgKv4Ox<9rFCtHLIw_*lX5p6=s!dy4KZRxCXjko#w4UCjrB_r+1NiUM9K#k zD+3`-d#Yp9C((x4Whl^KZGA>*m~vWnj~46c(Lz~Ay<$(HK7*gJ-lvfKnb1`kDyQB1 zg#aXmT15MooTlymyQXa_P@aNYKZS`8GvOMtINYC!ysNl^d3C1$_Gs_t*q{nB;N>m7 zMfe<W@>l{xpCbu(v;e?R%7&OK5<D{}RT-4EWX6u!J(U=jgqzA-7^g};bsh(_wwb?f z(ta*8BsemP5VD5+Ii~%^^8PHpN|n9-g$&5j5~a)fXZpBQb^e>@bt2|9?sP2%*+*x8 zZD#*yzMib*O7@Ibw30&rKl*994r9&ZPK-<61>_JF?yENt3;s`Fhq1$E0K?AWEU5av zoq<<AFi#}yxIy7>AGTr!;RT$^0H;zyIpNdv*6&Ls3g1<+h&hml0=M7H%I_JbcQwlX zuR0XrBj%*OrLC%ql>jmA5)4A0KSQ7fsk-oaQk_x%OVfZ?D|$X6G9LyzdFlgL9!s>B z_+w6`S{|l#5_HJbo7}BP^*3>}6I^?K?X6Gzx5zcf%Zn)=o&4L8{D`cfC{PBD>tH?@ zaV!;5g8D_mpj-jt@_0ZA>wYraM|-_YN_%93{X{Lmp+)g3+(J|dla25^(TuD2i}mvv zDQ8yM6Wu_4c~Bn<D17S!-}@67@MuwH$@S-hscS^ys#c&b37r_ylZgY??t!|5@w}sj zRj)(Hyd??FNKgAY<_9r0i0vqRKJyM;7}{96O~<w*J~Bd%e1Je?%;*Y!yh?f2qsm-y z_RLIq_6&6e@j?HbT%<$FlfXM|+-ixct%L`KecA|4IIS&Z31Q3p*YK0>a|{}PEjZ7) zWfD#j7*QSw@^d<%f=cNncBCIQj2w^%D=98=$p0@=wBIa#Yi>4r5fBo{vojYD9hwuZ zul}07Z4(LIH)YnB*ZiRJ*B*5LH^4WE=qt|mzfZRdVnEv?s2xyH0*2$D=Du{Xl9XXh z>+MzdKik2P*U5CV!1fnEF*=|s@D|C}tZg$9H_U9k;zlB>m=U|lOSqFFP<WGQr8VQL zyI4IR><Q%xbJ|ZDGsRiRL5!N&3iAf_zgDI5VZ$5)Ka&;a%ciYg%=Q1)B1~9EXpL7e z+?yn2wvE6H?4^9y%g^38qojuV^TV=v4Y^3<dFz1%!PDFtmXfmp0ii8iM4#B$J}SIG z1?alXfmv{Z4UrXuMjiLBSIH=&ssQeMgg%k*NO+(<u<M`_!@NnjWVK|Kw(c^{BhAhi z$?5Z^iTy=yXO8O{Uqz+P4j(d>EzQJEOR^Q!b3E1qdlOoB6B`>jwT9s|o)aPEjGI+F z1f2)3Hub+Q@nGpL5PaLl#&@g8v{!zIk36jyY8RQG5M`C-^66~;J_S@#e92*9%kO*k zrW^YYt4<6znjBr{ty=^qn7ivp9sWiPY`Q)72VroVGWkEt9UgjjweSwnJl+?L&#;JN zBpn???e@@n<nlU#E`vET$Vf)05SKlbl?i9WfUDPWBJKY+8($>o=w<Q}yKQ6AJM)R* zd5W_rnm2O)vuRnjX=wnysa$scU&W3}su^lZ6F9mc8=MXiny#!P!ZO5(*wKiKjeXmJ zdVC;>etZW<a}}dg$%!H6WMi5vBVo|wHbr!oG6<0mZoxqCt{vmzCVKiiFVph8$io}w zmvn9K%hzn<ApP{!J8zdIpTMhErEH7bLoR^!gC(Q8!Uqz#tIQK6@+`gCFspaxd3#@C z`*{B5?7nc)J3eQox_VLXG!EC!Vn1vk{GFQt<HohZ_PT8&5vHl;$T?CWCYa_6`a}T? z2s&Aop+XrZQMH5WI9ryY&_Ez>E$alulWJS}k25%5vtoX59v4zin$WBRK#!2~2cdaf z<<QXneNORoFLZnLHKfaUbfml4a~p2oVbc70n#K3%L{^lcm~rpVaj1qOXBVsk$WoR( z?C#C2z`5wP`DF+bNuMFA+7kl8F8)d&#FC)Kz0jXO^+=#+c4$QgOpxmg&<%>rii8N5 z=SujzyTv|#&ATMlT^nArZ4ike?=lJd?(rrPA0bj^Z~PudK;M|zVfUrg!x=*Hm+{dG z7!B>sJ!<IR9A4%t2b_Bf8!s$sS24P+l~mX^trA*EhA)t%W|}6_;r%k8M>If!^WSO< z!%mCO^V?N_Ol)YX<=Cd<ezOr!`4ML5<=A*w&N5-F&oUV%io;pXuoiKhY(Yo$2{hMm zYM#C5<6I#+uZ2voY$8MIuY39s#AZV;v;FxkH+)1KH-rrN!;ba5E;{ib3Sc6F0iQaF zZm1tT-;@mw7v<WCfb#h?SIk_CT*{6`0mD_wnmJGrl;|wWqpKcWnZW>nPCtk=IP*U^ z#U;HzRPone$;$t3Ycj$r%OQF@+|Nao|K-FV{ep^-jFm}vzK9(A@5BK9%!C!9;m=mg zvRK`{QMa*bq<QilZ%X@=_;=DMrz&{!+FBeFDiS1$I?|fjNiMO9PMvV-7#nDDKq+FX z<L__ldIdg05C=l)AT<(GM5=ZukHpUEd2@M<XfKc#njiE&1vSyijjH9zlPe#PyvdJT zuj_MNJY@Rjs;We;Xq;Q?<Q!JWX(lmLKdGwWt)h+JM~xu}-+(;-&^(-;ZWdrKLj%>p zA`10EB~hVLe0s@T6GOq|=<Ws^9udpP9A}EM3P$hIZU|mGUb^fCZ;k<c$wXA1iE?|b zI`!k(sbkplQzGcA6(PAC+%uOomsGD8ZL23nC${Q8-M^^WW3t=|Ee6G86fwouNT8C) zF)^UQbXjXujm~P6E2nWm3K<5OsFRE-_o0jh$6`*w2;-Fc@ux!`jBJ7^V8(_$#YJZ$ zZj*xZ3dNpcXq=LW0_I^(bt#`x)#0Cj6hVQzu%EP~77z6HRctz}Fl(ocn8uDc)%#wq zc=TXR%iVPMQLD6LC}AyCAQM=5Vn(4v9HAq#%7plapl!T<LzIYMH=&Fj+g;EtY}V3i z5spg70OHF>VCW!qtpz8T>`q|^A@~&Zu)smFu<LtXhnIQr7iu<`%h<(YoY_PakmY2s zvUbdw1xqQ?Vuffziqufh!7ri)^?fNy#hO@o*oB~X^S^?#j4>H9Q*4Pxd4@BPW>4f( zAkt#M!t+f~&%*^U?dqEp65YK}_n!yrVk?47v01At-?jgmX-qt;8U(k+8P9H=rJZ4l zUy(Vk{tZKFu~%D=jIQh)T*ro(Fft(1fnS@3GY&N(Li;Si{5z!m7V}{zO%FhrBL+fB z9)Ii>j2iD*x3AjR%^@NB$Kb1?S1xZn%U6<-f3aQQ0j;~2yT8AGu7PQwQqQb8_}h~z z(DDpCWuPxQfM#IW2bRf|+9L5^;>*#NvtE`3;;zz$U@Ni(8c(m1(srrA`UBO5xK*14 z3IRPcBWu1)jr26W%j7vzhDJzF!??cElT8`t`ds=islU)<<eb(C`yLJr5_~51*<1s2 zSKW3G23QqnB6OeApi8id!{k))bZ)B;_$wZET#9)g;x0Oq1Zs5w6(b)@vujqW*mR*G z<DbV#9Sr`S3m377x8w*c9`AfIvPsEO=tn%5uE=x1T66TQlmcY+lAw_Y&eKBf?{DVx z^d*qvd1FzGSIpdb@~^i4za$|VF0X&vm_76U+&R1L4YP4N99=JPFo^Gj<U^B(Q2IFg zAYwJUf0J62Yw~5jR8New_%;?tw{#=gsF7<teeC+!SdN*$c@>~FvUA%YA&%_R%Jjmg zHXmsCY^VLZR5dFrSyNQGMPJR{UOv!8#vK><Rt8dV&585qG7DkZg#P+NE1O}TfU91- z>IZN=GS|=*e7oqFUM6<*CdD+chxG{DCBh}wTq*zBZ`av;qaqNmv=zNYJ<Qg(9_?{J zBR-EvGWWESC&-f{S8661XgsKR%5vMM#ty&rgH^MqmYXVfksas9kg3o*`NBD`+H4V1 zMr^F?)V=I(#TmgY%HBrajn3~h72-5Y%)onT-D<kNwVZ+C#lLWmaF4#M-0QboeEseG zuWVGX<Ra(o9lC#VN?K_4^$Jn(+5;u-H*1kHIK|qIWCR)^6~h^()Sq{JO-YIbzZpuw z#aJ^CNebfBe5lxIGsLJ@A+c`TFG{md&fJiO<+xudw}zJ2u~Z-z`V>M|7w`rWO3a8+ z1Lci@KiA~p?vqNg_;t1C+$(^m^A4~rd-w{jZd_)abv)lbBiL<_E+b!O{S5+4YXPx0 zV_cH#ki?t!^7Gsr&x&0l!~!G8sLkcn<iov!54QfG-;Rgg%qh~PqZw3QpPW`)mtx%h z!dnfLi9A`+sapraEoQRX<%*H7X33&gZwGM&O?U$(PuVFI3}WYwm!zwZU(09oVw>$W zshmY*Gmf#6shNu7>eaLo`db8M?>R;9*m6)Ei6@U#v7iN_EM=jtC`aqZ*_jMT(?Mr$ zow#89yv=}eE}ljm8$zWul6lZ3a&Tei(?*Ye(M}E%Tk<33KaHxubPSd3-V!{GI%gYD znmO)37wF^m(`}zd6?YeIG|tQ^wtYKoOZ;4jfJFWQCxlZ`d2Q_d+wt|V<K?gCT5#@U z-n<5iA_}zrMAa}>2<5lSM@Y|Lz|(<^u%b<j(TSZ-aA_kUfuCo8<t5AEThGh*(9l8z z9X{<NF<O^99~>X<l`@IPVUy9t$^EdtizC5pyK?t__*W5g`!EbWzSwnjaN(elC038l z)@$Eklqp!(4$>{h(x$6pbb;0BC%SHg!WMh*I5^fEdp8!KgfcZxX~!l44i8pIS`v@d z*Of7!WH@D^0A~T>0$imd2`PNC5`<V$N?bx1;x-=>9N5wd4aPwE)JiLC0_4g8dLH0~ zQQ=THZDps2SQIpQdj7ft67~Zm;;5nUrB=CBsLF5qlg;XFjhOa1(Ti4Q`z^DNph#0t z^NSSoV>v(#JzTkb>kE*(i=-JC<_KwIJ?;@yZa;&<6|XNRhjofEa7^W)-ubDd$;b`) z-UcPQD=woXDi(&)#85j4N0yJ+!>G6@RyD#Fx1K36WR}IsTBvHG#Uj$71;m7;5Rg5X zLRLO0*8VVfYY;4oW{sG0J1@#ETK=Vzw>HP-wuGUQ5&>ql-9Q~$Fm;rkP>S+N5%3Dn z(J2~Y|LlJcjKGnFB=)YcTv=|<%gctlM|~w2PduFQNQg++P0JVtWb4=;j#gsa6Z>cA z-guf*78tH~4ob>nAyeFb^4~rNJx)G8{};`eq75;-al`htcC+CHqq;;``PS4EcK@cn z5&HyY+`eacWK?vE<4(#WvyjzN+E;zE92m|rL}sE4WptmxGM&tD81c{L8UH+~ABf+u z5u3LZpCfh*ar>lTZmwjFb;Aq(<Ye4~Sn<`8?KWVRIehq*%|@)_D_&I|ung54A`B%* zrLkOs^<gyaj;lon%cR!?jWIJIh{~{yJx`P#9hWvdM>(1@2TvU9nf=JcgD96NM84ni z&M=8ixdf?Naeq-2fYNq1TEH>gx<1+2Mnz&oP?ToZ2en@=NU|3I7b5}u(ct{Wc&GWK zajVG8$cL(jY+NB6EA$3Itn8y5sk-mVdn42eU`4X<Zus4W!T0uG;v==5$qooQo|}PK z`n2aFEqZO<yL%V{Q2D;1OZ8ojl(TrxtRd>Zn9$A0iklg&`RpD#fDro}#2mD5kri^R zTu4Cy9$=AeXN*j@f%sBNGuCq6kVfpn$3P~qz;sf5##*0sD5HRYNHAA!ou&DwP2F+@ z`34}y-en@Z8$ogs<rx78DQEz1(8^NZQq5flFk)^`M8QNrK(tdWp8i8<25dcv=aaEg zQU#zOcmKK|<XDIicA5}+8r?cI)BNg{$2BJN=-S7#A1#m6GsI+Qz$jf4z{aqQs7jn? z6@Bxwi}<}E&(&=P=z=MlHF4bnG7#O*KR*VfknVxFOGynx!=n_^{+FBgdaSXa)?A7U zN=l0AgWHi>vjl-h43vcmNmluMf-+cCD2YBST_n>2kO5el1NSo@(t>1v(5f}CdCk0U z2o!n_IW8${u|gwl@yQ1)FfA%W&2kHtEprkbc>l;<NQo2O)#SA{44g<D$5h|yM8|4K zgedP|3s^3gh+WM@;9XBbX_uM>hAvh+dtGCf|2wwfgSJezF_D81{lfydu!b_CU(2vM zCmaduXI~_Wg#37Md*U-HV*=~T+$089flo--9vU?3+wSb&#*G7TY5-fkf8VhcIiZq+ zsF~hq3?)Z;$U5eFa4aKYvy#rjMHz5Cpu#D3U-w8)xtjsjoD(u4hvVy50Gk~s17l-p z7j)yGUc-M2YkI2;ig-1tJB$mn#}zAFNsr{CicW=1Srj_F2o%uu>N>YxD>!fGk4mgB zB)xsOw~rN0MHlso3yB+RiPkJBT$hR3%p1s5o!O7#qN&<2r{cr0qdJ_Si&b_-%l*Ej zS2)ICMx2$bD48(iq_rOvdAQ>n-;tThs=1?ZH#(b~!2Z0R^9MwWl6&^2mjwQE9EVAR z{|;K(B4NVvmr>q&{J3ORpb@j>r?fuDA*7A(!+t#MPVy4(T2TPg8EDk${v&!AyLbzx zGVk#tIoQ4&PCVw?IA9<(k%%L(<>%f|KuVv(M&XSMdvf6#uiw*k>$v@zOc$>f&#Dq$ z%qEmbz5ckT-c-$?i58;~w`BfVG+w83j6&DXQ)#ii?x@1cc9ln&(~#$y>Ehpej>t~B z=e$eCyRgl-R<&=1(@F6FH)6#!I=K>Mr>?iXMz`@`h23d<@RypYblN#ORlmS)Yg!ul zjw5!v(ku-d{Ttg2vjY1e7CBiuzmR)po05F(FQSVErUN!h*y5=X*x)I$E1XV?ZY$+t z1ep<7bZtH;>0=VtjEjhAET%#U&R@uzx2Lma{Dc5uZoV`5f3o9)^F;<?oaeAFF(p}p zzgahUSv4Pi4~cWHn4tT{Fnv@$&n9ZL-72p8lfH!|nk074+x{n2aQ`Y5y&B4xvEk!* ztRNmk4J_yK>Ylg(O)9%~l6}VnVKeNRvf!|71JQ#_t>e<0H5DY2CKF|j-B8cgvg^=i zW9md!^u{3CN`=)nDAfa!k<w;Kaw=LCmcu0&1NmK1%T`8Y;#NbLw*O2>^e@lA9&<*g zJZZ_xF}gVwhVqWpE>!VZbg-2qB$Wplxl{iXo3WZL9FhqE!)MZkakuu!8w-`~ow*-& zh3!+(X?n{y%fYZ0gbUGv)(%&Q(LQ0DAbAl-fN5sG_BtQSZ7<mZ9NyCttq<wD=JXji z&h#o8t&=-2q%VqWb!ExL1J49ZVNm~i1YaVfWH2mmmY&Jlo1v*fL?^vwv#@e@=OH7S z9%Z^J)3Z$Ii__D_cNwS-2ORZFk}5?*gsVq_d&=Y%OcK+bK{n#&7<QMIVu352`|3M+ z^nZi3Wl88Wg3wMO3skC@8P-SL<!F@e-UY2*bsdrU`}ai||8mSuV9jTWdOs@z#T<j> zNgW%7dV31mH;$#iq}LPyCZQX7AO2y_PZs%6+F6`r!r?ev=c7E`W4BPmj=w5wTHyM# zalb*h3zOQv2}BS-I%&ao=S*~YOh5T!EF?F-jKcxy-mR%Q-QYG*a**NiREsQeCb2Z$ zenkO#c{$x~89xDVkkm<SkE(&{QN+b9Uuq!pnbC_R7!3MU-ESyT^>!)dI^hyTpupCR zJ280(UuP#A*#o~qm5yYy5r=7}`V98nvQQOmna#x1@e6)!3;U+5lm=5Z=n?8cr4j7c z9-H0Xi~ilO3Z2{!7t!!Nc7PVC2eA%d&{39S$N6tO8MwD#+l5W>$%Tjm;7tf<w6}qR zl<Zyr8m&r~yCZ+D7U-<Wy>ZHZa+|voYE{U4bK5S5;#yI}<QIFDpkN0k)Ss22MmEWT zRKOVLf}T4v9mzp$Va`^6nqqZEO<O&BgxOTp!GW+o|7fKNF?~uwD^MTX0RqJPK+vpA za{)RKt2o$nV?}9SDfs04*#IVqB#~|zyOFNrZ#ciIk490DP#PO{>7W!N$O(OtOs=?# zJZ5__$)I>k6sRE0<Uu>EAg-kel_R#CN$g&9{;#VTejHT*cABn5A=8IHY8MUg+%h^W zTRJSq4z~1>d<$rD<v#SMRiFjgpV#MAKNC25-j>(p%e_^4__084x?!fY7YN>(0dX#0 zRRfgrI|yl@c;Uing1g2HI3-IiSf$hS4~vPz#(u(BaG+%Q-am+-=M`m&7KqZ8qUvKt z)JsxOp&5zKpuC~%S?FIty@@A)0AT|Z8Yw~ea3O)|BI_iZ{~A`&0Z!D?LY~0y{BDI{ zlb~M~|I$xG))4%#>~J&pl7g!gx!2g+Yt35)Sp($gAhU*bfk&2KugLy@e}S8cI`h2X zGtlrP==uD-z3B0@dVad+Zs@pqo!(AN$ltOr<q~kJ{a2FmO55(m;Qp~Oaqsh96*PDJ zrLuq5$E3xnFjvceO7~@*^Y2gz47T8XPVa_jdVRHLz*)1UyCGOhX*+xi*Wcg0%2lwy zS;rfdKrv5B#Pz)9EKVHlN1rzmGjLI)4ywUy!XCNT&lz?Z<$jv8guVECxKkySf+SyI zpb$!x1RjK?3Zvd8D10uJK8KEu4%)-kKsLA2)N<4jDCply!R3fdwm$SAaQy0OG~I>O zZC)JjfBWrs%W;cUW|wu{P+jG<jvcG9995ZB%Gw<8Q&m|#2f4;M?pEN(uuh#V&()}1 zEyVT@%k3{_op7oC!62khFbXm++xQ>-6EpMl(s@%@%zSSdLTuUH_49K)cKfSv31iUz zr;o3Uiu#MX{tYlNgtUYp3=#v<AYCIp(w!0mNJ>k`P=bW0bhnhGbO{0?AuSz4Np}cC z`0)SwzR!BT-MjZW_k6f(oeyX2v(Y?@?`HFj`P;nOiu|3m1~q1mt{MU2@>2bAPM@){ zisLKeSpkQ*-iLT*835GO)D?}?8quiOc{5!CYKK_-nykN&t;iH{I5#=1$D|#V{fRTE zkG2#oa{cYTm>=YyUp7@iHA#&Nz?>>p8=i4KxZ$>tP~hE8|Gc@OFE#!8yWN<D?dhnh zN|ou_wJpev-^|l(maTH6;HL|bJjsLhL`qRlKWD$F7WCrAlW_g6o}ON4?x$8Hwtj;% zH*fu;ef)6SB13i6nR-lp*(>hImlbuI<-E~+xI<H<oqo>Wr`j#IG^%(X4mQ&=Vi~&F zhH0MIHx*TJ^8p|WgArI>!g*H4r`5Mp*(f^oYZE_wP!C;I72M_%sd0rKIkH*;mokxq zl}JY8(FkSl@44xe^o{V<c_EbCVjU($P&U#GaWDBJy)~9zu_x%>b5~^Uk+!&8*W={? zNj2(sQ9kdRkrp9TUJU=22QCiyT$V)HKgE?-GW}G4WkDEqyj+rGX>v;5pz~IGk_6Bn zKW-}bf2%d=%#1qLd&~``nHn$oBozI*Q~+S5hde<Es#W_X;~!Fo625oV{}LWrAgy5L zx^j?S&xNL4cJO(-(K%KL!ucxVyV^73TroX5`i_F~?KT}Mi5PXk39u!;20%1hF(J_U zfVK(nw1=h7^1=(9-$L9ue?)Q7CFX8=ef(LNCx8zj5Kh$~S^PQaiF&t3hB!7~6E?i> zS=N9X1IB_yw<<pWSAq{V=9OIiI3%}jQhWBbsQy9)ICFg>p=s;y^|1A*G?V`%*n{^? z7q3Yt=SZssHv1XkqzGx{21E7J7A)L7l^6;m83J%%1|!A3#1D*V{p|tGPgi9QAuDZO zi~F8kIv<^>iMmG`$j^V({CcOrAxbjI3v$=7!&P<u8vp>5%m4WTRD~%p{0KXW%}b#i zgUMf`!8z?$M^q*pYqkkW?>j*rvg@1bQE%0i?N{{(?LsC{>dIkaOd=Vhjp=cwc%1@3 zi6HrWgskv@H#f9usQgH}djO=Ay;3p?p6>D<JK4%?dhZZta2`Fj;3ZpTyvP@OletC6 zLn&1NzP%tiYn&=dCaw?^p&5QZ?@FgD-r^6#F?e%@3Ao(;yUFNf;Lik*ND_IJ{(jIs zd9qDw00uJN0HfjBynWu?eBGRC6y|-cmZ_$aj(+`VRA-&(=_Kx4MA*aCx^Hx8xc;m* zU|Y%bJ!*6mYTw&f)$^&z#0bqlJ9jU7oar{$C`VJE<*1(yf<&Ir*IH*dFgNa$lubK* zi8$usUt4``R!d@bR9e#)Kb#$Wd44rAk${7?gvb+S_IP8DeJo^Ge6=ahBfuF--S(Cr zNrn0WuVXh2Z+)m0C7*w%+!Kj6@bs+0yqRxd%?O&Vwls|NG+8g4-LoNcII{$d6Z6S` zG}?ak_};5BD^I=?Gep4kB5+&aUL12SC!s}TdW{~Aac7Yj_$o-&Vf7(>K9HW2+B75E z2NQWJbK|i`3G(UGaSO10%JY;%w2j&(dzb4w+o=GMO8C`CATzYPSx8Hpa(3FNwL)-& zDz4QyXwp^?XjW&+i0+OPncbr;k5xOXp%qitceOWbI*5@~LE2^$FXOJVM*IS~JI%$h z{$khU&JKwQmEo9<<VSN<2gwBA9M-%mZdHkg0oNI^)gG*7nV1xVOhs8_KLja4o0s6- zNlw&~h8v13Zz<b}`?Nk^GexJO(K&tadQlfoe=o*sxL|(p%Gvg*=We{ThGeJva?G>v z{RVGB^w~gx3ydLHrs3?$=p>ZHO+1;MlHl;ssZy8OtC!QR)HcU}m+Ze$_}MdQxuBiB z8T|VoKccPO8V-Hi8eRIq-sQ9?yp$wOc2D({{K%AVOEDDf9VTp`re!l%jUS!9keb+y zY|jg1Q|tI06P_#3@P*-#DB;$!yZL;^0_@>JsAo8X7={BFkb}LK4!M;083xYPoTOTl z-g1}7;-L||q;}8Qki+7Xob=k43exyU#|U6UZsPv>ljMZqlEN@xj>2%hG4=43Omc0? zI#g(E<Z3SI&v$Eb*ty5Im+%WgM$N7DET?7@{C-}-h>8l?JU;Il*LNw^)gS0-?nKpz z8GQRkyr0pq5Yl9Od#ZIKYLY8=%jQJQ0+Vynd1WovVtXDCgkT>Rvk>Qli5fjQcacwH z^^NMXF#8sIoG;zZ2a?;*Ep@6Q6FZ-e1`)lxn8!lSEhi-*nQa}fG;Gu3dL9CNOXI;Z zdF&DmX-t7!bGC%3ojp$(5)S_S_Uo@m@~{L*;id^Vd0*3>k|_fRd0<lzu=erE=grd8 z*Aek*SSXBfYKp6b{c1e0Fu@O{Y5jCBJGV_X-l!k+(2>NV5%%02>fPIxd3=4yu91Te zYBHdzF5y<6ZHbO|B2r4X8R1)4NW3Ou9M%10yf*)h;hGwBU&cu1t}H3RdcMSPUu<bv zTTO4e>v4m#O55VemjKMj@(m0DkfZ#mGCHks)IZ{g9T;>H60;c`yA6`^^f3{-EBBmx z+LPYDLmR@i(%W~OiE_mCH31t`#MWl%)r>~&Zj%S&ptC)q5U6oko!`&eYuT<E8k5=1 zAf17Qn&h?jO{<jD8wdToaD8njIFHoiBwik1=oDni3V_$%XId_Q4v_~wDdRxj0W2RO zaB`6H6EYMF*1fw3fVc<mxqI-Qy9fW{0K|XX|C12t1Vm?k3!XdXvp3(}|2>&2(}ZyY z*rS7dn}Yp1LbY>t_w&%X6qj1}*n;c2cg`6?gvWJ}`wPazg*VVwNEE#r5l9cXcM+z2 zyxYEWs&38H4!+NsdEi!!e?tS{s8_!4!MdIJc?+3Ge_cMmaN1S;(1I?|K;Obb5<)ur zgCJ%2u>oRxhu-Z{^PyEUzo8(Xo`-GGUS%%2I9N5;UrhE~+FhX4gc2Yh&ke>7zHtrp z+)AReuE45BZxiMmQWOrl+{=C$ko@mAaG;<je?a4a3<bl7V;xC>a7F~Ex>Fvreqld) zwQAOa(Fd>@<<IC$U;rL5{D@1ZR2Nr{eo=#gSimqG#(TCJ-p+g)`auLpMRZMTupEKi z_aNycXF<#$Q9A%jig}lW!Kp{wi?27eAKs67+=)t)_2R&N*4yx44bryql8UdorlX_d zW51_^#q#X#g{9N{nb&(z^UQ_TtF<mar%eScR}{C!pFSA|>_xS_F@JZL)09%fKN4J5 z=a@gs0(JyCc29IjgbzQfuS(UxcY<>sU$Z^*=S0;^npb~XUc$F{s4VOVs0)-HxDmx; zWlc!@6&4ZirOU_&IedS+O3War(l#+ej>5*X;5uKd8R@v}t2&Ury8hEHA%i9G&-O4D znV~!k>@DWaf5}Q$q;8`-L`)4J5>#x)-bNWdsf<g2e4+{AFzr%jSWs|R6V7E5xATJ& zK{oP|I185^4`4{oSvx3XlNV0H;m+&w&sR@Ir^^;p7zVH*@+^h^qNV?0_eqsYet}sd zufB=yp6~g1WnSHk3{|!xyn=RN=^uZFK2N)JdYWXP);~NHOTn#v%2LX;#$p_T3X1zc zpPDgXc(1Wn6=oQDwK{v_^i(}U<(1AA)dioJ9E3~zNK{4HQ`piFs<fm%(^T841S+o} z3=&WZMQmx?caFmqHDmBo|9NG8K+`|4@_od78-yJFDVl0+p9G=F%w)!Jafa~V^&xf` z@N0iUxL7UmdX&fBD4$U@e3sh|!^IyS#S^27K9uR?X-WsHexRvqSb=#2wGb(a=kO`T zimi@}(1_f!;5nA!jMWxND%z0oDF;(bBK=fsC|LaCw>a{j8+pj9jBVtanZgur*!EZ; z!yDR@%1!pTgXG)tpmJ{_Wo9(d#0wQW(%nuj759rjqBL@$+#>etDkC3hnyh>9e_@N+ zk|*J(s%nBfjLI^X@cjkuRqhYNzRFMJH67=w7c5#VX{-i+zRu5cVNuzi2u6Sl<C!@x zBCzyVXh>URK7}@XEA3V$`OIw6S0A3URm}u3{{Be0j-o};VM8r2xk!OCBm9G;j$!dj zuCvOZsd=8;OuMhvd<r+1Ov^-^$x!(T=#VT`7_KbM^YOm`f#H51s8P0Y=dW$8Zpx(; z8<g(U28!0g7n%$Ca|bGDqNf|NNu}EWx8Y?wh!M&^&sSK@%_iot4`SE;2bPC_qbiOL zwZg;(^AStE_M+e6Pet&7wv`j~qn&$rn#$s_jm2RJ{r%~~){<iOrSD)STteLaJ^{59 z+HBk(AdUT0F<^!oNugv}*|aqjw+SpHODIdj(5Q~m7+Mgq$R(s{s^S*tD2Wh(tx^5N z$IlY-3^pP3J?2vtQiA)To4+PxHRo=^x5UWq!-^xM-)0mw6@BPPU`>>u_%7XL+Wn&V zI(MXy^|^1ah6uH{kzwS%XRs#O;PB=(=SELA-)~Ozj*gjQ4z~ZB@Bd_|ol0+FT?flY zCi75wY|tQjLa;nY3r<NY^C=$7S=0rif)KhaVxc^$H(NKksaGWo;{Hl-<M011)hx_h zwTc+~c$}Uc&DNpZCQ3%o)Q{WIKUiWUa&Y2AV3u9s;AhzeXC;V&vO`0$o<Inqa#4`` z!~b`?hyS;r{}Yz615I~a(loNs8Ak}XCNU+V%Wef6T_RBV+rBaIjKn%}h3piY*&mt% zR-9NPE52rwy$=<+Qp}!*#VibzRVR`MfP9;c%N^LXGI>`F<JwUy`5_rRxptongvlHQ z5ZX>{2u;1;8}7}E⋘LdOnyLFA?xbtM0>f`*oWP?Yg{~b<HNzhAxE!q^+;Lo}HAF zz_%0be5$9tWqMx>@r_fMUi1;n&CRuyA6>~(E|W&yy$-@jTzuW}Bu_IKIyxb!ux*J$ zb9;OHrAxM>-Xe~6hvb|ZLb+|Eg~i#qdD^mGd%s!3FU9{rKI9oQUJq(Pphk~Uq%h@O zN9QxEe7NWkm1~M3NW>i8MMe;&VCF(+6~!a2KcP<qa~#t${W5dFeM9+O4d12dmyz=j z`wX_9Mn<D1%OYotJ?Wg}h+GBU_na88$s=dI-#dKePV%<--EWb7H<FmS6t~2K^sSc( zNS`dMxrQq&3^BG9v0XLyb>xx`%iLcCxjA86iSqeTx28iLBBs19<e~k>j0(qR{v89N zo)Qq4Ff&qa=>$t0;~~dbcR}yL9{Km|eSe*DG4d;ev&1sGEP}@<xx#9x^_O!wvY=bm z=u3T0<_Y_#T83!a=9jik{MAR@BfnEk{W?2{LA}%IJkP<F!`<!3CAr4v!!pz@6SZf1 zo_MR;?Xd>qV!a%N`}a!b<``nL4?ZC#c)Sfwf|>}Nz3E8l%R_X{t1Ebry~FB_*+*~0 z@RS@zB;;u9wzbpgw4%8<<S5uw0v-2+a0<KhN{a;cg4m?JWpFzrWkpvkn_^JC#76JX zEg%>~*Q+T0xXhISdzLanWHvD+vJ1?wR*Sp_sYMBkVkv&^R=Hj3(5&jd7k7E1OM2cp zOoUzc5i`6YdY!N|Bau+9+Nn7j$d=UM;SkIw^-adZ>P%I7iV+cMWiI3$km@%_O?wne zGkx{`<3c{~C+WEbA2z{d>Sh}AAsI>gq2+#V^@zY2hcl$dRae!c4C6?YMedIF%cMJB zc@G1F$A@C=CT1$Cvw?HW-&)CzZUs++9h4)Ai`m8}nnUbd%11rNqs;J!<G04lBIYeX z^~|$HraLP`YY8#1IHl$iewl}==8Vm5?2G|k&~K?e;==qGEoq-Xd6O41b%S{E!HI?# z@v`EHni;s~O3oZ|Rm=Jgw(&0o%G-lG#gyCJ5XeI_NkyQLNX-B4%c;o2c-ge<s-HW3 z=4ZkScL%!Vnm@IE+L1?8Rz7~Uop2ZgOH=#2QJgM(PP6fYfaXZ}an$WrEPpyJQSn)- zh<D!aIcNC?w^~b#gF!abOQ|TSB!$kOYvu}nZP@N@Lwa2gnQo6Yt<A5ume1%q;GS+4 zb9B=DwUfaxzT^78w)+L=^^y4$BF?M~OJ itzYZ2!vtIlR;mf*^fC6Dx<j76s@_ z38o-{e;v>{r?v^E2}1}-t>L)~fnzOX@u?k7w{FIFk6O$|(f)&+mo2%FIAOoU7#m8l z-H(Ij^m>V3bFy`YGKt1MP^f5-E#rgiP3PQMbc^Zt#O_wkj!il`?GdhKw2S_%;^-_I z$nWE#ki@1R?512fXX#kt0nh&?>!;4nvCg&+GMU7ys>Qyjwf35RLF}>2(>lRHc;J^x zB9;}cCy=(YKkn}@2>a3W`NH+mr^456-AL|C^53}i^MGcDRdFySSSfSJoGJeOap)kc zr_Umvp?%?PZSf%UX<TTGPHO|lle3BZ*79MtGDh>cr5*P}Qk$iT4JuVh>xGUO>c8-o zG@ZrPUd3MUm?nRk?!)X_e+s+^IxdUIiS_kn3|lcWg++<thN;<a^L@?b_iuuPR)1E5 z0m@#RZ)Q#d;{gQ=rD9|_dnIsq6;B4vtSU+QjQmkIL4sZCO0+PAstfDKEcn;7*X}Ec z_)76=|1j~}t!24W;`E<#W9@QeQX9)T%j6|mkfKJ?IZrA@u+p3U_^%sD(6(*esK`#> zHwTA!RW^*Yv<7=@lf0?OAu?}YkO~-{yP01p?_QkdQPzb&0%iF-lX!dIo84V=ShuyP zUAp`DT+TIoUEFlI3VwNTaJL&_e7f&=#sRxC$fj)*e$eaIW^V{BB6_>)I88jD+_;*H zQ``NP*=uz?t<Z`BcQM^(JMs17UtRF2vDuaGJg8HYlN6+Abf*xfT_rvg&-|Kkt7v-Q zy;&e{MLyqxuBIjBfa59QZSr!Y%hL6o?7t!Gf8r=gIYkTgL01hUa%#;mm0x459v`-8 zA=@P}d6Mc%i;07A68JxL3PnI`nLfClO72Zv2Y{;tC!qXn^A+<Z_$V#o*1>48iiT~x zciA^al$w(N50?5I1#x6#O415npD#kQ=jE%g7|H&`D1=vcKHTDwX1LUiw-obmcq9{X z(*+E;;60c)&kAf2^Q%^=a{e;Tc-)bI6?vsy`XRKdTbE~9^vQgO18cCP$@V-G@QQp& zlTEK*<YdXekWVXC*uB}k`H-)Mp+m4WrJsJkLf%cRqbOh_R5Z74yIB2xBz+s(=#Bg8 zC3M*R4u5$55G72844m=1<j^8}Xrpr}d`hld_&A5Ds!n{32(Bx@j2Px~jxNu70PV%6 zL#vKiJT3kGA-vF9JX?RwOR_RO)PmrBEW*;=LpzEvfd!wsI=jvuDb}uP8fT?uNQ~=h zt#*A2O>eFXUp)Nbk6AzII^cG^=DDRk)UW;(+2zAFMu5!6m5S4Kiwa2P)QyW^KoLef zU5AICM1qu}lL`Gfq4EG1>lCj7-McBD0tcKb2E71uC{Plv9&D|>*XWsO!=gJeC!{vP zijZw7ydP98PA%D|PdV>Gw%PAD24<D(_to+K&K%76M9|jh)mt$KvUFMix0}FG@2mn7 z>+2J~Rv|X$bPY8VwH&D4?{k(X>2(cnJzpxplx04W%03Qvsu#2>uAyv|J4>Alh@~fF z*!lJVI*4;Po)fTEwG|)FkE&{19%W>ZufaAOp>%IH!h_>+em8|AK>UI48!#HtA7J_7 zBMAV%j0r`pMFbU58Ym$IS?qfP!9zpH5w+8efCjNDC!rWkj)u?H<<67}vmY$IUhv4q zTOJEM^MP=uZ7LXU-nSsfw_T^zJn^?!C`a3Q7E)G<N7Az*KulZwCRh34#lUVzP|ow9 zh16slcG+&blOM_8ujhOEoXHWI!cZ!w<F_Q&tbI3RsLJiU#<QJY8Rch@*XE!A$|5We xjk1k#w*e5}5d~m0;+AjfP}l;r{L=uw0h;bjZmGoJ$$M{L0HL5RUny%5`afX3-xdG> literal 0 HcmV?d00001 diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index f2831377a659..bc6221df7e1c 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -1745,6 +1745,15 @@ const Users: User[] = [ source: 'https://github.com/supabase/supabase/tree/master/web', tags: ['opensource', 'favorite', 'design', 'large', 'product'], }, + { + title: 'Synergies', + description: + 'A performant and distributed state library for creating reusable React state logic by synergyzing atomar context pieces', + preview: require('./showcase/synergies.png'), + website: 'https://synergies.js.org', + source: 'https://github.com/lukasbach/synergies/tree/main/packages/docs', + tags: ['opensource', 'design'], + }, { title: 'T-Regx', description: 'Programmer-oriented Regular Expressions library for PHP', From bfbc78e52a56944d73552d15c30dcd9fc6b7563f Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Thu, 7 Apr 2022 13:33:52 +0300 Subject: [PATCH 127/405] feat: allow using pure HTML as label in navbar links (#7079) Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> --- .../src/__tests__/validateThemeConfig.test.ts | 18 ++++- .../src/theme-classic.d.ts | 1 + .../src/theme/NavbarItem/NavbarNavLink.tsx | 66 ++++++++++++------- .../src/validateThemeConfig.ts | 2 + .../docs/api/themes/theme-configuration.md | 3 + 5 files changed, 63 insertions(+), 27 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index a333f882b58c..6fe62bb524ec 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -112,6 +112,13 @@ describe('themeConfig', () => { docId: 'intro', label: 'Introduction', }, + // Doc link with HTML as label + { + type: 'doc', + position: 'left', + docId: 'intro', + html: '<b>Introduction</b>', + }, // Regular link { to: '/guide/', @@ -119,6 +126,13 @@ describe('themeConfig', () => { position: 'left', activeBaseRegex: '/guide/', }, + // Regular link with HTML as label + { + to: '/guide/', + html: '<b>Guide</b>', + position: 'left', + activeBaseRegex: '/guide/', + }, // Regular dropdown { label: 'Community', @@ -136,10 +150,10 @@ describe('themeConfig', () => { }, ], }, - // Dropdown with name + // Dropdown with label as HTML { type: 'dropdown', - label: 'Tools', + label: 'Tools <sup>new</sup>', position: 'left', items: [ { diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 9f3c48ed3da0..cde00cc5c6d9 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -651,6 +651,7 @@ declare module '@theme/NavbarItem/NavbarNavLink' { readonly activeBaseRegex?: string; readonly exact?: boolean; readonly label?: ReactNode; + readonly html?: string; readonly prependBaseUrlToHref?: string; } diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx index af498982f6f1..e19758815f6d 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx @@ -21,6 +21,7 @@ export default function NavbarNavLink({ to, href, label, + html, activeClassName = '', prependBaseUrlToHref, ...props @@ -33,32 +34,47 @@ export default function NavbarNavLink({ const isExternalLink = label && href && !isInternalUrl(href); const isDropdownLink = activeClassName === dropdownLinkActiveClass; + // Link content is set through html XOR label + const linkContentProps = html + ? {dangerouslySetInnerHTML: {__html: html}} + : { + children: ( + <> + {label} + {isExternalLink && ( + <IconExternalLink + {...(isDropdownLink && {width: 12, height: 12})} + /> + )} + </> + ), + }; + + if (href) { + return ( + <Link + href={prependBaseUrlToHref ? normalizedHref : href} + {...props} + {...linkContentProps} + /> + ); + } + return ( <Link - {...(href - ? { - href: prependBaseUrlToHref ? normalizedHref : href, - } - : { - isNavLink: true, - activeClassName: !props.className?.includes(activeClassName) - ? activeClassName - : '', - to: toUrl, - ...(activeBasePath || activeBaseRegex - ? { - isActive: (_match, location) => - activeBaseRegex - ? isRegexpStringMatch(activeBaseRegex, location.pathname) - : location.pathname.startsWith(activeBaseUrl), - } - : null), - })} - {...props}> - {label} - {isExternalLink && ( - <IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} /> - )} - </Link> + to={toUrl} + isNavLink + activeClassName={ + !props.className?.includes(activeClassName) ? activeClassName : '' + } + {...((activeBasePath || activeBaseRegex) && { + isActive: (_match, location) => + activeBaseRegex + ? isRegexpStringMatch(activeBaseRegex, location.pathname) + : location.pathname.startsWith(activeBaseUrl), + })} + {...props} + {...linkContentProps} + /> ); } diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts index 8de448ea652a..c1687093695d 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.ts +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.ts @@ -49,8 +49,10 @@ const NavbarItemPosition = Joi.string().equal('left', 'right').default('left'); const NavbarItemBaseSchema = Joi.object({ label: Joi.string(), + html: Joi.string(), className: Joi.string(), }) + .nand('html', 'label') // We allow any unknown attributes on the links (users may need additional // attributes like target, aria-role, data-customAttribute...) .unknown(); diff --git a/website/docs/api/themes/theme-configuration.md b/website/docs/api/themes/theme-configuration.md index d954079d52bb..fd1e4ac30659 100644 --- a/website/docs/api/themes/theme-configuration.md +++ b/website/docs/api/themes/theme-configuration.md @@ -259,6 +259,7 @@ Accepted fields: | --- | --- | --- | --- | | `type` | `'default'` | Optional | Sets the type of this item to a link. | | `label` | `string` | **Required** | The name to be shown for this item. | +| `html` | `string` | Optional | Same as `label`, but renders pure HTML instead of text content. | | `to` | `string` | **Required** | Client-side routing, used for navigating within the website. The baseUrl will be automatically prepended to this value. | | `href` | `string` | **Required** | A full-page navigation, used for navigating outside of the website. **Only one of `to` or `href` should be used.** | | `prependBaseUrlToHref` | `boolean` | `false` | Prepends the baseUrl to `href` values. | @@ -288,6 +289,8 @@ module.exports = { // Only one of "to" or "href" should be used // href: 'https://www.facebook.com', label: 'Introduction', + // Only one of "label" or "html" should be used + // html: '<b>Introduction</b>' position: 'left', activeBaseRegex: 'docs/(next|v8)', target: '_blank', From 0963bff5e7a35410e3f7c89a4f61ba667691c23e Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn <lex61rus@gmail.com> Date: Thu, 7 Apr 2022 13:59:47 +0300 Subject: [PATCH 128/405] feat(preset-classic): exclude debug plugin routes from sitemap (#7122) --- packages/docusaurus-plugin-debug/src/index.ts | 16 +++++++++------- .../src/plugin-debug.d.ts | 4 ++++ packages/docusaurus-preset-classic/src/index.ts | 12 +++++++++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/docusaurus-plugin-debug/src/index.ts b/packages/docusaurus-plugin-debug/src/index.ts index 01a9e0a4e03f..26fcc297a9d3 100644 --- a/packages/docusaurus-plugin-debug/src/index.ts +++ b/packages/docusaurus-plugin-debug/src/index.ts @@ -9,6 +9,8 @@ import type {LoadContext, Plugin} from '@docusaurus/types'; import {docuHash, normalizeUrl, posixPath} from '@docusaurus/utils'; import path from 'path'; +export const routeBasePath = '__docusaurus/debug'; + export default function pluginDebug({ siteConfig: {baseUrl}, generatedFilesDir, @@ -40,37 +42,37 @@ export default function pluginDebug({ // Home is config (duplicate for now) addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug']), + path: normalizeUrl([baseUrl, routeBasePath]), component: '@theme/DebugConfig', exact: true, }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/config']), + path: normalizeUrl([baseUrl, routeBasePath, 'config']), component: '@theme/DebugConfig', exact: true, }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/metadata']), + path: normalizeUrl([baseUrl, routeBasePath, 'metadata']), component: '@theme/DebugSiteMetadata', exact: true, }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/registry']), + path: normalizeUrl([baseUrl, routeBasePath, 'registry']), component: '@theme/DebugRegistry', exact: true, }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/routes']), + path: normalizeUrl([baseUrl, routeBasePath, 'routes']), component: '@theme/DebugRoutes', exact: true, }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/content']), + path: normalizeUrl([baseUrl, routeBasePath, 'content']), component: '@theme/DebugContent', exact: true, modules: { @@ -79,7 +81,7 @@ export default function pluginDebug({ }); addRoute({ - path: normalizeUrl([baseUrl, '__docusaurus/debug/globalData']), + path: normalizeUrl([baseUrl, routeBasePath, 'globalData']), component: '@theme/DebugGlobalData', exact: true, }); diff --git a/packages/docusaurus-plugin-debug/src/plugin-debug.d.ts b/packages/docusaurus-plugin-debug/src/plugin-debug.d.ts index 93b666dd4f31..6bde34dab9bc 100644 --- a/packages/docusaurus-plugin-debug/src/plugin-debug.d.ts +++ b/packages/docusaurus-plugin-debug/src/plugin-debug.d.ts @@ -7,6 +7,10 @@ /// <reference types="@docusaurus/module-type-aliases" /> +declare module '@docusaurus/plugin-debug' { + export const routeBasePath: string; +} + declare module '@theme/DebugConfig' { export default function DebugMetadata(): JSX.Element; } diff --git a/packages/docusaurus-preset-classic/src/index.ts b/packages/docusaurus-preset-classic/src/index.ts index e3059a520665..79a60b65c9c7 100644 --- a/packages/docusaurus-preset-classic/src/index.ts +++ b/packages/docusaurus-preset-classic/src/index.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {routeBasePath as debugPluginRouteBasePath} from '@docusaurus/plugin-debug'; import type { Preset, LoadContext, @@ -28,7 +29,7 @@ export default function preset( opts: Options = {}, ): Preset { const {siteConfig} = context; - const {themeConfig} = siteConfig; + const {themeConfig, baseUrl} = siteConfig; const {algolia} = themeConfig as Partial<ThemeConfig>; const isProd = process.env.NODE_ENV === 'production'; const { @@ -36,12 +37,13 @@ export default function preset( docs, blog, pages, - sitemap, + sitemap = {}, theme, googleAnalytics, gtag, ...rest } = opts; + const isDebugEnabled = debug || (debug === undefined && !isProd); const themes: PluginConfig[] = []; themes.push(makePluginConfig('@docusaurus/theme-classic', theme)); @@ -74,13 +76,17 @@ export default function preset( makePluginConfig('@docusaurus/plugin-google-analytics', googleAnalytics), ); } - if (debug || (debug === undefined && !isProd)) { + if (isDebugEnabled) { plugins.push(require.resolve('@docusaurus/plugin-debug')); } if (gtag) { plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag)); } if (isProd && sitemap !== false) { + if (isDebugEnabled) { + sitemap.ignorePatterns ??= []; + sitemap.ignorePatterns.push(`${baseUrl}${debugPluginRouteBasePath}/**`); + } plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap)); } if (Object.keys(rest).length > 0) { From f9c0a5a6d504114284fb9a72427488736744cc76 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 7 Apr 2022 21:27:20 +0800 Subject: [PATCH 129/405] feat(core): allow plugin/preset config to contain false/null (#7124) --- packages/docusaurus-types/src/index.d.ts | 10 ++++++++-- .../src/server/__tests__/configValidation.test.ts | 10 ++++++++++ packages/docusaurus/src/server/configValidation.ts | 3 ++- .../__tests__/__fixtures__/presets/preset-mixed.js | 4 ++-- .../__tests__/__snapshots__/presets.test.ts.snap | 2 ++ packages/docusaurus/src/server/plugins/configs.ts | 4 ++-- packages/docusaurus/src/server/plugins/presets.ts | 7 +++++-- 7 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 7d24b70a47e7..7a5b9ad5ecd5 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -27,9 +27,15 @@ export type PluginConfig = | string | [string, PluginOptions] | [PluginModule, PluginOptions] - | PluginModule; + | PluginModule + | false + | null; -export type PresetConfig = string | [string, {[key: string]: unknown}]; +export type PresetConfig = + | string + | [string, {[key: string]: unknown}] + | false + | null; export type ThemeConfig = { [key: string]: unknown; diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index b6d606b41701..1f8838efa7fc 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -173,6 +173,7 @@ describe('normalizeConfig', () => { 'should accept [function, object] for plugin', [[() => {}, {it: 'should work'}]], ], + ['should accept false/null for plugin', [false, null, 'classic']], ])(`%s for the input of: %p`, (_message, plugins) => { expect(() => { normalizeConfig({ @@ -211,6 +212,7 @@ describe('normalizeConfig', () => { 'should accept [function, object] for theme', [[function theme() {}, {it: 'should work'}]], ], + ['should accept false/null for themes', [false, null, 'classic']], ])(`%s for the input of: %p`, (_message, themes) => { expect(() => { normalizeConfig({ @@ -254,6 +256,14 @@ describe('normalizeConfig', () => { `); }); + it('accepts presets as false / null', () => { + expect(() => { + normalizeConfig({ + presets: [false, null, 'classic'], + }); + }).not.toThrow(); + }); + it("throws error if scripts doesn't have src", () => { expect(() => { normalizeConfig({ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index a25659ae892e..74f3836b0e9f 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -71,7 +71,7 @@ function createPluginSchema(theme: boolean) { Joi.array() .ordered(Joi.string().required(), Joi.object().required()) .length(2), - Joi.bool().equal(false), // In case of conditional adding of plugins. + Joi.any().valid(false, null), ) // @ts-expect-error: bad lib def, doesn't recognize an array of reports .error((errors) => { @@ -119,6 +119,7 @@ const PresetSchema = Joi.alternatives() Joi.array() .items(Joi.string().required(), Joi.object().required()) .length(2), + Joi.any().valid(false, null), ) .messages({ 'alternatives.types': `{#label} does not look like a valid preset config. A preset config entry should be one of: diff --git a/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js b/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js index fdd55264f67d..bbe10eaa44fd 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js +++ b/packages/docusaurus/src/server/plugins/__tests__/__fixtures__/presets/preset-mixed.js @@ -7,7 +7,7 @@ module.exports = function preset(context, opts = {}) { return { - themes: [['@docusaurus/theme-classic', opts.test]], - plugins: [['@docusaurus/plugin-test', opts.test]], + themes: [['@docusaurus/theme-classic', opts.test], null], + plugins: [['@docusaurus/plugin-test', opts.test], false], }; }; diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap index 84f8e1be4bfe..d5da620ec554 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/presets.test.ts.snap @@ -107,6 +107,7 @@ exports[`loadPresets mixed form with themes 1`] = ` "@docusaurus/plugin-test", undefined, ], + false, ], "themes": [ [ @@ -121,6 +122,7 @@ exports[`loadPresets mixed form with themes 1`] = ` "@docusaurus/theme-classic", undefined, ], + null, ], } `; diff --git a/packages/docusaurus/src/server/plugins/configs.ts b/packages/docusaurus/src/server/plugins/configs.ts index 2662ddc69b99..5c4b7711c0e6 100644 --- a/packages/docusaurus/src/server/plugins/configs.ts +++ b/packages/docusaurus/src/server/plugins/configs.ts @@ -17,7 +17,7 @@ import type { } from '@docusaurus/types'; async function normalizePluginConfig( - pluginConfig: PluginConfig, + pluginConfig: Exclude<PluginConfig, false | null>, configPath: string, pluginRequire: NodeRequire, ): Promise<NormalizedPluginConfig> { @@ -120,7 +120,7 @@ export async function loadPluginConfigs( // Site config should be the highest priority. ...standalonePlugins, ...standaloneThemes, - ]; + ].filter(<T>(x: T | null | false): x is T => Boolean(x)); return Promise.all( pluginConfigs.map((pluginConfig) => normalizePluginConfig( diff --git a/packages/docusaurus/src/server/plugins/presets.ts b/packages/docusaurus/src/server/plugins/presets.ts index 877150cc6703..27788b747d80 100644 --- a/packages/docusaurus/src/server/plugins/presets.ts +++ b/packages/docusaurus/src/server/plugins/presets.ts @@ -33,6 +33,9 @@ export async function loadPresets( presets.forEach((presetItem) => { let presetModuleImport: string; let presetOptions = {}; + if (!presetItem) { + return; + } if (typeof presetItem === 'string') { presetModuleImport = presetItem; } else { @@ -53,10 +56,10 @@ export async function loadPresets( ); if (preset.plugins) { - plugins.push(...preset.plugins.filter(Boolean)); + plugins.push(...preset.plugins); } if (preset.themes) { - themes.push(...preset.themes.filter(Boolean)); + themes.push(...preset.themes); } }); From ca718ccac001e0c5cf5ef8ce7b4185be01656b96 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 7 Apr 2022 21:56:50 +0800 Subject: [PATCH 130/405] refactor(theme-classic): blog mobile secondary menu use consistent styles (#7068) --- .../src/theme-classic.d.ts | 22 +++++++- .../src/theme/BlogLayout/index.tsx | 6 +- .../src/theme/BlogSidebar/Desktop/index.tsx | 45 +++++++++++++++ .../{ => Desktop}/styles.module.css | 6 +- .../src/theme/BlogSidebar/Mobile/index.tsx | 38 +++++++++++++ .../src/theme/BlogSidebar/index.tsx | 56 +++---------------- 6 files changed, 113 insertions(+), 60 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx rename packages/docusaurus-theme-classic/src/theme/BlogSidebar/{ => Desktop}/styles.module.css (95%) create mode 100644 packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index cde00cc5c6d9..5e58568bb857 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -47,13 +47,33 @@ declare module '@theme/BlogListPaginator' { export default function BlogListPaginator(props: Props): JSX.Element; } -declare module '@theme/BlogSidebar' { +declare module '@theme/BlogSidebar/Desktop' { + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; + + export interface Props { + readonly sidebar: BlogSidebar; + } + + export default function BlogSidebarDesktop(props: Props): JSX.Element; +} + +declare module '@theme/BlogSidebar/Mobile' { import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; export interface Props { readonly sidebar: BlogSidebar; } + export default function BlogSidebarMobile(props: Props): JSX.Element; +} + +declare module '@theme/BlogSidebar' { + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; + + export interface Props { + readonly sidebar?: BlogSidebar; + } + export default function BlogSidebar(props: Props): JSX.Element; } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx index 009eef93276d..30d68822c650 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx @@ -20,11 +20,7 @@ export default function BlogLayout(props: Props): JSX.Element { <Layout {...layoutProps}> <div className="container margin-vert--lg"> <div className="row"> - {hasSidebar && ( - <aside className="col col--3"> - <BlogSidebar sidebar={sidebar} /> - </aside> - )} + <BlogSidebar sidebar={sidebar} /> <main className={clsx('col', { 'col--7': hasSidebar, diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx new file mode 100644 index 000000000000..15e5cecb70d5 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx @@ -0,0 +1,45 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import clsx from 'clsx'; +import Link from '@docusaurus/Link'; +import {translate} from '@docusaurus/Translate'; + +import styles from './styles.module.css'; +import type {Props} from '@theme/BlogSidebar/Desktop'; + +export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element { + return ( + <aside className="col col--3"> + <nav + className={clsx(styles.sidebar, 'thin-scrollbar')} + aria-label={translate({ + id: 'theme.blog.sidebar.navAriaLabel', + message: 'Blog recent posts navigation', + description: 'The ARIA label for recent posts in the blog sidebar', + })}> + <div className={clsx(styles.sidebarItemTitle, 'margin-bottom--md')}> + {sidebar.title} + </div> + <ul className={styles.sidebarItemList}> + {sidebar.items.map((item) => ( + <li key={item.permalink} className={styles.sidebarItem}> + <Link + isNavLink + to={item.permalink} + className={styles.sidebarItemLink} + activeClassName={styles.sidebarItemLinkActive}> + {item.title} + </Link> + </li> + ))} + </ul> + </nav> + </aside> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css similarity index 95% rename from packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css index d3e7700af508..3ca0d4b8d5e7 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css @@ -40,11 +40,7 @@ } @media (max-width: 996px) { - .sidebarDesktop { - display: none; - } - .sidebar { - top: 0; + display: none; } } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx new file mode 100644 index 000000000000..a07967840419 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Link from '@docusaurus/Link'; +import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common'; +import type {Props} from '@theme/BlogSidebar/Mobile'; + +function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element { + return ( + <ul className="menu__list"> + {sidebar.items.map((item) => ( + <li key={item.permalink} className="menu__list-item"> + <Link + isNavLink + to={item.permalink} + className="menu__link" + activeClassName="menu__link--active"> + {item.title} + </Link> + </li> + ))} + </ul> + ); +} + +export default function BlogSidebarMobile(props: Props): JSX.Element { + return ( + <NavbarSecondaryMenuFiller + component={BlogSidebarMobileSecondaryMenu} + props={props} + /> + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx index ad478860fe42..742f4bd42781 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/index.tsx @@ -6,61 +6,19 @@ */ import React from 'react'; -import clsx from 'clsx'; -import Link from '@docusaurus/Link'; -import {translate} from '@docusaurus/Translate'; -import { - NavbarSecondaryMenuFiller, - useWindowSize, -} from '@docusaurus/theme-common'; +import BlogSidebarDesktop from '@theme/BlogSidebar/Desktop'; +import BlogSidebarMobile from '@theme/BlogSidebar/Mobile'; +import {useWindowSize} from '@docusaurus/theme-common'; import type {Props} from '@theme/BlogSidebar'; -import styles from './styles.module.css'; -function BlogSidebarContent({ - sidebar, - className, -}: Props & {className?: string}): JSX.Element { - return ( - <nav - className={clsx(styles.sidebar, 'thin-scrollbar', className)} - aria-label={translate({ - id: 'theme.blog.sidebar.navAriaLabel', - message: 'Blog recent posts navigation', - description: 'The ARIA label for recent posts in the blog sidebar', - })}> - <div className={clsx(styles.sidebarItemTitle, 'margin-bottom--md')}> - {sidebar.title} - </div> - <ul className={styles.sidebarItemList}> - {sidebar.items.map((item) => ( - <li key={item.permalink} className={styles.sidebarItem}> - <Link - isNavLink - to={item.permalink} - className={styles.sidebarItemLink} - activeClassName={styles.sidebarItemLinkActive}> - {item.title} - </Link> - </li> - ))} - </ul> - </nav> - ); -} - -export default function BlogSidebar(props: Props): JSX.Element | null { +export default function BlogSidebar({sidebar}: Props): JSX.Element | null { const windowSize = useWindowSize(); - if (props.sidebar.items.length === 0) { + if (!sidebar?.items.length) { return null; } // Mobile sidebar doesn't need to be server-rendered if (windowSize === 'mobile') { - return ( - <NavbarSecondaryMenuFiller - component={BlogSidebarContent} - props={{...props, className: 'margin-left--md'}} - /> - ); + return <BlogSidebarMobile sidebar={sidebar} />; } - return <BlogSidebarContent {...props} className={styles.sidebarDesktop} />; + return <BlogSidebarDesktop sidebar={sidebar} />; } From 1156be3f20faeb5aca4497a5f53d17978d79f115 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Thu, 7 Apr 2022 21:58:21 +0800 Subject: [PATCH 131/405] refactor(content-{blog,docs}): unify handling of tags (#7117) --- .../__snapshots__/index.test.ts.snap | 8 +- .../src/blogUtils.ts | 2 +- .../src/index.ts | 92 +++++++++---------- .../src/plugin-content-blog.d.ts | 26 ++---- .../src/types.ts | 13 +-- .../__snapshots__/index.test.ts.snap | 66 +++++++------ .../src/__tests__/props.test.ts | 5 +- .../src/index.ts | 4 +- .../src/plugin-content-docs.d.ts | 26 ++---- .../src/props.ts | 7 +- .../src/types.ts | 5 +- .../src/theme-classic.d.ts | 6 +- .../src/theme/BlogTagsListPage/index.tsx | 5 +- .../src/theme/BlogTagsPostsPage/index.tsx | 13 ++- .../src/theme/DocTagDocListPage/index.tsx | 7 +- .../src/theme/Tag/index.tsx | 6 +- .../src/theme/TagsListInline/index.tsx | 2 +- packages/docusaurus-theme-common/src/index.ts | 1 - .../src/utils/__tests__/tagUtils.test.ts | 12 +-- .../src/utils/tagsUtils.ts | 13 +-- packages/docusaurus-types/src/index.d.ts | 19 ++++ .../src/validationSchemas.ts | 2 +- packages/docusaurus-utils/src/index.ts | 1 - packages/docusaurus-utils/src/tags.ts | 7 +- 24 files changed, 170 insertions(+), 178 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap index 1eab791d4450..c19351278b5f 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap @@ -8,7 +8,7 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` "/another/tags", "/another/tags2", ], - "name": "tag1", + "label": "tag1", "pages": [ { "items": [ @@ -36,7 +36,7 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` "/another/tags", "/another/tags2", ], - "name": "tag2", + "label": "tag2", "pages": [ { "items": [ @@ -69,7 +69,7 @@ exports[`blog plugin works with blog tags 1`] = ` "/another/tags", "/another/tags2", ], - "name": "tag1", + "label": "tag1", "pages": [ { "items": [ @@ -112,7 +112,7 @@ exports[`blog plugin works with blog tags 1`] = ` "/another/tags", "/another/tags2", ], - "name": "tag2", + "label": "tag2", "pages": [ { "items": [ diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index b1823bb6d68d..8138d1ab8b00 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -114,7 +114,7 @@ export function getBlogTags({ ); return _.mapValues(groups, ({tag, items: tagBlogPosts}) => ({ - name: tag.label, + label: tag.label, items: tagBlogPosts.map((item) => item.id), permalink: tag.permalink, pages: paginateBlogPosts({ diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 3414d2820a07..c5538be08235 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -30,7 +30,13 @@ import type { BlogContentPaths, BlogMarkdownLoaderOptions, } from './types'; -import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; +import type { + LoadContext, + Plugin, + HtmlTags, + TagsListItem, + TagModule, +} from '@docusaurus/types'; import { generateBlogPosts, getSourceToPermalink, @@ -43,7 +49,6 @@ import type { BlogPostFrontMatter, BlogPostMetadata, Assets, - TagModule, } from '@docusaurus/plugin-content-blog'; export default async function pluginContentBlog( @@ -117,6 +122,8 @@ export default async function pluginContentBlog( blogSidebarTitle, } = options; + const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]); + const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]); const blogPosts = await generateBlogPosts(contentPaths, context, options); if (!blogPosts.length) { @@ -125,7 +132,7 @@ export default async function pluginContentBlog( blogPosts: [], blogListPaginated: [], blogTags: {}, - blogTagsListPath: null, + blogTagsListPath, blogTagsPaginated: [], }; } @@ -150,8 +157,6 @@ export default async function pluginContentBlog( } }); - const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]); - const blogListPaginated: BlogPaginated[] = paginateBlogPosts({ blogPosts, blogTitle, @@ -167,11 +172,6 @@ export default async function pluginContentBlog( blogTitle, }); - const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]); - - const blogTagsListPath = - Object.keys(blogTags).length > 0 ? tagsPath : null; - return { blogSidebarTitle, blogPosts, @@ -307,30 +307,47 @@ export default async function pluginContentBlog( }), ); - // Tags. - if (blogTagsListPath === null) { + // Tags. This is the last part so we early-return if there are no tags. + if (Object.keys(blogTags).length === 0) { return; } - const tagsModule: {[tagName: string]: TagModule} = Object.fromEntries( - Object.entries(blogTags).map(([, tag]) => { - const tagModule: TagModule = { - allTagsPath: blogTagsListPath, - name: tag.name, - count: tag.items.length, - permalink: tag.permalink, - }; - return [tag.name, tagModule]; - }), - ); + async function createTagsListPage() { + const tagsProp: TagsListItem[] = Object.values(blogTags).map((tag) => ({ + label: tag.label, + permalink: tag.permalink, + count: tag.items.length, + })); - async function createTagRoutes(tag: BlogTag): Promise<void> { + const tagsPropPath = await createData( + `${docuHash(`${blogTagsListPath}-tags`)}.json`, + JSON.stringify(tagsProp, null, 2), + ); + + addRoute({ + path: blogTagsListPath, + component: blogTagsListComponent, + exact: true, + modules: { + sidebar: aliasedSource(sidebarProp), + tags: aliasedSource(tagsPropPath), + }, + }); + } + + async function createTagPostsListPage(tag: BlogTag): Promise<void> { await Promise.all( tag.pages.map(async (blogPaginated) => { const {metadata, items} = blogPaginated; - const tagsMetadataPath = await createData( + const tagProp: TagModule = { + label: tag.label, + permalink: tag.permalink, + allTagsPath: blogTagsListPath, + count: tag.items.length, + }; + const tagPropPath = await createData( `${docuHash(metadata.permalink)}.json`, - JSON.stringify(tagsModule[tag.name], null, 2), + JSON.stringify(tagProp, null, 2), ); const listMetadataPath = await createData( @@ -356,7 +373,7 @@ export default async function pluginContentBlog( }, }; }), - metadata: aliasedSource(tagsMetadataPath), + tag: aliasedSource(tagPropPath), listMetadata: aliasedSource(listMetadataPath), }, }); @@ -364,25 +381,8 @@ export default async function pluginContentBlog( ); } - await Promise.all(Object.values(blogTags).map(createTagRoutes)); - - // Only create /tags page if there are tags. - if (Object.keys(blogTags).length > 0) { - const tagsListPath = await createData( - `${docuHash(`${blogTagsListPath}-tags`)}.json`, - JSON.stringify(tagsModule, null, 2), - ); - - addRoute({ - path: blogTagsListPath, - component: blogTagsListComponent, - exact: true, - modules: { - sidebar: aliasedSource(sidebarProp), - tags: aliasedSource(tagsListPath), - }, - }); - } + await createTagsListPage(); + await Promise.all(Object.values(blogTags).map(createTagPostsListPage)); }, translateContent({content, translationFiles}) { diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index 1733bff9bc16..939ae794289f 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -7,8 +7,9 @@ declare module '@docusaurus/plugin-content-blog' { import type {MDXOptions} from '@docusaurus/mdx-loader'; - import type {FrontMatterTag, Tag} from '@docusaurus/utils'; + import type {FrontMatterTag} from '@docusaurus/utils'; import type {Overwrite} from 'utility-types'; + import type {Tag} from '@docusaurus/types'; export type Assets = { /** @@ -406,17 +407,6 @@ declare module '@docusaurus/plugin-content-blog' { } >; - export type TagModule = { - /** Permalink of the tag's own page. */ - permalink: string; - /** Name of the tag. */ - name: string; - /** Number of posts with this tag. */ - count: number; - /** The tags list page. */ - allTagsPath: string; - }; - export type BlogSidebar = { title: string; items: {title: string; permalink: string}[]; @@ -511,28 +501,30 @@ declare module '@theme/BlogListPage' { } declare module '@theme/BlogTagsListPage' { - import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog'; + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; + import type {TagsListItem} from '@docusaurus/types'; export interface Props { /** Blog sidebar. */ readonly sidebar: BlogSidebar; - /** A map from tag names to the full tag module. */ - readonly tags: Readonly<{[tagName: string]: TagModule}>; + /** All tags declared in this blog. */ + readonly tags: TagsListItem[]; } export default function BlogTagsListPage(props: Props): JSX.Element; } declare module '@theme/BlogTagsPostsPage' { - import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog'; + import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; import type {Content} from '@theme/BlogPostPage'; import type {Metadata} from '@theme/BlogListPage'; + import type {TagModule} from '@docusaurus/types'; export interface Props { /** Blog sidebar. */ readonly sidebar: BlogSidebar; /** Metadata of this tag. */ - readonly metadata: TagModule; + readonly tag: TagModule; /** Looks exactly the same as the posts list page */ readonly listMetadata: Metadata; /** diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index 220ddbf1d579..84f76fa92753 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -6,6 +6,7 @@ */ import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils'; +import type {Tag} from '@docusaurus/types'; import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog'; import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage'; @@ -16,22 +17,16 @@ export type BlogContent = { blogPosts: BlogPost[]; blogListPaginated: BlogPaginated[]; blogTags: BlogTags; - blogTagsListPath: string | null; + blogTagsListPath: string; }; export type BlogTags = { - // TODO, the key is the tag slug/permalink - // This is due to legacy frontmatter: tags: - // [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}] - // Soon we should forbid declaring permalink through frontmatter - [tagKey: string]: BlogTag; + [permalink: string]: BlogTag; }; -export type BlogTag = { - name: string; +export type BlogTag = Tag & { /** Blog post permalinks. */ items: string[]; - permalink: string; pages: BlogPaginated[]; }; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 55f087ee4e7d..2af71ead7b26 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -714,9 +714,11 @@ exports[`simple website content: data 1`] = ` } }", "tag-docs-tags-tag-1-b3f.json": "{ - \\"name\\": \\"tag 1\\", + \\"label\\": \\"tag 1\\", \\"permalink\\": \\"/docs/tags/tag-1\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/tags\\", + \\"count\\": 2, + \\"items\\": [ { \\"id\\": \\"foo/baz\\", \\"title\\": \\"baz\\", @@ -729,48 +731,49 @@ exports[`simple website content: data 1`] = ` \\"description\\": \\"Hi, Endilie here :)\\", \\"permalink\\": \\"/docs/\\" } - ], - \\"allTagsPath\\": \\"/docs/tags\\" + ] }", "tag-docs-tags-tag-2-custom-permalink-825.json": "{ - \\"name\\": \\"tag 2\\", + \\"label\\": \\"tag 2\\", \\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/tags\\", + \\"count\\": 1, + \\"items\\": [ { \\"id\\": \\"foo/baz\\", \\"title\\": \\"baz\\", \\"description\\": \\"Images\\", \\"permalink\\": \\"/docs/foo/bazSlug.html\\" } - ], - \\"allTagsPath\\": \\"/docs/tags\\" + ] }", "tag-docs-tags-tag-3-ab5.json": "{ - \\"name\\": \\"tag 3\\", + \\"label\\": \\"tag 3\\", \\"permalink\\": \\"/docs/tags/tag-3\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/tags\\", + \\"count\\": 1, + \\"items\\": [ { \\"id\\": \\"hello\\", \\"title\\": \\"Hello, World !\\", \\"description\\": \\"Hi, Endilie here :)\\", \\"permalink\\": \\"/docs/\\" } - ], - \\"allTagsPath\\": \\"/docs/tags\\" + ] }", "tags-list-current-prop-15a.json": "[ { - \\"name\\": \\"tag 1\\", + \\"label\\": \\"tag 1\\", \\"permalink\\": \\"/docs/tags/tag-1\\", \\"count\\": 2 }, { - \\"name\\": \\"tag 2\\", + \\"label\\": \\"tag 2\\", \\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\", \\"count\\": 1 }, { - \\"name\\": \\"tag 3\\", + \\"label\\": \\"tag 3\\", \\"permalink\\": \\"/docs/tags/tag-3\\", \\"count\\": 1 } @@ -3172,57 +3175,60 @@ exports[`versioned website content: data 1`] = ` } }", "tag-docs-next-tags-bar-tag-1-a8f.json": "{ - \\"name\\": \\"barTag 1\\", + \\"label\\": \\"barTag 1\\", \\"permalink\\": \\"/docs/next/tags/bar-tag-1\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/next/tags\\", + \\"count\\": 1, + \\"items\\": [ { \\"id\\": \\"foo/bar\\", \\"title\\": \\"bar\\", \\"description\\": \\"This is next version of bar.\\", \\"permalink\\": \\"/docs/next/foo/barSlug\\" } - ], - \\"allTagsPath\\": \\"/docs/next/tags\\" + ] }", "tag-docs-next-tags-bar-tag-2-216.json": "{ - \\"name\\": \\"barTag-2\\", + \\"label\\": \\"barTag-2\\", \\"permalink\\": \\"/docs/next/tags/bar-tag-2\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/next/tags\\", + \\"count\\": 1, + \\"items\\": [ { \\"id\\": \\"foo/bar\\", \\"title\\": \\"bar\\", \\"description\\": \\"This is next version of bar.\\", \\"permalink\\": \\"/docs/next/foo/barSlug\\" } - ], - \\"allTagsPath\\": \\"/docs/next/tags\\" + ] }", "tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{ - \\"name\\": \\"barTag 3\\", + \\"label\\": \\"barTag 3\\", \\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\", - \\"docs\\": [ + \\"allTagsPath\\": \\"/docs/next/tags\\", + \\"count\\": 1, + \\"items\\": [ { \\"id\\": \\"foo/bar\\", \\"title\\": \\"bar\\", \\"description\\": \\"This is next version of bar.\\", \\"permalink\\": \\"/docs/next/foo/barSlug\\" } - ], - \\"allTagsPath\\": \\"/docs/next/tags\\" + ] }", "tags-list-current-prop-15a.json": "[ { - \\"name\\": \\"barTag 1\\", + \\"label\\": \\"barTag 1\\", \\"permalink\\": \\"/docs/next/tags/bar-tag-1\\", \\"count\\": 1 }, { - \\"name\\": \\"barTag-2\\", + \\"label\\": \\"barTag-2\\", \\"permalink\\": \\"/docs/next/tags/bar-tag-2\\", \\"count\\": 1 }, { - \\"name\\": \\"barTag 3\\", + \\"label\\": \\"barTag 3\\", \\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\", \\"count\\": 1 } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts index 86bd7b88fc27..db2648c5e5d7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts @@ -54,9 +54,10 @@ describe('toTagDocListProp', () => { expect(result).toEqual({ allTagsPath, - name: tag.label, + count: 2, + label: tag.label, permalink: tag.permalink, - docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence + items: [doc3, doc1], // docs sorted by title, ignore "id5" absence }); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index a0dc21768960..b8e7c121148b 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -228,13 +228,13 @@ export default async function pluginContentDocs( const tagsProp: PropTagsListPage['tags'] = Object.values( versionTags, ).map((tagValue) => ({ - name: tagValue.label, + label: tagValue.label, permalink: tagValue.permalink, count: tagValue.docIds.length, })); // Only create /tags page if there are tags. - if (Object.keys(tagsProp).length > 0) { + if (tagsProp.length > 0) { const tagsPropPath = await createData( `${docuHash(`tags-list-${version.versionName}-prop`)}.json`, JSON.stringify(tagsProp, null, 2), diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 271bfa4923db..77d4b7b894c0 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -7,7 +7,8 @@ declare module '@docusaurus/plugin-content-docs' { import type {MDXOptions} from '@docusaurus/mdx-loader'; - import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils'; + import type {ContentPaths, FrontMatterTag} from '@docusaurus/utils'; + import type {TagsListItem, TagModule, Tag} from '@docusaurus/types'; import type {Required} from 'utility-types'; export type Assets = { @@ -483,25 +484,14 @@ declare module '@docusaurus/plugin-content-docs' { export type PropSidebar = import('./sidebars/types').PropSidebar; export type PropSidebars = import('./sidebars/types').PropSidebars; - export type PropTagDocListDoc = { - id: string; - title: string; - description: string; - permalink: string; - }; - export type PropTagDocList = { - allTagsPath: string; - name: string; // normalized name/label of the tag - permalink: string; // pathname of the tag - docs: PropTagDocListDoc[]; - }; + export type PropTagDocListDoc = Pick< + DocMetadata, + 'id' | 'title' | 'description' | 'permalink' + >; + export type PropTagDocList = TagModule & {items: PropTagDocListDoc[]}; export type PropTagsListPage = { - tags: { - name: string; - permalink: string; - count: number; - }[]; + tags: TagsListItem[]; }; } diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index d25888db63a8..43d3028d455c 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -137,7 +137,7 @@ export function toTagDocListProp({ }: { allTagsPath: string; tag: VersionTag; - docs: Pick<DocMetadata, 'id' | 'title' | 'description' | 'permalink'>[]; + docs: DocMetadata[]; }): PropTagDocList { function toDocListProp(): PropTagDocListDoc[] { const list = _.compact( @@ -154,9 +154,10 @@ export function toTagDocListProp({ } return { - name: tag.label, + label: tag.label, permalink: tag.permalink, - docs: toDocListProp(), allTagsPath, + count: tag.docIds.length, + items: toDocListProp(), }; } diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 909a200da7e4..bb9f8e8e15d1 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -8,13 +8,14 @@ /// <reference types="@docusaurus/module-type-aliases" /> import type {Sidebars} from './sidebars/types'; -import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils'; +import type {BrokenMarkdownLink} from '@docusaurus/utils'; import type { VersionMetadata, LastUpdateData, DocMetadata, CategoryGeneratedIndexMetadata, } from '@docusaurus/plugin-content-docs'; +import type {Tag} from '@docusaurus/types'; export type DocFile = { contentPath: string; // /!\ may be localized @@ -33,7 +34,7 @@ export type VersionTag = Tag & { docIds: string[]; }; export type VersionTags = { - [key: string]: VersionTag; + [permalink: string]: VersionTag; }; export type LoadedVersion = VersionMetadata & { diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 5e58568bb857..7c0deb7dc60a 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -1031,7 +1031,7 @@ declare module '@theme/IconExternalLink' { } declare module '@theme/TagsListByLetter' { - import type {TagsListItem} from '@docusaurus/theme-common'; + import type {TagsListItem} from '@docusaurus/types'; export interface Props { readonly tags: readonly TagsListItem[]; @@ -1040,7 +1040,7 @@ declare module '@theme/TagsListByLetter' { } declare module '@theme/TagsListInline' { - import type {Tag} from '@docusaurus/utils'; + import type {Tag} from '@docusaurus/types'; export interface Props { readonly tags: readonly Tag[]; @@ -1049,7 +1049,7 @@ declare module '@theme/TagsListInline' { } declare module '@theme/Tag' { - import type {TagsListItem} from '@docusaurus/theme-common'; + import type {TagsListItem} from '@docusaurus/types'; import type {Optional} from 'utility-types'; export interface Props extends Optional<TagsListItem, 'count'> {} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx index 1124e06aaa37..2f53b6ee41fa 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx @@ -19,8 +19,7 @@ import { import SearchMetadata from '../SearchMetadata'; import clsx from 'clsx'; -export default function BlogTagsListPage(props: Props): JSX.Element { - const {tags, sidebar} = props; +export default function BlogTagsListPage({tags, sidebar}: Props): JSX.Element { const title = translateTagsPageTitle(); return ( <HtmlClassNameProvider @@ -32,7 +31,7 @@ export default function BlogTagsListPage(props: Props): JSX.Element { <SearchMetadata tag="blog_tags_list" /> <BlogLayout sidebar={sidebar}> <h1>{title}</h1> - <TagsListByLetter tags={Object.values(tags)} /> + <TagsListByLetter tags={tags} /> </BlogLayout> </HtmlClassNameProvider> ); diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx index fa3bf26a2437..fddda0795d75 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx @@ -40,9 +40,12 @@ function useBlogPostsPlural() { ); } -export default function BlogTagsPostsPage(props: Props): JSX.Element { - const {metadata, items, sidebar, listMetadata} = props; - const {allTagsPath, name: tagName, count} = metadata; +export default function BlogTagsPostsPage({ + tag, + items, + sidebar, + listMetadata, +}: Props): JSX.Element { const blogPostsPlural = useBlogPostsPlural(); const title = translate( { @@ -50,7 +53,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element { description: 'The title of the page for a blog tag', message: '{nPosts} tagged with "{tagName}"', }, - {nPosts: blogPostsPlural(count), tagName}, + {nPosts: blogPostsPlural(tag.count), tagName: tag.label}, ); return ( @@ -65,7 +68,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element { <header className="margin-bottom--xl"> <h1>{title}</h1> - <Link href={allTagsPath}> + <Link href={tag.allTagsPath}> <Translate id="theme.tags.tagsPageLink" description="The label of the link targeting the tag list page"> diff --git a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx index 512eabc4a892..22cf3ff7ac9b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx @@ -15,7 +15,6 @@ import { ThemeClassNames, usePluralForm, } from '@docusaurus/theme-common'; -import type {PropTagDocListDoc} from '@docusaurus/plugin-content-docs'; import Translate, {translate} from '@docusaurus/Translate'; import type {Props} from '@theme/DocTagDocListPage'; import SearchMetadata from '@theme/SearchMetadata'; @@ -39,7 +38,7 @@ function useNDocsTaggedPlural() { ); } -function DocItem({doc}: {doc: PropTagDocListDoc}): JSX.Element { +function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element { return ( <article className="margin-vert--lg"> <Link to={doc.permalink}> @@ -58,7 +57,7 @@ export default function DocTagDocListPage({tag}: Props): JSX.Element { description: 'The title of the page for a docs tag', message: '{nDocsTagged} with "{tagName}"', }, - {nDocsTagged: nDocsTaggedPlural(tag.docs.length), tagName: tag.name}, + {nDocsTagged: nDocsTaggedPlural(tag.count), tagName: tag.label}, ); return ( @@ -84,7 +83,7 @@ export default function DocTagDocListPage({tag}: Props): JSX.Element { </Link> </header> <section className="margin-vert--lg"> - {tag.docs.map((doc) => ( + {tag.items.map((doc) => ( <DocItem key={doc.id} doc={doc} /> ))} </section> diff --git a/packages/docusaurus-theme-classic/src/theme/Tag/index.tsx b/packages/docusaurus-theme-classic/src/theme/Tag/index.tsx index ffe3ea717df3..3b04395d3954 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tag/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tag/index.tsx @@ -12,9 +12,7 @@ import type {Props} from '@theme/Tag'; import styles from './styles.module.css'; -export default function Tag(props: Props): JSX.Element { - const {permalink, name, count} = props; - +export default function Tag({permalink, label, count}: Props): JSX.Element { return ( <Link href={permalink} @@ -22,7 +20,7 @@ export default function Tag(props: Props): JSX.Element { styles.tag, count ? styles.tagWithCount : styles.tagRegular, )}> - {name} + {label} {count && <span>{count}</span>} </Link> ); diff --git a/packages/docusaurus-theme-classic/src/theme/TagsListInline/index.tsx b/packages/docusaurus-theme-classic/src/theme/TagsListInline/index.tsx index abf7bb497f78..b0b6fdaff5eb 100644 --- a/packages/docusaurus-theme-classic/src/theme/TagsListInline/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/TagsListInline/index.tsx @@ -26,7 +26,7 @@ export default function TagsListInline({tags}: Props): JSX.Element { <ul className={clsx(styles.tags, 'padding--none', 'margin-left--sm')}> {tags.map(({label, permalink: tagPermalink}) => ( <li key={tagPermalink} className={styles.tag}> - <Tag name={label} permalink={tagPermalink} /> + <Tag label={label} permalink={tagPermalink} /> </li> ))} </ul> diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 77afa2fdfd21..97b0de33a583 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -86,7 +86,6 @@ export { translateTagsPageTitle, listTagsByLetters, type TagLetterEntry, - type TagsListItem, } from './utils/tagsUtils'; export {useHistoryPopHandler} from './utils/historyUtils'; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts index 2de931f7e047..4e1f614d7702 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/tagUtils.test.ts @@ -15,32 +15,32 @@ describe('listTagsByLetters', () => { it('creates letters list', () => { const tag1: Tag = { - name: 'tag1', + label: 'tag1', permalink: '/tag1', count: 1, }; const tag2: Tag = { - name: 'Tag2', + label: 'Tag2', permalink: '/tag2', count: 11, }; const tagZxy: Tag = { - name: 'zxy', + label: 'zxy', permalink: '/zxy', count: 987, }; const tagAbc: Tag = { - name: 'Abc', + label: 'Abc', permalink: '/abc', count: 123, }; const tagDef: Tag = { - name: 'def', + label: 'def', permalink: '/def', count: 1, }; const tagAaa: Tag = { - name: 'aaa', + label: 'aaa', permalink: '/aaa', count: 10, }; diff --git a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts index 99dfdc9d379f..c29afab1cf65 100644 --- a/packages/docusaurus-theme-common/src/utils/tagsUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/tagsUtils.ts @@ -6,6 +6,7 @@ */ import {translate} from '@docusaurus/Translate'; +import type {TagsListItem} from '@docusaurus/types'; export const translateTagsPageTitle = (): string => translate({ @@ -14,13 +15,7 @@ export const translateTagsPageTitle = (): string => description: 'The title of the tag list page', }); -export type TagsListItem = Readonly<{ - name: string; - permalink: string; - count: number; -}>; - -export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>; +export type TagLetterEntry = {letter: string; tags: TagsListItem[]}; function getTagLetter(tag: string): string { return tag[0]!.toUpperCase(); @@ -35,7 +30,7 @@ export function listTagsByLetters( ): TagLetterEntry[] { const groups: {[initial: string]: TagsListItem[]} = {}; Object.values(tags).forEach((tag) => { - const initial = getTagLetter(tag.name); + const initial = getTagLetter(tag.label); groups[initial] ??= []; groups[initial]!.push(tag); }); @@ -47,7 +42,7 @@ export function listTagsByLetters( .map(([letter, letterTags]) => { // Sort tags inside a letter const sortedTags = letterTags.sort((tag1, tag2) => - tag1.name.localeCompare(tag2.name), + tag1.label.localeCompare(tag2.label), ); return {letter, tags: sortedTags}; }) diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 7a5b9ad5ecd5..fcfdb35e1873 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -594,3 +594,22 @@ export type ClientModule = { }) => void; onRouteUpdateDelayed?: (args: {location: Location}) => void; }; + +/** What the user configures. */ +export type Tag = { + label: string; + /** Permalink to this tag's page, without the `/tags/` base path. */ + permalink: string; +}; + +/** What the tags list page should know about each tag. */ +export type TagsListItem = Tag & { + /** Number of posts/docs with this tag. */ + count: number; +}; + +/** What the tag's own page should know about the tag. */ +export type TagModule = TagsListItem & { + /** The tags list page's permalink. */ + allTagsPath: string; +}; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index 4e6134a7b2a1..385efd4ff226 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -7,7 +7,7 @@ import Joi from './Joi'; import {isValidPathname, DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; -import type {Tag} from '@docusaurus/utils'; +import type {Tag} from '@docusaurus/types'; import {JoiFrontMatter} from './JoiFrontMatter'; export const PluginIdSchema = Joi.string() diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 7cd871a631e8..575f67e62920 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -56,7 +56,6 @@ export { buildSshUrl, } from './urlUtils'; export { - type Tag, type FrontMatterTag, normalizeFrontMatterTags, groupTaggedItems, diff --git a/packages/docusaurus-utils/src/tags.ts b/packages/docusaurus-utils/src/tags.ts index fa5eb4eebd1e..e3eb2933e6f0 100644 --- a/packages/docusaurus-utils/src/tags.ts +++ b/packages/docusaurus-utils/src/tags.ts @@ -7,12 +7,7 @@ import _ from 'lodash'; import {normalizeUrl} from './urlUtils'; - -export type Tag = { - label: string; - /** Permalink to this tag's page, without the `/tags/` base path. */ - permalink: string; -}; +import type {Tag} from '@docusaurus/types'; export type FrontMatterTag = string | Tag; From 0a3aad618eb79415427a895e1aadef0373ae52ca Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 8 Apr 2022 00:38:33 +0800 Subject: [PATCH 132/405] feat(core): allow plugins to declare custom route context (#7082) --- packages/docusaurus-types/src/index.d.ts | 6 ++++++ .../__snapshots__/routes.test.ts.snap | 19 +++++++++++++------ .../src/server/__tests__/routes.test.ts | 6 ++++++ .../docusaurus/src/server/plugins/index.ts | 17 +++++++---------- packages/docusaurus/src/server/routes.ts | 4 ++++ 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index fcfdb35e1873..e20bd74ee6a5 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -493,6 +493,12 @@ export type RouteConfig = { * `createData`) */ modules?: RouteModules; + /** + * The route context will wrap the `component`. Use `useRouteContext` to + * retrieve what's declared here. Note that all custom route context declared + * here will be namespaced under {@link RouteContext.data}. + */ + context?: RouteModules; /** Nested routes config. */ routes?: RouteConfig[]; /** React router config option: `exact` routes would not match subroutes. */ diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index 80de4e006fca..9979705a3132 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -66,19 +66,26 @@ exports[`loadRoutes loads nested route config 1`] = ` "docsMetadata---docs-routef-34-881": "docs-b5f.json", "metadata---docs-foo-baz-2-cf-fa7": "docs-foo-baz-dd9.json", "metadata---docs-hello-956-741": "docs-hello-da2.json", + "plugin---docs-hello-665-3ca": "pluginRouteContextModule-100.json", }, "routesChunkNames": { - "/docs/hello-44b": { + "/docs/hello-fcc": { "__comp": "__comp---theme-doc-item-178-a40", + "__context": { + "plugin": "plugin---docs-hello-665-3ca", + }, "content": "content---docs-helloaff-811", "metadata": "metadata---docs-hello-956-741", }, - "/docs:route-52d": { + "/docs:route-502": { "__comp": "__comp---theme-doc-page-1-be-9be", "docsMetadata": "docsMetadata---docs-routef-34-881", }, - "docs/foo/baz-070": { + "docs/foo/baz-eb2": { "__comp": "__comp---theme-doc-item-178-a40", + "__context": { + "plugin": "plugin---docs-hello-665-3ca", + }, "content": "content---docs-foo-baz-8-ce-61e", "metadata": "metadata---docs-foo-baz-2-cf-fa7", }, @@ -89,17 +96,17 @@ import ComponentCreator from '@docusaurus/ComponentCreator'; export default [ { path: '/docs:route', - component: ComponentCreator('/docs:route', '52d'), + component: ComponentCreator('/docs:route', '502'), routes: [ { path: '/docs/hello', - component: ComponentCreator('/docs/hello', '44b'), + component: ComponentCreator('/docs/hello', 'fcc'), exact: true, sidebar: \\"main\\" }, { path: 'docs/foo/baz', - component: ComponentCreator('docs/foo/baz', '070'), + component: ComponentCreator('docs/foo/baz', 'eb2'), sidebar: \\"secondary\\", \\"key:a\\": \\"containing colon\\", \\"key'b\\": \\"containing quote\\", diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index 1e8062a69632..b18f0ccca679 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -117,6 +117,9 @@ describe('loadRoutes', () => { content: 'docs/hello.md', metadata: 'docs-hello-da2.json', }, + context: { + plugin: 'pluginRouteContextModule-100.json', + }, sidebar: 'main', }, { @@ -126,6 +129,9 @@ describe('loadRoutes', () => { content: 'docs/foo/baz.md', metadata: 'docs-foo-baz-dd9.json', }, + context: { + plugin: 'pluginRouteContextModule-100.json', + }, sidebar: 'secondary', 'key:a': 'containing colon', "key'b": 'containing quote', diff --git a/packages/docusaurus/src/server/plugins/index.ts b/packages/docusaurus/src/server/plugins/index.ts index d63b95589bc4..c87c99dc9ef0 100644 --- a/packages/docusaurus/src/server/plugins/index.ts +++ b/packages/docusaurus/src/server/plugins/index.ts @@ -104,22 +104,19 @@ export async function loadPlugins(context: LoadContext): Promise<{ plugin.name, pluginId, ); - // TODO this would be better to do all that in the codegen phase - // TODO handle context for nested routes - const pluginRouteContext: PluginRouteContext = { - plugin: {name: plugin.name, id: pluginId}, - data: undefined, // TODO allow plugins to provide context data - }; const pluginRouteContextModulePath = path.join( dataDir, `${docuHash('pluginRouteContextModule')}.json`, ); + const pluginRouteContext: PluginRouteContext['plugin'] = { + name: plugin.name, + id: pluginId, + }; await generate( '/', pluginRouteContextModulePath, JSON.stringify(pluginRouteContext, null, 2), ); - const actions: PluginContentLoadedActions = { addRoute(initialRouteConfig) { // Trailing slash behavior is handled generically for all plugins @@ -129,9 +126,9 @@ export async function loadPlugins(context: LoadContext): Promise<{ ); pluginsRouteConfigs.push({ ...finalRouteConfig, - modules: { - ...finalRouteConfig.modules, - __context: pluginRouteContextModulePath, + context: { + ...(finalRouteConfig.context && {data: finalRouteConfig.context}), + plugin: pluginRouteContextModulePath, }, }); }, diff --git a/packages/docusaurus/src/server/routes.ts b/packages/docusaurus/src/server/routes.ts index 6350e2166069..733bf0bc2f51 100644 --- a/packages/docusaurus/src/server/routes.ts +++ b/packages/docusaurus/src/server/routes.ts @@ -250,6 +250,7 @@ function genRouteCode(routeConfig: RouteConfig, res: LoadedRoutes): string { path: routePath, component, modules = {}, + context, routes: subroutes, priority, exact, @@ -271,6 +272,9 @@ ${JSON.stringify(routeConfig)}`, res.routesChunkNames[`${routePath}-${routeHash}`] = { // Avoid clash with a prop called "component" ...genChunkNames({__comp: component}, 'component', component, res), + ...(context + ? genChunkNames({__context: context}, 'context', routePath, res) + : {}), ...genChunkNames(modules, 'module', routePath, res), }; From 4134ebb3fb2cd499a0005525fbb00ebe69cea0e5 Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 8 Apr 2022 01:43:24 +0800 Subject: [PATCH 133/405] feat(content-docs): make docs:version command work on localized docs (#7106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com> --- .../current/ipsum.md | 0 .../current/lorem.md | 0 .../current/hello.md | 0 .../src/__tests__/cli.test.ts | 171 ++++++++---------- .../src/__tests__/index.test.ts | 92 ++++------ .../docusaurus-plugin-content-docs/src/cli.ts | 72 +++++--- .../src/index.ts | 9 +- .../src/versions.ts | 4 +- 8 files changed, 165 insertions(+), 183 deletions(-) create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ipsum.md create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/lorem.md create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/fr/docusaurus-plugin-content-docs-community/current/hello.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ipsum.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ipsum.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/lorem.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current/lorem.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/fr/docusaurus-plugin-content-docs-community/current/hello.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/fr/docusaurus-plugin-content-docs-community/current/hello.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 22aeed790cb9..27d56ecee103 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -8,10 +8,7 @@ import {jest} from '@jest/globals'; import path from 'path'; import {cliDocsVersionCommand} from '../cli'; -import type { - PathOptions, - SidebarOptions, -} from '@docusaurus/plugin-content-docs'; +import type {PluginOptions} from '@docusaurus/plugin-content-docs'; import fs from 'fs-extra'; import { getVersionedDocsDirPath, @@ -26,7 +23,8 @@ describe('docsVersion', () => { const simpleSiteDir = path.join(fixtureDir, 'simple-site'); const versionedSiteDir = path.join(fixtureDir, 'versioned-site'); - const DEFAULT_OPTIONS: PathOptions & SidebarOptions = { + const DEFAULT_OPTIONS: PluginOptions = { + id: 'default', path: 'docs', sidebarPath: '', sidebarCollapsed: true, @@ -35,32 +33,19 @@ describe('docsVersion', () => { it('no version tag provided', async () => { await expect(() => - cliDocsVersionCommand( - null, - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand(null, DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: no version tag specified! Pass the version you wish to create as an argument, for example: 1.0.0."`, ); await expect(() => - cliDocsVersionCommand( - undefined, - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand(undefined, DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: no version tag specified! Pass the version you wish to create as an argument, for example: 1.0.0."`, ); await expect(() => - cliDocsVersionCommand( - '', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('', DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: no version tag specified! Pass the version you wish to create as an argument, for example: 1.0.0."`, ); @@ -68,22 +53,16 @@ describe('docsVersion', () => { it('version tag should not have slash', async () => { await expect(() => - cliDocsVersionCommand( - 'foo/bar', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('foo/bar', DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowError( '[docs]: invalid version tag specified! Do not include slash (/) or backslash (\\). Try something like: 1.0.0.', ); await expect(() => - cliDocsVersionCommand( - 'foo\\bar', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('foo\\bar', DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowError( '[docs]: invalid version tag specified! Do not include slash (/) or backslash (\\). Try something like: 1.0.0.', ); @@ -91,12 +70,9 @@ describe('docsVersion', () => { it('version tag should not be too long', async () => { await expect(() => - cliDocsVersionCommand( - 'a'.repeat(255), - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('a'.repeat(255), DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Length cannot exceed 32 characters. Try something like: 1.0.0."`, ); @@ -104,22 +80,12 @@ describe('docsVersion', () => { it('version tag should not be a dot or two dots', async () => { await expect(() => - cliDocsVersionCommand( - '..', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('..', DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0."`, ); await expect(() => - cliDocsVersionCommand( - '.', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('.', DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0."`, ); @@ -127,32 +93,23 @@ describe('docsVersion', () => { it('version tag should be a valid pathname', async () => { await expect(() => - cliDocsVersionCommand( - '<foo|bar>', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('<foo|bar>', DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0."`, ); await expect(() => - cliDocsVersionCommand( - 'foo\x00bar', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('foo\x00bar', DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0."`, ); await expect(() => - cliDocsVersionCommand( - 'foo:bar', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('foo:bar', DEFAULT_OPTIONS, { + siteDir: simpleSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0."`, ); @@ -160,12 +117,9 @@ describe('docsVersion', () => { it('version tag already exist', async () => { await expect(() => - cliDocsVersionCommand( - '1.0.0', - versionedSiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('1.0.0', DEFAULT_OPTIONS, { + siteDir: versionedSiteDir, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( `"[docs]: this version already exists! Use a version tag that does not already exist."`, ); @@ -174,14 +128,12 @@ describe('docsVersion', () => { it('no docs file to version', async () => { const emptySiteDir = path.join(fixtureDir, 'empty-site'); await expect(() => - cliDocsVersionCommand( - '1.0.0', - emptySiteDir, - DEFAULT_PLUGIN_ID, - DEFAULT_OPTIONS, - ), + cliDocsVersionCommand('1.0.0', DEFAULT_OPTIONS, { + siteDir: emptySiteDir, + i18n: {locales: ['en', 'zh-Hans'], defaultLocale: 'en'}, + }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[docs]: no docs found in <PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs."`, + `"[docs]: no docs found in \\"<PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs\\"."`, ); }); @@ -205,12 +157,10 @@ describe('docsVersion', () => { ...DEFAULT_OPTIONS, sidebarPath: path.join(simpleSiteDir, 'sidebars.json'), }; - await cliDocsVersionCommand( - '1.0.0', - simpleSiteDir, - DEFAULT_PLUGIN_ID, - options, - ); + await cliDocsVersionCommand('1.0.0', options, { + siteDir: simpleSiteDir, + i18n: {locales: ['en', 'zh-Hans'], defaultLocale: 'en'}, + }); expect(copyMock).toHaveBeenCalledWith( path.join(simpleSiteDir, options.path), path.join( @@ -218,6 +168,16 @@ describe('docsVersion', () => { 'version-1.0.0', ), ); + expect(copyMock).toHaveBeenCalledWith( + path.join( + simpleSiteDir, + 'i18n/zh-Hans/docusaurus-plugin-content-docs/current', + ), + path.join( + simpleSiteDir, + 'i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.0.0', + ), + ); expect(versionedSidebar).toMatchSnapshot(); expect(versionedSidebarPath).toEqual( path.join( @@ -256,16 +216,15 @@ describe('docsVersion', () => { versions = JSON.parse(content as string); }); const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); + const warnMock = jest.spyOn(console, 'warn').mockImplementation(() => {}); const options = { ...DEFAULT_OPTIONS, sidebarPath: path.join(versionedSiteDir, 'sidebars.json'), }; - await cliDocsVersionCommand( - '2.0.0', - versionedSiteDir, - DEFAULT_PLUGIN_ID, - options, - ); + await cliDocsVersionCommand('2.0.0', options, { + siteDir: versionedSiteDir, + i18n: {locales: ['en', 'zh-Hans'], defaultLocale: 'en'}, + }); expect(copyMock).toHaveBeenCalledWith( path.join(versionedSiteDir, options.path), path.join( @@ -289,7 +248,11 @@ describe('docsVersion', () => { /.*\[SUCCESS\].*\[docs\].*: version .*2\.0\.0.* created!.*/, ), ); + expect(warnMock.mock.calls[0][0]).toMatchInlineSnapshot( + `"[WARNING] [docs]: no docs found in \\"<PROJECT_ROOT>/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current\\". Skipping."`, + ); + warnMock.mockRestore(); copyMock.mockRestore(); writeMock.mockRestore(); consoleMock.mockRestore(); @@ -315,10 +278,14 @@ describe('docsVersion', () => { const consoleMock = jest.spyOn(console, 'log').mockImplementation(() => {}); const options = { ...DEFAULT_OPTIONS, + id: pluginId, path: 'community', sidebarPath: path.join(versionedSiteDir, 'community_sidebars.json'), }; - await cliDocsVersionCommand('2.0.0', versionedSiteDir, pluginId, options); + await cliDocsVersionCommand('2.0.0', options, { + siteDir: versionedSiteDir, + i18n: {locales: ['en', 'fr'], defaultLocale: 'en'}, + }); expect(copyMock).toHaveBeenCalledWith( path.join(versionedSiteDir, options.path), path.join( @@ -326,6 +293,16 @@ describe('docsVersion', () => { 'version-2.0.0', ), ); + expect(copyMock).toHaveBeenCalledWith( + path.join( + versionedSiteDir, + 'i18n/fr/docusaurus-plugin-content-docs-community/current', + ), + path.join( + versionedSiteDir, + 'i18n/fr/docusaurus-plugin-content-docs-community/version-2.0.0', + ), + ); expect(versionedSidebar).toMatchSnapshot(); expect(versionedSidebarPath).toEqual( path.join( diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 926bcfb8f96f..1ad236a88638 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -16,7 +16,7 @@ import pluginContentDocs from '../index'; import {loadContext} from '@docusaurus/core/src/server/index'; import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils'; import type {RouteConfig} from '@docusaurus/types'; -import {posixPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; +import {posixPath} from '@docusaurus/utils'; import {sortConfig} from '@docusaurus/core/src/server/plugins/routeConfig'; import * as cliDocs from '../cli'; @@ -230,23 +230,21 @@ describe('simple website', () => { const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'sidebars.json'); - const plugin = await pluginContentDocs( - context, - validateOptions({ - validate: normalizePluginOptions, - options: { - path: 'docs', - sidebarPath, - }, - }), - ); + const options = validateOptions({ + validate: normalizePluginOptions, + options: { + path: 'docs', + sidebarPath, + }, + }); + const plugin = await pluginContentDocs(context, options); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); - return {siteDir, context, sidebarPath, plugin, pluginContentDir}; + return {siteDir, context, sidebarPath, plugin, options, pluginContentDir}; } it('extendCli - docsVersion', async () => { - const {siteDir, sidebarPath, plugin} = await loadSite(); + const {plugin, options, context} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') .mockImplementation(async () => {}); @@ -256,12 +254,7 @@ describe('simple website', () => { plugin.extendCli!(cli); cli.parse(['node', 'test', 'docs:version', '1.0.0']); expect(mock).toHaveBeenCalledTimes(1); - expect(mock).toHaveBeenCalledWith('1.0.0', siteDir, DEFAULT_PLUGIN_ID, { - path: 'docs', - sidebarPath, - sidebarCollapsed: true, - sidebarCollapsible: true, - }); + expect(mock).toHaveBeenCalledWith('1.0.0', options, context); mock.mockRestore(); }); @@ -344,29 +337,28 @@ describe('versioned website', () => { const context = await loadContext({siteDir}); const sidebarPath = path.join(siteDir, 'sidebars.json'); const routeBasePath = 'docs'; - const plugin = await pluginContentDocs( - context, - validateOptions({ - validate: normalizePluginOptions, - options: { - routeBasePath, - sidebarPath, - }, - }), - ); + const options = validateOptions({ + validate: normalizePluginOptions, + options: { + routeBasePath, + sidebarPath, + }, + }); + const plugin = await pluginContentDocs(context, options); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); return { siteDir, context, routeBasePath, sidebarPath, + options, plugin, pluginContentDir, }; } it('extendCli - docsVersion', async () => { - const {siteDir, routeBasePath, sidebarPath, plugin} = await loadSite(); + const {plugin, context, options} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') .mockImplementation(async () => {}); @@ -376,12 +368,7 @@ describe('versioned website', () => { plugin.extendCli!(cli); cli.parse(['node', 'test', 'docs:version', '2.0.0']); expect(mock).toHaveBeenCalledTimes(1); - expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, DEFAULT_PLUGIN_ID, { - path: routeBasePath, - sidebarPath, - sidebarCollapsed: true, - sidebarCollapsible: true, - }); + expect(mock).toHaveBeenCalledWith('2.0.0', options, context); mock.mockRestore(); }); @@ -474,18 +461,16 @@ describe('versioned website (community)', () => { const sidebarPath = path.join(siteDir, 'community_sidebars.json'); const routeBasePath = 'community'; const pluginId = 'community'; - const plugin = await pluginContentDocs( - context, - validateOptions({ - validate: normalizePluginOptions, - options: { - id: 'community', - path: 'community', - routeBasePath, - sidebarPath, - }, - }), - ); + const options = validateOptions({ + validate: normalizePluginOptions, + options: { + id: 'community', + path: 'community', + routeBasePath, + sidebarPath, + }, + }); + const plugin = await pluginContentDocs(context, options); const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); return { siteDir, @@ -493,14 +478,14 @@ describe('versioned website (community)', () => { routeBasePath, sidebarPath, pluginId, + options, plugin, pluginContentDir, }; } it('extendCli - docsVersion', async () => { - const {siteDir, routeBasePath, sidebarPath, pluginId, plugin} = - await loadSite(); + const {pluginId, plugin, options, context} = await loadSite(); const mock = jest .spyOn(cliDocs, 'cliDocsVersionCommand') .mockImplementation(async () => {}); @@ -510,12 +495,7 @@ describe('versioned website (community)', () => { plugin.extendCli!(cli); cli.parse(['node', 'test', `docs:version:${pluginId}`, '2.0.0']); expect(mock).toHaveBeenCalledTimes(1); - expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, pluginId, { - path: routeBasePath, - sidebarPath, - sidebarCollapsed: true, - sidebarCollapsible: true, - }); + expect(mock).toHaveBeenCalledWith('2.0.0', options, context); mock.mockRestore(); }); diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index 710a5c3d7c67..e405d11560dc 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -9,16 +9,16 @@ import { getVersionsFilePath, getVersionedDocsDirPath, getVersionedSidebarsDirPath, + getDocsDirPathLocalized, } from './versions'; import fs from 'fs-extra'; import path from 'path'; -import type { - PathOptions, - SidebarOptions, -} from '@docusaurus/plugin-content-docs'; +import type {PluginOptions} from '@docusaurus/plugin-content-docs'; import {loadSidebarsFileUnsafe, resolveSidebarPathOption} from './sidebars'; +import {CURRENT_VERSION_NAME} from './constants'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import logger from '@docusaurus/logger'; +import type {LoadContext} from '@docusaurus/types'; async function createVersionedSidebarFile({ siteDir, @@ -58,9 +58,8 @@ async function createVersionedSidebarFile({ // Tests depend on non-default export for mocking. export async function cliDocsVersionCommand( version: string | null | undefined, - siteDir: string, - pluginId: string, - options: PathOptions & SidebarOptions, + {id: pluginId, path: docsPath, sidebarPath}: PluginOptions, + {siteDir, i18n}: LoadContext, ): Promise<void> { // It wouldn't be very user-friendly to show a [default] log prefix, // so we use [docs] instead of [default] @@ -114,22 +113,53 @@ export async function cliDocsVersionCommand( ); } - const {path: docsPath, sidebarPath} = options; - - // Copy docs files. - const docsDir = path.resolve(siteDir, docsPath); - - if ( - (await fs.pathExists(docsDir)) && - (await fs.readdir(docsDir)).length > 0 - ) { - const versionedDir = getVersionedDocsDirPath(siteDir, pluginId); - const newVersionDir = path.join(versionedDir, `version-${version}`); - await fs.copy(docsDir, newVersionDir); - } else { - throw new Error(`${pluginIdLogPrefix}: no docs found in ${docsDir}.`); + if (i18n.locales.length > 1) { + logger.info`Versioned docs will be created for the following locales: name=${i18n.locales}`; } + await Promise.all( + i18n.locales.map(async (locale) => { + // Copy docs files. + const docsDir = + locale === i18n.defaultLocale + ? path.resolve(siteDir, docsPath) + : getDocsDirPathLocalized({ + siteDir, + locale, + pluginId, + versionName: CURRENT_VERSION_NAME, + }); + + if ( + !(await fs.pathExists(docsDir)) || + (await fs.readdir(docsDir)).length === 0 + ) { + if (locale === i18n.defaultLocale) { + throw new Error( + logger.interpolate`${pluginIdLogPrefix}: no docs found in path=${docsDir}.`, + ); + } else { + logger.warn`${pluginIdLogPrefix}: no docs found in path=${docsDir}. Skipping.`; + return; + } + } + + const newVersionDir = + locale === i18n.defaultLocale + ? path.join( + getVersionedDocsDirPath(siteDir, pluginId), + `version-${version}`, + ) + : getDocsDirPathLocalized({ + siteDir, + locale, + pluginId, + versionName: version, + }); + await fs.copy(docsDir, newVersionDir); + }), + ); + await createVersionedSidebarFile({ siteDir, pluginId, diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index b8e7c121148b..7fbc9595b4b4 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -67,7 +67,7 @@ export default async function pluginContentDocs( const versionsMetadata = await readVersionsMetadata({context, options}); - const pluginId = options.id ?? DEFAULT_PLUGIN_ID; + const pluginId = options.id; const pluginDataDirRoot = path.join( generatedFilesDir, @@ -97,12 +97,7 @@ export default async function pluginContentDocs( .arguments('<version>') .description(commandDescription) .action((version) => { - cliDocsVersionCommand(version, siteDir, pluginId, { - path: options.path, - sidebarPath: options.sidebarPath, - sidebarCollapsed: options.sidebarCollapsed, - sidebarCollapsible: options.sidebarCollapsible, - }); + cliDocsVersionCommand(version, options, context); }); }, diff --git a/packages/docusaurus-plugin-content-docs/src/versions.ts b/packages/docusaurus-plugin-content-docs/src/versions.ts index 7b06aa0e089c..a7f216f53223 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions.ts @@ -133,7 +133,7 @@ export async function readVersionNames( return versions; } -function getDocsDirPathLocalized({ +export function getDocsDirPathLocalized({ siteDir, locale, pluginId, @@ -143,7 +143,7 @@ function getDocsDirPathLocalized({ locale: string; pluginId: string; versionName: string; -}) { +}): string { return getPluginI18nPath({ siteDir, locale, From 9145ae88cc22ad322e070b705ee3c4c8ef8f0a0a Mon Sep 17 00:00:00 2001 From: Joshua Chen <sidachen2003@gmail.com> Date: Fri, 8 Apr 2022 11:23:19 +0800 Subject: [PATCH 134/405] chore: disable string escaping in snapshots (#7131) --- jest.config.mjs | 1 + jest/snapshotPathNormalizer.ts | 2 + package.json | 1 + .../__snapshots__/index.test.ts.snap | 32 +- .../src/__tests__/index.test.ts | 36 +- .../__snapshots__/index.test.ts.snap | 30 +- .../__snapshots__/index.test.ts.snap | 32 +- .../__snapshots__/index.test.ts.snap | 52 +- .../__snapshots__/index.test.ts.snap | 554 ++--- .../collectRedirects.test.ts.snap | 8 +- .../createRedirectPageContent.test.ts.snap | 12 +- .../__snapshots__/options.test.ts.snap | 6 +- .../redirectValidation.test.ts.snap | 10 +- .../writeRedirectFiles.test.ts.snap | 66 +- .../src/__tests__/extensionRedirects.test.ts | 32 +- .../__tests__/__snapshots__/feed.test.ts.snap | 194 +- .../__snapshots__/options.test.ts.snap | 4 +- .../src/__tests__/authors.test.ts | 21 +- .../src/__tests__/options.test.ts | 4 +- .../__snapshots__/index.test.ts.snap | 2142 ++++++++--------- .../src/__tests__/cli.test.ts | 8 +- .../src/__tests__/docs.test.ts | 2 +- .../src/__tests__/index.test.ts | 9 +- .../src/__tests__/options.test.ts | 31 +- .../src/__tests__/slug.test.ts | 2 +- .../src/__tests__/versions.test.ts | 30 +- .../client/__tests__/docsClientUtils.test.ts | 4 +- .../src/markdown/__tests__/linkify.test.ts | 2 +- .../src/sidebars/__tests__/index.test.ts | 4 +- .../sidebars/__tests__/normalization.test.ts | 9 +- .../src/sidebars/__tests__/validation.test.ts | 129 +- .../src/__tests__/options.test.ts | 2 +- .../src/__tests__/options.test.ts | 10 +- .../__snapshots__/index.test.ts.snap | 22 +- .../src/__tests__/validateThemeConfig.test.ts | 20 +- .../src/theme/Tabs/__tests__/index.test.tsx | 6 +- .../__snapshots__/codeBlockUtils.test.ts.snap | 2 +- .../utils/__tests__/usePluralForm.test.tsx | 2 +- .../src/__tests__/validateThemeConfig.test.ts | 4 +- .../src/__tests__/validateThemeConfig.test.ts | 16 +- .../src/__tests__/utils.test.ts | 2 +- .../validationSchemas.test.ts.snap | 102 +- .../src/__tests__/validationUtils.test.ts | 6 +- .../src/__tests__/dataFileUtils.test.ts | 2 +- .../src/__tests__/jsUtils.test.ts | 2 +- .../exports/__tests__/BrowserOnly.test.tsx | 4 +- .../exports/__tests__/useGlobalData.test.tsx | 4 +- .../commands/swizzle/__tests__/config.test.ts | 6 +- .../configValidation.test.ts.snap | 76 +- .../__snapshots__/routes.test.ts.snap | 14 +- .../src/server/__tests__/config.test.ts | 8 +- .../server/__tests__/configValidation.test.ts | 16 +- .../src/server/__tests__/htmlTags.test.ts | 28 +- .../src/server/__tests__/routes.test.ts | 12 +- .../src/server/__tests__/siteMetadata.test.ts | 7 +- .../__tests__/__snapshots__/init.test.ts.snap | 12 +- .../__snapshots__/pluginIds.test.ts.snap | 10 +- .../plugins/__tests__/moduleShorthand.test.ts | 4 +- .../__tests__/translations.test.ts | 17 +- .../src/webpack/__tests__/utils.test.ts | 2 +- 60 files changed, 1942 insertions(+), 1945 deletions(-) diff --git a/jest.config.mjs b/jest.config.mjs index 479ebd5948b3..5c241b301ed8 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -69,6 +69,7 @@ export default { 'jest-serializer-react-helmet-async', ], snapshotFormat: { + escapeString: false, printBasicPrototype: false, }, }; diff --git a/jest/snapshotPathNormalizer.ts b/jest/snapshotPathNormalizer.ts index d8b2d7a14e45..084abc14a6cc 100644 --- a/jest/snapshotPathNormalizer.ts +++ b/jest/snapshotPathNormalizer.ts @@ -10,6 +10,7 @@ import _ from 'lodash'; import {escapePath} from '@docusaurus/utils'; +import stripAnsi from 'strip-ansi'; import {version} from '@docusaurus/core/package.json'; import os from 'os'; import path from 'path'; @@ -76,6 +77,7 @@ function normalizePaths<T>(value: T): T { const homeRealRelativeToTemp = path.relative(tempDir, homeDirReal); const runner: ((val: string) => string)[] = [ + (val) => (val.includes('keepAnsi') ? val : stripAnsi(val)), // Replace process.cwd with <PROJECT_ROOT> (val) => val.split(cwdReal).join('<PROJECT_ROOT>'), (val) => val.split(cwd).join('<PROJECT_ROOT>'), diff --git a/package.json b/package.json index bc377a1193fb..f0a14ca0c702 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "remark-parse": "^8.0.2", "rimraf": "^3.0.2", "sharp": "^0.30.3", + "strip-ansi": "^6.0.1", "stylelint": "^14.6.1", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard": "^25.0.0", diff --git a/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap index cf55c3083aea..5980bd3de212 100644 --- a/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-logger/src/__tests__/__snapshots__/index.test.ts.snap @@ -3,16 +3,16 @@ exports[`error prints objects 1`] = ` [ [ - "[ERROR] {\\"a\\":1}", + "[ERROR] {"a":1}", ], [ - "[ERROR] undefined", + "[ERROR] undefined", ], [ - "[ERROR] 1,2,3", + "[ERROR] 1,2,3", ], [ - "[ERROR] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + "[ERROR] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; @@ -20,16 +20,16 @@ exports[`error prints objects 1`] = ` exports[`info prints objects 1`] = ` [ [ - "[INFO] {\\"a\\":1}", + "[INFO] {"a":1}", ], [ - "[INFO] undefined", + "[INFO] undefined", ], [ - "[INFO] 1,2,3", + "[INFO] 1,2,3", ], [ - "[INFO] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + "[INFO] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; @@ -37,16 +37,16 @@ exports[`info prints objects 1`] = ` exports[`success prints objects 1`] = ` [ [ - "[SUCCESS] {\\"a\\":1}", + "[SUCCESS] {"a":1}", ], [ - "[SUCCESS] undefined", + "[SUCCESS] undefined", ], [ - "[SUCCESS] 1,2,3", + "[SUCCESS] 1,2,3", ], [ - "[SUCCESS] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + "[SUCCESS] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; @@ -54,16 +54,16 @@ exports[`success prints objects 1`] = ` exports[`warn prints objects 1`] = ` [ [ - "[WARNING] {\\"a\\":1}", + "[WARNING] {"a":1}", ], [ - "[WARNING] undefined", + "[WARNING] undefined", ], [ - "[WARNING] 1,2,3", + "[WARNING] 1,2,3", ], [ - "[WARNING] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", + "[WARNING] Sat Nov 13 2021 00:00:00 GMT+0000 (Coordinated Universal Time)", ], ] `; diff --git a/packages/docusaurus-logger/src/__tests__/index.test.ts b/packages/docusaurus-logger/src/__tests__/index.test.ts index 0b2b710769fd..59a8f9c0d1d9 100644 --- a/packages/docusaurus-logger/src/__tests__/index.test.ts +++ b/packages/docusaurus-logger/src/__tests__/index.test.ts @@ -8,24 +8,25 @@ import {jest} from '@jest/globals'; import logger from '../index'; +// cSpell:ignore mkeep + describe('formatters', () => { it('path', () => { - // cSpell:ignore mhey - expect(logger.path('hey')).toMatchInlineSnapshot(`"\\"hey\\""`); + expect(logger.path('keepAnsi')).toMatchInlineSnapshot(`""keepAnsi""`); }); it('url', () => { - expect(logger.url('https://docusaurus.io/')).toMatchInlineSnapshot( - `"https://docusaurus.io/"`, + expect(logger.url('https://docusaurus.io/keepAnsi')).toMatchInlineSnapshot( + `"https://docusaurus.io/keepAnsi"`, ); }); it('id', () => { - expect(logger.name('hey')).toMatchInlineSnapshot(`"hey"`); + expect(logger.name('keepAnsi')).toMatchInlineSnapshot(`"keepAnsi"`); }); it('code', () => { - expect(logger.code('hey')).toMatchInlineSnapshot(`"\`hey\`"`); + expect(logger.code('keepAnsi')).toMatchInlineSnapshot(`"\`keepAnsi\`"`); }); it('subdue', () => { - expect(logger.subdue('hey')).toMatchInlineSnapshot(`"hey"`); + expect(logger.subdue('keepAnsi')).toMatchInlineSnapshot(`"keepAnsi"`); }); }); @@ -33,9 +34,10 @@ describe('interpolate', () => { it('formats text with variables & arrays', () => { const name = 'Josh'; const items = [1, 'hi', 'Hmmm']; - expect(logger.interpolate`Hello ${name}! Here are your goodies:${items}`) - .toMatchInlineSnapshot(` - "Hello Josh! Here are your goodies: + expect( + logger.interpolate`(keepAnsi) Hello ${name}! Here are your goodies:${items}`, + ).toMatchInlineSnapshot(` + "(keepAnsi) Hello Josh! Here are your goodies: - 1 - hi - Hmmm" @@ -43,20 +45,20 @@ describe('interpolate', () => { }); it('recognizes valid flags', () => { expect( - logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, + logger.interpolate`(keepAnsi) The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`, ).toMatchInlineSnapshot( - `"The package at \\"packages/docusaurus\\" has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, + `"(keepAnsi) The package at "packages/docusaurus" has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`, ); }); it('interpolates arrays with flags', () => { expect( - logger.interpolate`The following commands are available:code=${[ + logger.interpolate`(keepAnsi) The following commands are available:code=${[ 'docusaurus start', 'docusaurus build', 'docusaurus deploy', ]}`, ).toMatchInlineSnapshot(` - "The following commands are available: + "(keepAnsi) The following commands are available: - \`docusaurus start\` - \`docusaurus build\` - \`docusaurus deploy\`" @@ -64,15 +66,15 @@ describe('interpolate', () => { }); it('prints detached flags as-is', () => { expect( - logger.interpolate`You can use placeholders like code= ${'and it will'} be replaced with the succeeding arguments`, + logger.interpolate`(keepAnsi) You can use placeholders like code= ${'and it will'} be replaced with the succeeding arguments`, ).toMatchInlineSnapshot( - `"You can use placeholders like code= and it will be replaced with the succeeding arguments"`, + `"(keepAnsi) You can use placeholders like code= and it will be replaced with the succeeding arguments"`, ); }); it('throws with bad flags', () => { expect( () => - logger.interpolate`I mistyped this: cde=${'this code'} and I will be damned`, + logger.interpolate`(keepAnsi) I mistyped this: cde=${'this code'} and I will be damned`, ).toThrowErrorMatchingInlineSnapshot( `"Bad Docusaurus logging message. This is likely an internal bug, please report it."`, ); diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap index e8540eda835d..8366a7b23e19 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__snapshots__/index.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`transformImage plugin does not choke on invalid image 1`] = ` -"<img alt={\\"invalid image\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png\\").default} /> +"<img alt={"invalid image"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/invalid.png").default} /> " `; @@ -9,7 +9,7 @@ exports[`transformImage plugin fail if image does not exist 1`] = `"Image packag exports[`transformImage plugin fail if image relative path does not exist 1`] = `"Image packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/notFound.png used in packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/fail2.md not found."`; -exports[`transformImage plugin fail if image url is absent 1`] = `"Markdown image URL is mandatory in \\"packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/noUrl.md\\" file"`; +exports[`transformImage plugin fail if image url is absent 1`] = `"Markdown image URL is mandatory in "packages/docusaurus-mdx-loader/src/remark/transformImage/__tests__/__fixtures__/noUrl.md" file"`; exports[`transformImage plugin pathname protocol 1`] = ` "![img](/img/unchecked.png) @@ -19,29 +19,29 @@ exports[`transformImage plugin pathname protocol 1`] = ` exports[`transformImage plugin transform md images to <img /> 1`] = ` "![img](https://example.com/img.png) -<img src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={"img"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={"img from second static folder"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> -<img alt={\\"img from second static folder\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={"img from second static folder"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2.png").default} width="256" height="82" /> -<img alt={\\"img with URL encoded chars\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png\\").default} width=\\"256\\" height=\\"82\\" /> +<img alt={"img with URL encoded chars"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static2/img2 copy.png").default} width="256" height="82" /> -<img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"Title\\" width=\\"200\\" height=\\"200\\" /> <img alt={\\"img\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={"img"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} title="Title" width="200" height="200" /> <img alt={"img"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -<img alt={\\"img with "quotes"\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} title=\\"'Quoted' title\\" width=\\"200\\" height=\\"200\\" /> +<img alt={"img with "quotes""} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} title="'Quoted' title" width="200" height="200" /> -<img alt={\\"site alias\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={"site alias"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default} width="200" height="200" /> -<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> -<img alt={\\"img with hash\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png\\").default + '#dark'} width=\\"200\\" height=\\"200\\" /> +<img alt={"img with hash"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#light'} width="200" height="200" /> +<img alt={"img with hash"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png").default + '#dark'} width="200" height="200" /> -<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10\\").default} width=\\"200\\" height=\\"200\\" /> -<img alt={\\"img with query\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default} width=\\"200\\" height=\\"200\\" /> +<img alt={"img with query"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10").default} width="200" height="200" /> +<img alt={"img with query"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default} width="200" height="200" /> -<img alt={\\"img with both\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10\\").default + '#light'} width=\\"200\\" height=\\"200\\" /> +<img alt={"img with both"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/img.png?w=10&h=10").default + '#light'} width="200" height="200" /> ## Heading diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap index 810a5542ed2b..0daf646c0574 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__snapshots__/index.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`transformAsset plugin fail if asset url is absent 1`] = `"Markdown link URL is mandatory in \\"packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/noUrl.md\\" file (title: asset, line: 1)."`; +exports[`transformAsset plugin fail if asset url is absent 1`] = `"Markdown link URL is mandatory in "packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/noUrl.md" file (title: asset, line: 1)."`; exports[`transformAsset plugin fail if asset with site alias does not exist 1`] = `"Asset packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/foo.pdf used in packages/docusaurus-mdx-loader/src/remark/transformLinks/__tests__/__fixtures__/nonexistentSiteAlias.md not found."`; @@ -12,15 +12,15 @@ exports[`transformAsset plugin pathname protocol 1`] = ` exports[`transformAsset plugin transform md links to <a /> 1`] = ` "[asset](https://example.com/asset.pdf) -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}></a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}></a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf').default}>asset with URL encoded chars</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf').default}>asset with URL encoded chars</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default + '#page=2'}>asset with hash</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default + '#page=2'}>asset with hash</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default} title=\\"Title\\">asset</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default} title="Title">asset</a> [page](noUrl.md) @@ -34,24 +34,24 @@ exports[`transformAsset plugin transform md links to <a /> 1`] = ` [assets](/github/!file-loader!/assets.pdf) -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}>asset</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf').default}>asset2</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf').default}>asset2</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>staticAsset.pdf</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>staticAsset.pdf</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>@site/static/staticAsset.pdf</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>@site/static/staticAsset.pdf</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default + '#page=2'} title=\\"Title\\">@site/static/staticAsset.pdf</a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default + '#page=2'} title="Title">@site/static/staticAsset.pdf</a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>Just staticAsset.pdf</a>, and <a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}><strong>awesome</strong> staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf').default}>coded <code>staticAsset 3.pdf</code></a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img alt={\\"Clickable Docusaurus logo\\"} src={require(\\"!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png\\").default} width=\\"200\\" height=\\"200\\" /></a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png').default}><img alt={"Clickable Docusaurus logo"} src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png").default} width="200" height="200" /></a> -<a target=\\"_blank\\" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}><span style={{color: \\"red\\"}}>Stylized link to asset file</span></a> +<a target="_blank" href={require('!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf').default}><span style={{color: "red"}}>Stylized link to asset file</span></a> -<a target=\\"_blank\\" href={require('./data.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json').default}>json</a> +<a target="_blank" href={require('./data.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json').default}>json</a> -<a target=\\"_blank\\" href={require('./static/static-json.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json').default}>static json</a> +<a target="_blank" href={require('./static/static-json.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json').default}>static json</a> " `; diff --git a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap index 35011f30c986..9b8ed7b0ada3 100644 --- a/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/unwrapMdxCodeBlocks/__tests__/__snapshots__/index.test.ts.snap @@ -17,7 +17,7 @@ text import XYZ from 'xyz'; -<XYZ abc=\\"1\\" def={[1, '42', {hello: 'world'}]} style={{color: 'red'}}> +<XYZ abc="1" def={[1, '42', {hello: 'world'}]} style={{color: 'red'}}> <span>Test</span> </XYZ> @@ -32,30 +32,30 @@ import Avatar from 'avatar'; ## Some complex MDX with nested code blocks <Tabs - defaultValue=\\"bash\\" + defaultValue="bash" values={[ { label: 'Bash', value: 'bash' }, { label: 'Windows', value: 'windows' }, { label: 'PowerShell', value: 'powershell' } ]}> - <TabItem value=\\"bash\\"> + <TabItem value="bash"> \`\`\`bash GIT_USER=<GITHUB_USERNAME> yarn deploy \`\`\` </TabItem> - <TabItem value=\\"windows\\"> + <TabItem value="windows"> \`\`\`batch - cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" + cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy" \`\`\` </TabItem> - <TabItem value=\\"powershell\\"> + <TabItem value="powershell"> \`\`\`powershell -cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' +cmd /C 'set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy' \`\`\` </TabItem> @@ -64,30 +64,30 @@ cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' ## Some complex MDX code block with nested code blocks <Tabs - defaultValue=\\"bash\\" + defaultValue="bash" values={[ { label: 'Bash', value: 'bash' }, { label: 'Windows', value: 'windows' }, { label: 'PowerShell', value: 'powershell' } ]}> -<TabItem value=\\"bash\\"> +<TabItem value="bash"> \`\`\`bash GIT_USER=<GITHUB_USERNAME> yarn deploy \`\`\` </TabItem> -<TabItem value=\\"windows\\"> +<TabItem value="windows"> \`\`\`batch -cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" +cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy" \`\`\` </TabItem> -<TabItem value=\\"powershell\\"> +<TabItem value="powershell"> \`\`\`powershell -cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' +cmd /C 'set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy' \`\`\` </TabItem> @@ -421,7 +421,7 @@ exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = }, }, "type": "jsx", - "value": "<XYZ abc=\\"1\\" def={[1, '42', {hello: 'world'}]} style={{color: 'red'}}> + "value": "<XYZ abc="1" def={[1, '42', {hello: 'world'}]} style={{color: 'red'}}> <span>Test</span> </XYZ>", }, @@ -551,13 +551,13 @@ exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = }, "type": "jsx", "value": "<Tabs - defaultValue=\\"bash\\" + defaultValue="bash" values={[ { label: 'Bash', value: 'bash' }, { label: 'Windows', value: 'windows' }, { label: 'PowerShell', value: 'powershell' } ]}> - <TabItem value=\\"bash\\">", + <TabItem value="bash">", }, { "lang": "bash", @@ -599,7 +599,7 @@ exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = }, "type": "jsx", "value": " </TabItem> - <TabItem value=\\"windows\\">", + <TabItem value="windows">", }, { "lang": null, @@ -622,7 +622,7 @@ exports[`unwrapMdxCodeBlocks remark plugin unwraps the mdx code blocks AST 1`] = }, "type": "code", "value": "\`\`\`batch -cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" +cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy" \`\`\`", }, { @@ -643,7 +643,7 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" }, "type": "jsx", "value": " </TabItem> - <TabItem value=\\"powershell\\">", + <TabItem value="powershell">", }, { "lang": "powershell", @@ -665,7 +665,7 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" }, }, "type": "code", - "value": "cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy'", + "value": "cmd /C 'set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy'", }, { "position": Position { @@ -772,30 +772,30 @@ cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" }, "type": "code", "value": "<Tabs - defaultValue=\\"bash\\" + defaultValue="bash" values={[ { label: 'Bash', value: 'bash' }, { label: 'Windows', value: 'windows' }, { label: 'PowerShell', value: 'powershell' } ]}> -<TabItem value=\\"bash\\"> +<TabItem value="bash"> \`\`\`bash GIT_USER=<GITHUB_USERNAME> yarn deploy \`\`\` </TabItem> -<TabItem value=\\"windows\\"> +<TabItem value="windows"> \`\`\`batch -cmd /C \\"set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy\\" +cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy" \`\`\` </TabItem> -<TabItem value=\\"powershell\\"> +<TabItem value="powershell"> \`\`\`powershell -cmd /C 'set \\"GIT_USER=<GITHUB_USERNAME>\\" && yarn deploy' +cmd /C 'set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy' \`\`\` </TabItem> diff --git a/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap index 6bb29e50da09..4fd3d63d75ff 100644 --- a/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-migrate/src/__tests__/__snapshots__/index.test.ts.snap @@ -32,106 +32,106 @@ exports[`migration CLI migrates complex website: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/docusaurus.config.js", "module.exports={ - \\"title\\": \\"Docusaurus\\", - \\"tagline\\": \\"Easy to Maintain Open Source Documentation Websites\\", - \\"url\\": \\"https://docusaurus.io\\", - \\"baseUrl\\": \\"/\\", - \\"organizationName\\": \\"facebook\\", - \\"projectName\\": \\"docusaurus\\", - \\"noIndex\\": false, - \\"scripts\\": [ - \\"https://buttons.github.io/buttons.js\\", - \\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\", - \\"/js/code-blocks-buttons.js\\" + "title": "Docusaurus", + "tagline": "Easy to Maintain Open Source Documentation Websites", + "url": "https://docusaurus.io", + "baseUrl": "/", + "organizationName": "facebook", + "projectName": "docusaurus", + "noIndex": false, + "scripts": [ + "https://buttons.github.io/buttons.js", + "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js", + "/js/code-blocks-buttons.js" ], - \\"favicon\\": \\"img/docusaurus.ico\\", - \\"customFields\\": { - \\"users\\": { - \\"caption\\": \\"DevSpace\\", - \\"image\\": \\"/img/users/devspace.svg\\", - \\"infoLink\\": \\"https://devspace.cloud/docs/\\", - \\"fbOpenSource\\": false, - \\"pinned\\": false + "favicon": "img/docusaurus.ico", + "customFields": { + "users": { + "caption": "DevSpace", + "image": "/img/users/devspace.svg", + "infoLink": "https://devspace.cloud/docs/", + "fbOpenSource": false, + "pinned": false }, - \\"translationRecruitingLink\\": \\"https://crowdin.com/project/docusaurus\\", - \\"facebookAppId\\": \\"199138890728411\\" + "translationRecruitingLink": "https://crowdin.com/project/docusaurus", + "facebookAppId": "199138890728411" }, - \\"onBrokenLinks\\": \\"log\\", - \\"onBrokenMarkdownLinks\\": \\"log\\", - \\"presets\\": [ + "onBrokenLinks": "log", + "onBrokenMarkdownLinks": "log", + "presets": [ [ - \\"@docusaurus/preset-classic\\", + "@docusaurus/preset-classic", { - \\"docs\\": { - \\"showLastUpdateAuthor\\": true, - \\"showLastUpdateTime\\": true, - \\"editUrl\\": \\"https://github.com/facebook/docusaurus/edit/main/docs/\\" + "docs": { + "showLastUpdateAuthor": true, + "showLastUpdateTime": true, + "editUrl": "https://github.com/facebook/docusaurus/edit/main/docs/" }, - \\"blog\\": {}, - \\"theme\\": { - \\"customCss\\": \\"../complex_website/src/css/customTheme.css\\" + "blog": {}, + "theme": { + "customCss": "../complex_website/src/css/customTheme.css" }, - \\"googleAnalytics\\": { - \\"trackingID\\": \\"UA-44373548-31\\" + "googleAnalytics": { + "trackingID": "UA-44373548-31" } } ] ], - \\"plugins\\": [], - \\"themeConfig\\": { - \\"navbar\\": { - \\"title\\": \\"Docusaurus\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus.svg\\" + "plugins": [], + "themeConfig": { + "navbar": { + "title": "Docusaurus", + "logo": { + "src": "img/docusaurus.svg" }, - \\"items\\": [ + "items": [ { - \\"to\\": \\"docs/installation\\", - \\"label\\": \\"Docs\\", - \\"position\\": \\"left\\" + "to": "docs/installation", + "label": "Docs", + "position": "left" }, { - \\"to\\": \\"docs/tutorial-setup\\", - \\"label\\": \\"Tutorial\\", - \\"position\\": \\"left\\" + "to": "docs/tutorial-setup", + "label": "Tutorial", + "position": "left" }, { - \\"to\\": \\"/users\\", - \\"label\\": \\"Users\\", - \\"position\\": \\"left\\" + "to": "/users", + "label": "Users", + "position": "left" }, { - \\"href\\": \\"https://github.com/facebook/docusaurus\\", - \\"label\\": \\"GitHub\\", - \\"position\\": \\"left\\" + "href": "https://github.com/facebook/docusaurus", + "label": "GitHub", + "position": "left" } ] }, - \\"image\\": \\"img/docusaurus.png\\", - \\"footer\\": { - \\"links\\": [ + "image": "img/docusaurus.png", + "footer": { + "links": [ { - \\"title\\": \\"Community\\", - \\"items\\": [ + "title": "Community", + "items": [ { - \\"label\\": \\"Twitter\\", - \\"to\\": \\"https://twitter.com/docusaurus\\" + "label": "Twitter", + "to": "https://twitter.com/docusaurus" } ] } ], - \\"copyright\\": \\"Copyright © 2022 Facebook Inc.\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus_monochrome.svg\\" + "copyright": "Copyright © 2022 Facebook Inc.", + "logo": { + "src": "img/docusaurus_monochrome.svg" } }, - \\"algolia\\": { - \\"apiKey\\": \\"3eb9507824b8be89e7a199ecaa1a9d2c\\", - \\"indexName\\": \\"docusaurus\\", - \\"algoliaOptions\\": { - \\"facetFilters\\": [ - \\"language:LANGUAGE\\", - \\"version:VERSION\\" + "algolia": { + "apiKey": "3eb9507824b8be89e7a199ecaa1a9d2c", + "indexName": "docusaurus", + "algoliaOptions": { + "facetFilters": [ + "language:LANGUAGE", + "version:VERSION" ] } } @@ -141,29 +141,29 @@ exports[`migration CLI migrates complex website: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/package.json", "{ - \\"name\\": \\"docusaurus-1-website\\", - \\"version\\": \\"2.0.0-alpha.58\\", - \\"private\\": true, - \\"scripts\\": { - \\"start\\": \\"docusaurus start\\", - \\"build\\": \\"docusaurus build\\", - \\"publish-gh-pages\\": \\"docusaurus-publish\\", - \\"examples\\": \\"docusaurus-examples\\", - \\"write-translations\\": \\"docusaurus-write-translations\\", - \\"docusaurus-version\\": \\"docusaurus-version\\", - \\"rename-version\\": \\"docusaurus-rename-version\\", - \\"crowdin-upload\\": \\"crowdin --config ../crowdin.yaml upload sources --auto-update -b master\\", - \\"crowdin-download\\": \\"crowdin --config ../crowdin.yaml download -b master\\", - \\"swizzle\\": \\"docusaurus swizzle\\", - \\"deploy\\": \\"docusaurus deploy\\", - \\"docusaurus\\": \\"docusaurus\\" + "name": "docusaurus-1-website", + "version": "2.0.0-alpha.58", + "private": true, + "scripts": { + "start": "docusaurus start", + "build": "docusaurus build", + "publish-gh-pages": "docusaurus-publish", + "examples": "docusaurus-examples", + "write-translations": "docusaurus-write-translations", + "docusaurus-version": "docusaurus-version", + "rename-version": "docusaurus-rename-version", + "crowdin-upload": "crowdin --config ../crowdin.yaml upload sources --auto-update -b master", + "crowdin-download": "crowdin --config ../crowdin.yaml download -b master", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "docusaurus": "docusaurus" }, - \\"dependencies\\": { - \\"@docusaurus/core\\": \\"<CURRENT_VERSION>\\", - \\"@docusaurus/preset-classic\\": \\"<CURRENT_VERSION>\\", - \\"clsx\\": \\"^1.1.1\\", - \\"react\\": \\"^17.0.2\\", - \\"react-dom\\": \\"^17.0.2\\" + "dependencies": { + "@docusaurus/core": "<CURRENT_VERSION>", + "@docusaurus/preset-classic": "<CURRENT_VERSION>", + "clsx": "^1.1.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" } }", ], @@ -215,106 +215,106 @@ exports[`migration CLI migrates missing versions: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/docusaurus.config.js", "module.exports={ - \\"title\\": \\"Docusaurus\\", - \\"tagline\\": \\"Easy to Maintain Open Source Documentation Websites\\", - \\"url\\": \\"https://docusaurus.io\\", - \\"baseUrl\\": \\"/\\", - \\"organizationName\\": \\"facebook\\", - \\"projectName\\": \\"docusaurus\\", - \\"noIndex\\": false, - \\"scripts\\": [ - \\"https://buttons.github.io/buttons.js\\", - \\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\", - \\"/js/code-blocks-buttons.js\\" + "title": "Docusaurus", + "tagline": "Easy to Maintain Open Source Documentation Websites", + "url": "https://docusaurus.io", + "baseUrl": "/", + "organizationName": "facebook", + "projectName": "docusaurus", + "noIndex": false, + "scripts": [ + "https://buttons.github.io/buttons.js", + "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js", + "/js/code-blocks-buttons.js" ], - \\"favicon\\": \\"img/docusaurus.ico\\", - \\"customFields\\": { - \\"users\\": { - \\"caption\\": \\"DevSpace\\", - \\"image\\": \\"/img/users/devspace.svg\\", - \\"infoLink\\": \\"https://devspace.cloud/docs/\\", - \\"fbOpenSource\\": false, - \\"pinned\\": false + "favicon": "img/docusaurus.ico", + "customFields": { + "users": { + "caption": "DevSpace", + "image": "/img/users/devspace.svg", + "infoLink": "https://devspace.cloud/docs/", + "fbOpenSource": false, + "pinned": false }, - \\"translationRecruitingLink\\": \\"https://crowdin.com/project/docusaurus\\", - \\"facebookAppId\\": \\"199138890728411\\" + "translationRecruitingLink": "https://crowdin.com/project/docusaurus", + "facebookAppId": "199138890728411" }, - \\"onBrokenLinks\\": \\"log\\", - \\"onBrokenMarkdownLinks\\": \\"log\\", - \\"presets\\": [ + "onBrokenLinks": "log", + "onBrokenMarkdownLinks": "log", + "presets": [ [ - \\"@docusaurus/preset-classic\\", + "@docusaurus/preset-classic", { - \\"docs\\": { - \\"showLastUpdateAuthor\\": true, - \\"showLastUpdateTime\\": true, - \\"editUrl\\": \\"https://github.com/facebook/docusaurus/edit/main/docs/\\" + "docs": { + "showLastUpdateAuthor": true, + "showLastUpdateTime": true, + "editUrl": "https://github.com/facebook/docusaurus/edit/main/docs/" }, - \\"blog\\": {}, - \\"theme\\": { - \\"customCss\\": \\"../missing_version_website/src/css/customTheme.css\\" + "blog": {}, + "theme": { + "customCss": "../missing_version_website/src/css/customTheme.css" }, - \\"googleAnalytics\\": { - \\"trackingID\\": \\"UA-44373548-31\\" + "googleAnalytics": { + "trackingID": "UA-44373548-31" } } ] ], - \\"plugins\\": [], - \\"themeConfig\\": { - \\"navbar\\": { - \\"title\\": \\"Docusaurus\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus.svg\\" + "plugins": [], + "themeConfig": { + "navbar": { + "title": "Docusaurus", + "logo": { + "src": "img/docusaurus.svg" }, - \\"items\\": [ + "items": [ { - \\"to\\": \\"docs/installation\\", - \\"label\\": \\"Docs\\", - \\"position\\": \\"left\\" + "to": "docs/installation", + "label": "Docs", + "position": "left" }, { - \\"to\\": \\"docs/tutorial-setup\\", - \\"label\\": \\"Tutorial\\", - \\"position\\": \\"left\\" + "to": "docs/tutorial-setup", + "label": "Tutorial", + "position": "left" }, { - \\"to\\": \\"/users\\", - \\"label\\": \\"Users\\", - \\"position\\": \\"left\\" + "to": "/users", + "label": "Users", + "position": "left" }, { - \\"href\\": \\"https://github.com/facebook/docusaurus\\", - \\"label\\": \\"GitHub\\", - \\"position\\": \\"left\\" + "href": "https://github.com/facebook/docusaurus", + "label": "GitHub", + "position": "left" } ] }, - \\"image\\": \\"img/docusaurus.png\\", - \\"footer\\": { - \\"links\\": [ + "image": "img/docusaurus.png", + "footer": { + "links": [ { - \\"title\\": \\"Community\\", - \\"items\\": [ + "title": "Community", + "items": [ { - \\"label\\": \\"Twitter\\", - \\"to\\": \\"https://twitter.com/docusaurus\\" + "label": "Twitter", + "to": "https://twitter.com/docusaurus" } ] } ], - \\"copyright\\": \\"Copyright © 2022 Facebook Inc.\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus_monochrome.svg\\" + "copyright": "Copyright © 2022 Facebook Inc.", + "logo": { + "src": "img/docusaurus_monochrome.svg" } }, - \\"algolia\\": { - \\"apiKey\\": \\"3eb9507824b8be89e7a199ecaa1a9d2c\\", - \\"indexName\\": \\"docusaurus\\", - \\"algoliaOptions\\": { - \\"facetFilters\\": [ - \\"language:LANGUAGE\\", - \\"version:VERSION\\" + "algolia": { + "apiKey": "3eb9507824b8be89e7a199ecaa1a9d2c", + "indexName": "docusaurus", + "algoliaOptions": { + "facetFilters": [ + "language:LANGUAGE", + "version:VERSION" ] } } @@ -324,29 +324,29 @@ exports[`migration CLI migrates missing versions: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/package.json", "{ - \\"name\\": \\"docusaurus-1-website\\", - \\"version\\": \\"2.0.0-alpha.58\\", - \\"private\\": true, - \\"scripts\\": { - \\"start\\": \\"docusaurus start\\", - \\"build\\": \\"docusaurus build\\", - \\"publish-gh-pages\\": \\"docusaurus-publish\\", - \\"examples\\": \\"docusaurus-examples\\", - \\"write-translations\\": \\"docusaurus-write-translations\\", - \\"docusaurus-version\\": \\"docusaurus-version\\", - \\"rename-version\\": \\"docusaurus-rename-version\\", - \\"crowdin-upload\\": \\"crowdin --config ../crowdin.yaml upload sources --auto-update -b master\\", - \\"crowdin-download\\": \\"crowdin --config ../crowdin.yaml download -b master\\", - \\"swizzle\\": \\"docusaurus swizzle\\", - \\"deploy\\": \\"docusaurus deploy\\", - \\"docusaurus\\": \\"docusaurus\\" + "name": "docusaurus-1-website", + "version": "2.0.0-alpha.58", + "private": true, + "scripts": { + "start": "docusaurus start", + "build": "docusaurus build", + "publish-gh-pages": "docusaurus-publish", + "examples": "docusaurus-examples", + "write-translations": "docusaurus-write-translations", + "docusaurus-version": "docusaurus-version", + "rename-version": "docusaurus-rename-version", + "crowdin-upload": "crowdin --config ../crowdin.yaml upload sources --auto-update -b master", + "crowdin-download": "crowdin --config ../crowdin.yaml download -b master", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "docusaurus": "docusaurus" }, - \\"dependencies\\": { - \\"@docusaurus/core\\": \\"<CURRENT_VERSION>\\", - \\"@docusaurus/preset-classic\\": \\"<CURRENT_VERSION>\\", - \\"clsx\\": \\"^1.1.1\\", - \\"react\\": \\"^17.0.2\\", - \\"react-dom\\": \\"^17.0.2\\" + "dependencies": { + "@docusaurus/core": "<CURRENT_VERSION>", + "@docusaurus/preset-classic": "<CURRENT_VERSION>", + "clsx": "^1.1.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" } }", ], @@ -394,107 +394,107 @@ exports[`migration CLI migrates simple website: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/docusaurus.config.js", "module.exports={ - \\"title\\": \\"Docusaurus\\", - \\"tagline\\": \\"Easy to Maintain Open Source Documentation Websites\\", - \\"url\\": \\"https://docusaurus.io\\", - \\"baseUrl\\": \\"/\\", - \\"organizationName\\": \\"facebook\\", - \\"projectName\\": \\"docusaurus\\", - \\"noIndex\\": false, - \\"scripts\\": [ - \\"https://buttons.github.io/buttons.js\\", - \\"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js\\", - \\"/js/code-blocks-buttons.js\\" + "title": "Docusaurus", + "tagline": "Easy to Maintain Open Source Documentation Websites", + "url": "https://docusaurus.io", + "baseUrl": "/", + "organizationName": "facebook", + "projectName": "docusaurus", + "noIndex": false, + "scripts": [ + "https://buttons.github.io/buttons.js", + "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js", + "/js/code-blocks-buttons.js" ], - \\"favicon\\": \\"img/docusaurus.ico\\", - \\"customFields\\": { - \\"users\\": { - \\"caption\\": \\"DevSpace\\", - \\"image\\": \\"/img/users/devspace.svg\\", - \\"infoLink\\": \\"https://devspace.cloud/docs/\\", - \\"fbOpenSource\\": false, - \\"pinned\\": false + "favicon": "img/docusaurus.ico", + "customFields": { + "users": { + "caption": "DevSpace", + "image": "/img/users/devspace.svg", + "infoLink": "https://devspace.cloud/docs/", + "fbOpenSource": false, + "pinned": false }, - \\"translationRecruitingLink\\": \\"https://crowdin.com/project/docusaurus\\", - \\"facebookAppId\\": \\"199138890728411\\" + "translationRecruitingLink": "https://crowdin.com/project/docusaurus", + "facebookAppId": "199138890728411" }, - \\"onBrokenLinks\\": \\"log\\", - \\"onBrokenMarkdownLinks\\": \\"log\\", - \\"presets\\": [ + "onBrokenLinks": "log", + "onBrokenMarkdownLinks": "log", + "presets": [ [ - \\"@docusaurus/preset-classic\\", + "@docusaurus/preset-classic", { - \\"docs\\": { - \\"showLastUpdateAuthor\\": true, - \\"showLastUpdateTime\\": true, - \\"editUrl\\": \\"https://github.com/facebook/docusaurus/edit/main/docs/\\", - \\"path\\": \\"../simple_website/docs\\" + "docs": { + "showLastUpdateAuthor": true, + "showLastUpdateTime": true, + "editUrl": "https://github.com/facebook/docusaurus/edit/main/docs/", + "path": "../simple_website/docs" }, - \\"blog\\": {}, - \\"theme\\": { - \\"customCss\\": \\"../simple_website/src/css/customTheme.css\\" + "blog": {}, + "theme": { + "customCss": "../simple_website/src/css/customTheme.css" }, - \\"googleAnalytics\\": { - \\"trackingID\\": \\"UA-44373548-31\\" + "googleAnalytics": { + "trackingID": "UA-44373548-31" } } ] ], - \\"plugins\\": [], - \\"themeConfig\\": { - \\"navbar\\": { - \\"title\\": \\"Docusaurus\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus.svg\\" + "plugins": [], + "themeConfig": { + "navbar": { + "title": "Docusaurus", + "logo": { + "src": "img/docusaurus.svg" }, - \\"items\\": [ + "items": [ { - \\"to\\": \\"docs/installation\\", - \\"label\\": \\"Docs\\", - \\"position\\": \\"left\\" + "to": "docs/installation", + "label": "Docs", + "position": "left" }, { - \\"to\\": \\"docs/tutorial-setup\\", - \\"label\\": \\"Tutorial\\", - \\"position\\": \\"left\\" + "to": "docs/tutorial-setup", + "label": "Tutorial", + "position": "left" }, { - \\"to\\": \\"/users\\", - \\"label\\": \\"Users\\", - \\"position\\": \\"left\\" + "to": "/users", + "label": "Users", + "position": "left" }, { - \\"href\\": \\"https://github.com/facebook/docusaurus\\", - \\"label\\": \\"GitHub\\", - \\"position\\": \\"left\\" + "href": "https://github.com/facebook/docusaurus", + "label": "GitHub", + "position": "left" } ] }, - \\"image\\": \\"img/docusaurus.png\\", - \\"footer\\": { - \\"links\\": [ + "image": "img/docusaurus.png", + "footer": { + "links": [ { - \\"title\\": \\"Community\\", - \\"items\\": [ + "title": "Community", + "items": [ { - \\"label\\": \\"Twitter\\", - \\"to\\": \\"https://twitter.com/docusaurus\\" + "label": "Twitter", + "to": "https://twitter.com/docusaurus" } ] } ], - \\"copyright\\": \\"Copyright © 2022 Facebook Inc.\\", - \\"logo\\": { - \\"src\\": \\"img/docusaurus_monochrome.svg\\" + "copyright": "Copyright © 2022 Facebook Inc.", + "logo": { + "src": "img/docusaurus_monochrome.svg" } }, - \\"algolia\\": { - \\"apiKey\\": \\"3eb9507824b8be89e7a199ecaa1a9d2c\\", - \\"indexName\\": \\"docusaurus\\", - \\"algoliaOptions\\": { - \\"facetFilters\\": [ - \\"language:LANGUAGE\\", - \\"version:VERSION\\" + "algolia": { + "apiKey": "3eb9507824b8be89e7a199ecaa1a9d2c", + "indexName": "docusaurus", + "algoliaOptions": { + "facetFilters": [ + "language:LANGUAGE", + "version:VERSION" ] } } @@ -504,29 +504,29 @@ exports[`migration CLI migrates simple website: write 1`] = ` [ "<PROJECT_ROOT>/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/package.json", "{ - \\"name\\": \\"docusaurus-1-website\\", - \\"version\\": \\"2.0.0-alpha.58\\", - \\"private\\": true, - \\"scripts\\": { - \\"start\\": \\"docusaurus start\\", - \\"build\\": \\"docusaurus build\\", - \\"publish-gh-pages\\": \\"docusaurus-publish\\", - \\"examples\\": \\"docusaurus-examples\\", - \\"write-translations\\": \\"docusaurus-write-translations\\", - \\"docusaurus-version\\": \\"docusaurus-version\\", - \\"rename-version\\": \\"docusaurus-rename-version\\", - \\"crowdin-upload\\": \\"crowdin --config ../crowdin.yaml upload sources --auto-update -b master\\", - \\"crowdin-download\\": \\"crowdin --config ../crowdin.yaml download -b master\\", - \\"swizzle\\": \\"docusaurus swizzle\\", - \\"deploy\\": \\"docusaurus deploy\\", - \\"docusaurus\\": \\"docusaurus\\" + "name": "docusaurus-1-website", + "version": "2.0.0-alpha.58", + "private": true, + "scripts": { + "start": "docusaurus start", + "build": "docusaurus build", + "publish-gh-pages": "docusaurus-publish", + "examples": "docusaurus-examples", + "write-translations": "docusaurus-write-translations", + "docusaurus-version": "docusaurus-version", + "rename-version": "docusaurus-rename-version", + "crowdin-upload": "crowdin --config ../crowdin.yaml upload sources --auto-update -b master", + "crowdin-download": "crowdin --config ../crowdin.yaml download -b master", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "docusaurus": "docusaurus" }, - \\"dependencies\\": { - \\"@docusaurus/core\\": \\"<CURRENT_VERSION>\\", - \\"@docusaurus/preset-classic\\": \\"<CURRENT_VERSION>\\", - \\"clsx\\": \\"^1.1.1\\", - \\"react\\": \\"^17.0.2\\", - \\"react-dom\\": \\"^17.0.2\\" + "dependencies": { + "@docusaurus/core": "<CURRENT_VERSION>", + "@docusaurus/preset-classic": "<CURRENT_VERSION>", + "clsx": "^1.1.1", + "react": "^17.0.2", + "react-dom": "^17.0.2" } }", ], diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap index 7c9cd4ee9de9..a9ce789f9861 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/collectRedirects.test.ts.snap @@ -14,14 +14,14 @@ Valid paths you can redirect to: exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = ` "Some created redirects are invalid: -- {\\"from\\":[\\"/fromPath\\"],\\"to\\":\\"/\\"} => Validation error: \\"from\\" must be a string +- {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string " `; exports[`collectRedirects throws if redirect creator creates invalid redirects 1`] = ` "Some created redirects are invalid: -- {\\"from\\":\\"https://google.com/\\",\\"to\\":\\"/\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. -- {\\"from\\":\\"//abc\\",\\"to\\":\\"/\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. -- {\\"from\\":\\"/def?queryString=toto\\",\\"to\\":\\"/\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. +- {"from":"https://google.com/","to":"/"} => Validation error: "from" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. +- {"from":"//abc","to":"/"} => Validation error: "from" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. +- {"from":"/def?queryString=toto","to":"/"} => Validation error: "from" is not a valid pathname. Pathname should start with slash and not contain any domain or query string. " `; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap index 7882ae877ad0..a98e1c3f7ed7 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/createRedirectPageContent.test.ts.snap @@ -4,9 +4,9 @@ exports[`createRedirectPageContent encodes uri special chars 1`] = ` "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/"> + <link rel="canonical" href="https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/" /> </head> <script> window.location.href = 'https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/'; @@ -18,9 +18,9 @@ exports[`createRedirectPageContent works 1`] = ` "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/"> + <link rel="canonical" href="https://docusaurus.io/" /> </head> <script> window.location.href = 'https://docusaurus.io/'; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap index 83f23180a018..db2fe1ed15cb 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/options.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = `"\\"createRedirects\\" must be of type function"`; +exports[`normalizePluginOptions rejects bad createRedirects user inputs 1`] = `""createRedirects" must be of type function"`; -exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = `"\\"fromExtensions[0]\\" contains an invalid value"`; +exports[`normalizePluginOptions rejects bad fromExtensions user inputs 1`] = `""fromExtensions[0]" contains an invalid value"`; -exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = `"\\"toExtensions[0]\\" contains an invalid value"`; +exports[`normalizePluginOptions rejects bad toExtensions user inputs 1`] = `""toExtensions[0]" contains an invalid value"`; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap index 0153b77a23dd..d76b4d18d1f3 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/redirectValidation.test.ts.snap @@ -1,11 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validateRedirect throw for bad redirects 1`] = `"{\\"from\\":\\"https://fb.com/fromSomePath\\",\\"to\\":\\"/toSomePath\\"} => Validation error: \\"from\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validateRedirect throw for bad redirects 1`] = `"{"from":"https://fb.com/fromSomePath","to":"/toSomePath"} => Validation error: "from" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validateRedirect throw for bad redirects 2`] = `"{\\"from\\":\\"/fromSomePath\\",\\"to\\":\\"https://fb.com/toSomePath\\"} => Validation error: \\"to\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validateRedirect throw for bad redirects 2`] = `"{"from":"/fromSomePath","to":"https://fb.com/toSomePath"} => Validation error: "to" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validateRedirect throw for bad redirects 3`] = `"{\\"from\\":\\"/fromSomePath\\",\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"to\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validateRedirect throw for bad redirects 3`] = `"{"from":"/fromSomePath","to":"/toSomePath?queryString=xyz"} => Validation error: "to" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validateRedirect throw for bad redirects 4`] = `"{\\"from\\":null,\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"from\\" must be a string"`; +exports[`validateRedirect throw for bad redirects 4`] = `"{"from":null,"to":"/toSomePath?queryString=xyz"} => Validation error: "from" must be a string"`; -exports[`validateRedirect throw for bad redirects 5`] = `"{\\"from\\":[\\"hey\\"],\\"to\\":\\"/toSomePath?queryString=xyz\\"} => Validation error: \\"from\\" must be a string"`; +exports[`validateRedirect throw for bad redirects 5`] = `"{"from":["hey"],"to":"/toSomePath?queryString=xyz"} => Validation error: "from" must be a string"`; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap index fa9472e3b172..1405eefda432 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/__snapshots__/writeRedirectFiles.test.ts.snap @@ -5,9 +5,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata for empty baseUrl: "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=/abc\\"> - <link rel=\\"canonical\\" href=\\"/abc\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=/abc"> + <link rel="canonical" href="/abc" /> </head> <script> window.location.href = '/abc'; @@ -21,9 +21,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata for root baseUrl: "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=/abc\\"> - <link rel=\\"canonical\\" href=\\"/abc\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=/abc"> + <link rel="canonical" href="/abc" /> </head> <script> window.location.href = '/abc'; @@ -37,9 +37,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=fals "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/abc\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/abc\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/abc"> + <link rel="canonical" href="https://docusaurus.io/abc" /> </head> <script> window.location.href = 'https://docusaurus.io/abc'; @@ -48,9 +48,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=fals "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/def.html\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/def.html\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/def.html"> + <link rel="canonical" href="https://docusaurus.io/def.html" /> </head> <script> window.location.href = 'https://docusaurus.io/def.html'; @@ -59,9 +59,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=fals "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/"> + <link rel="canonical" href="https://docusaurus.io/" /> </head> <script> window.location.href = 'https://docusaurus.io/'; @@ -75,9 +75,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=true "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/abc\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/abc\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/abc"> + <link rel="canonical" href="https://docusaurus.io/abc" /> </head> <script> window.location.href = 'https://docusaurus.io/abc'; @@ -86,9 +86,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=true "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/def.html\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/def.html\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/def.html"> + <link rel="canonical" href="https://docusaurus.io/def.html" /> </head> <script> window.location.href = 'https://docusaurus.io/def.html'; @@ -97,9 +97,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=true "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/"> + <link rel="canonical" href="https://docusaurus.io/" /> </head> <script> window.location.href = 'https://docusaurus.io/'; @@ -113,9 +113,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=unde "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/abc\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/abc\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/abc"> + <link rel="canonical" href="https://docusaurus.io/abc" /> </head> <script> window.location.href = 'https://docusaurus.io/abc'; @@ -124,9 +124,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=unde "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/def.html\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/def.html\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/def.html"> + <link rel="canonical" href="https://docusaurus.io/def.html" /> </head> <script> window.location.href = 'https://docusaurus.io/def.html'; @@ -135,9 +135,9 @@ exports[`toRedirectFilesMetadata creates appropriate metadata trailingSlash=unde "<!DOCTYPE html> <html> <head> - <meta charset=\\"UTF-8\\"> - <meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\"> - <link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" /> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="0; url=https://docusaurus.io/"> + <link rel="canonical" href="https://docusaurus.io/" /> </head> <script> window.location.href = 'https://docusaurus.io/'; diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts index 59f60c679e89..8fff636cff9d 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/extensionRedirects.test.ts @@ -15,8 +15,8 @@ describe('createToExtensionsRedirects', () => { expect(() => { createToExtensionsRedirects(['/'], ['']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\"\\" is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension "" is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -24,8 +24,8 @@ describe('createToExtensionsRedirects', () => { expect(() => { createToExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\".html\\" contains a \\".\\" (dot) which is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension ".html" contains a "." (dot) which is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -33,8 +33,8 @@ describe('createToExtensionsRedirects', () => { expect(() => { createToExtensionsRedirects(['/'], ['ht/ml']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\"ht/ml\\" contains a \\"/\\" (slash) which is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension "ht/ml" contains a "/" (slash) which is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -42,8 +42,8 @@ describe('createToExtensionsRedirects', () => { expect(() => { createToExtensionsRedirects(['/'], [',']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\",\\" contains invalid URI characters. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension "," contains invalid URI characters. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -79,8 +79,8 @@ describe('createFromExtensionsRedirects', () => { expect(() => { createFromExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\".html\\" contains a \\".\\" (dot) which is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension ".html" contains a "." (dot) which is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -88,8 +88,8 @@ describe('createFromExtensionsRedirects', () => { expect(() => { createFromExtensionsRedirects(['/'], ['.html']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\".html\\" contains a \\".\\" (dot) which is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension ".html" contains a "." (dot) which is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -97,8 +97,8 @@ describe('createFromExtensionsRedirects', () => { expect(() => { createFromExtensionsRedirects(['/'], ['ht/ml']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\"ht/ml\\" contains a \\"/\\" (slash) which is not allowed. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension "ht/ml" contains a "/" (slash) which is not allowed. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); @@ -106,8 +106,8 @@ describe('createFromExtensionsRedirects', () => { expect(() => { createFromExtensionsRedirects(['/'], [',']); }).toThrowErrorMatchingInlineSnapshot(` - "Extension \\",\\" contains invalid URI characters. - If the redirect extension system is not good enough for your use case, you can create redirects yourself with the \\"createRedirects\\" plugin option." + "Extension "," contains invalid URI characters. + If the redirect extension system is not good enough for your use case, you can create redirects yourself with the "createRedirects" plugin option." `); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index 5fa35968ed25..bf7d608e30c6 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -2,76 +2,76 @@ exports[`atom has feed item for each post 1`] = ` [ - "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?> -<feed xmlns=\\"http://www.w3.org/2005/Atom\\"> + "<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"> <id>https://docusaurus.io/myBaseUrl/blog</id> <title>Hello Blog 2021-03-06T00:00:00.000Z https://github.com/jpmonette/feed - + Hello Blog https://docusaurus.io/myBaseUrl/image/favicon.ico Copyright - <![CDATA[MDX Blog Sample with require calls]]> + <![CDATA[MDX Blog Sample with require calls]]> /mdx-require-blog-post - + 2021-03-06T00:00:00.000Z -

    - Test MDX with require calls

    ]]>
    + + Test MDX with require calls

    ]]>
    - <![CDATA[Full Blog Sample]]> + <![CDATA[Full Blog Sample]]> /mdx-blog-post - + 2021-03-05T00:00:00.000Z - - HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    link\\"image\\"

    ]]>
    + + HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    linkimage

    ]]>
    - <![CDATA[Complex Slug]]> + <![CDATA[Complex Slug]]> /hey/my super path/héllô - + 2020-08-16T00:00:00.000Z - - complex url slug

    ]]>
    - - + + complex url slug

    ]]>
    + +
    - <![CDATA[Simple Slug]]> + <![CDATA[Simple Slug]]> /simple/slug - + 2020-08-15T00:00:00.000Z - - simple url slug

    ]]>
    + + simple url slug

    ]]>
    Sébastien Lorber https://sebastienlorber.com
    - <![CDATA[some heading]]> + <![CDATA[some heading]]> /heading-as-title - + 2019-01-02T00:00:00.000Z - <![CDATA[date-matter]]> + <![CDATA[date-matter]]> /date-matter - + 2019-01-01T00:00:00.000Z - - date inside front matter

    ]]>
    - + + date inside front matter

    ]]>
    +
    - <![CDATA[Happy 1st Birthday Slash! (translated)]]> + <![CDATA[Happy 1st Birthday Slash! (translated)]]> /2018/12/14/Happy-First-Birthday-Slash - + 2018-12-14T00:00:00.000Z - - Happy birthday!

    ]]>
    + + Happy birthday!

    ]]>
    Yangshun Tay (translated) @@ -87,84 +87,84 @@ exports[`atom has feed item for each post 1`] = ` exports[`json has feed item for each post 1`] = ` [ "{ - \\"version\\": \\"https://jsonfeed.org/version/1\\", - \\"title\\": \\"Hello Blog\\", - \\"home_page_url\\": \\"https://docusaurus.io/myBaseUrl/blog\\", - \\"description\\": \\"Hello Blog\\", - \\"items\\": [ + "version": "https://jsonfeed.org/version/1", + "title": "Hello Blog", + "home_page_url": "https://docusaurus.io/myBaseUrl/blog", + "description": "Hello Blog", + "items": [ { - \\"id\\": \\"/mdx-require-blog-post\\", - \\"content_html\\": \\"

    Test MDX with require calls

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post\\", - \\"title\\": \\"MDX Blog Sample with require calls\\", - \\"summary\\": \\"Test MDX with require calls\\", - \\"date_modified\\": \\"2021-03-06T00:00:00.000Z\\", - \\"tags\\": [] + "id": "/mdx-require-blog-post", + "content_html": "

    Test MDX with require calls

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post", + "title": "MDX Blog Sample with require calls", + "summary": "Test MDX with require calls", + "date_modified": "2021-03-06T00:00:00.000Z", + "tags": [] }, { - \\"id\\": \\"/mdx-blog-post\\", - \\"content_html\\": \\"

    HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    link\\\\\\"image\\\\\\"

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/mdx-blog-post\\", - \\"title\\": \\"Full Blog Sample\\", - \\"summary\\": \\"HTML Heading 1\\", - \\"date_modified\\": \\"2021-03-05T00:00:00.000Z\\", - \\"tags\\": [] + "id": "/mdx-blog-post", + "content_html": "

    HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    link\\"image\\"

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/mdx-blog-post", + "title": "Full Blog Sample", + "summary": "HTML Heading 1", + "date_modified": "2021-03-05T00:00:00.000Z", + "tags": [] }, { - \\"id\\": \\"/hey/my super path/héllô\\", - \\"content_html\\": \\"

    complex url slug

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô\\", - \\"title\\": \\"Complex Slug\\", - \\"summary\\": \\"complex url slug\\", - \\"date_modified\\": \\"2020-08-16T00:00:00.000Z\\", - \\"tags\\": [ - \\"date\\", - \\"complex\\" + "id": "/hey/my super path/héllô", + "content_html": "

    complex url slug

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô", + "title": "Complex Slug", + "summary": "complex url slug", + "date_modified": "2020-08-16T00:00:00.000Z", + "tags": [ + "date", + "complex" ] }, { - \\"id\\": \\"/simple/slug\\", - \\"content_html\\": \\"

    simple url slug

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/simple/slug\\", - \\"title\\": \\"Simple Slug\\", - \\"summary\\": \\"simple url slug\\", - \\"date_modified\\": \\"2020-08-15T00:00:00.000Z\\", - \\"author\\": { - \\"name\\": \\"Sébastien Lorber\\", - \\"url\\": \\"https://sebastienlorber.com\\" + "id": "/simple/slug", + "content_html": "

    simple url slug

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/simple/slug", + "title": "Simple Slug", + "summary": "simple url slug", + "date_modified": "2020-08-15T00:00:00.000Z", + "author": { + "name": "Sébastien Lorber", + "url": "https://sebastienlorber.com" }, - \\"tags\\": [] + "tags": [] }, { - \\"id\\": \\"/heading-as-title\\", - \\"content_html\\": \\"\\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/heading-as-title\\", - \\"title\\": \\"some heading\\", - \\"date_modified\\": \\"2019-01-02T00:00:00.000Z\\", - \\"tags\\": [] + "id": "/heading-as-title", + "content_html": "", + "url": "https://docusaurus.io/myBaseUrl/blog/heading-as-title", + "title": "some heading", + "date_modified": "2019-01-02T00:00:00.000Z", + "tags": [] }, { - \\"id\\": \\"/date-matter\\", - \\"content_html\\": \\"

    date inside front matter

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/date-matter\\", - \\"title\\": \\"date-matter\\", - \\"summary\\": \\"date inside front matter\\", - \\"date_modified\\": \\"2019-01-01T00:00:00.000Z\\", - \\"tags\\": [ - \\"date\\" + "id": "/date-matter", + "content_html": "

    date inside front matter

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/date-matter", + "title": "date-matter", + "summary": "date inside front matter", + "date_modified": "2019-01-01T00:00:00.000Z", + "tags": [ + "date" ] }, { - \\"id\\": \\"/2018/12/14/Happy-First-Birthday-Slash\\", - \\"content_html\\": \\"

    Happy birthday!

    \\", - \\"url\\": \\"https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash\\", - \\"title\\": \\"Happy 1st Birthday Slash! (translated)\\", - \\"summary\\": \\"Happy birthday! (translated)\\", - \\"date_modified\\": \\"2018-12-14T00:00:00.000Z\\", - \\"author\\": { - \\"name\\": \\"Yangshun Tay (translated)\\" + "id": "/2018/12/14/Happy-First-Birthday-Slash", + "content_html": "

    Happy birthday!

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash", + "title": "Happy 1st Birthday Slash! (translated)", + "summary": "Happy birthday! (translated)", + "date_modified": "2018-12-14T00:00:00.000Z", + "author": { + "name": "Yangshun Tay (translated)" }, - \\"tags\\": [] + "tags": [] } ] }", @@ -173,8 +173,8 @@ exports[`json has feed item for each post 1`] = ` exports[`rss has feed item for each post 1`] = ` [ - " - + " + Hello Blog https://docusaurus.io/myBaseUrl/blog @@ -190,7 +190,7 @@ exports[`rss has feed item for each post 1`] = ` /mdx-require-blog-post Sat, 06 Mar 2021 00:00:00 GMT - Test MDX with require calls

    ]]>
    + Test MDX with require calls

    ]]>
    <![CDATA[Full Blog Sample]]> @@ -198,7 +198,7 @@ exports[`rss has feed item for each post 1`] = ` /mdx-blog-post Fri, 05 Mar 2021 00:00:00 GMT - HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    link\\"image\\"

    ]]>
    + HTML Heading 1

    HTML Heading 2

    HTML Paragraph

    Import DOM

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    • list1
    • list2
    • list3
    • list1
    • list2
    • list3

    Normal Text Italics Text Bold Text

    linkimage

    ]]>
    <![CDATA[Complex Slug]]> diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap index 76f0a53c41b7..4406ef7b72eb 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/options.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validateOptions throws Error in case of invalid feed type 1`] = `"\\"feedOptions.type\\" does not match any of the allowed types"`; +exports[`validateOptions throws Error in case of invalid feed type 1`] = `""feedOptions.type" does not match any of the allowed types"`; -exports[`validateOptions throws Error in case of invalid options 1`] = `"\\"postsPerPage\\" must be greater than or equal to 1"`; +exports[`validateOptions throws Error in case of invalid options 1`] = `""postsPerPage" must be greater than or equal to 1"`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts index 0fde188e85af..67dd4571eae7 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/authors.test.ts @@ -200,13 +200,14 @@ describe('getBlogPostAuthors', () => { frontMatter: { authors: 'slorber', }, + authorsMap: { yangshun: {name: 'Yangshun Tay'}, jmarcey: {name: 'Joel Marcey'}, }, }), ).toThrowErrorMatchingInlineSnapshot(` - "Blog author with key \\"slorber\\" not found in the authors map file. + "Blog author with key "slorber" not found in the authors map file. Valid author keys are: - yangshun - jmarcey" @@ -219,13 +220,14 @@ describe('getBlogPostAuthors', () => { frontMatter: { authors: ['yangshun', 'jmarcey', 'slorber'], }, + authorsMap: { yangshun: {name: 'Yangshun Tay'}, jmarcey: {name: 'Joel Marcey'}, }, }), ).toThrowErrorMatchingInlineSnapshot(` - "Blog author with key \\"slorber\\" not found in the authors map file. + "Blog author with key "slorber" not found in the authors map file. Valid author keys are: - yangshun - jmarcey" @@ -238,13 +240,14 @@ describe('getBlogPostAuthors', () => { frontMatter: { authors: [{key: 'yangshun'}, {key: 'jmarcey'}, {key: 'slorber'}], }, + authorsMap: { yangshun: {name: 'Yangshun Tay'}, jmarcey: {name: 'Joel Marcey'}, }, }), ).toThrowErrorMatchingInlineSnapshot(` - "Blog author with key \\"slorber\\" not found in the authors map file. + "Blog author with key "slorber" not found in the authors map file. Valid author keys are: - yangshun - jmarcey" @@ -372,7 +375,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap(authorsMap), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" must contain at least one of [name, imageURL]"`, + `""slorber" must contain at least one of [name, imageURL]"`, ); }); @@ -382,7 +385,7 @@ describe('validateAuthorsMap', () => { slorber: undefined, }), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" cannot be undefined. It should be an author object containing properties like name, title, and imageURL."`, + `""slorber" cannot be undefined. It should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -392,7 +395,7 @@ describe('validateAuthorsMap', () => { slorber: null, }), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, + `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -400,7 +403,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap({slorber: []}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, + `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -414,7 +417,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap({name: 'Sébastien'}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"name\\" should be an author object containing properties like name, title, and imageURL."`, + `""name" should be an author object containing properties like name, title, and imageURL."`, ); }); @@ -426,7 +429,7 @@ describe('validateAuthorsMap', () => { expect(() => validateAuthorsMap(authorsMap), ).toThrowErrorMatchingInlineSnapshot( - `"\\"slorber\\" should be an author object containing properties like name, title, and imageURL."`, + `""slorber" should be an author object containing properties like name, title, and imageURL."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts index 738884dd0297..2b375f7cee52 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/options.test.ts @@ -139,7 +139,7 @@ describe('validateOptions', () => { it('rejects "abcdef" sidebar count', () => { const userOptions = {blogSidebarCount: 'abcdef'}; expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot( - `"\\"blogSidebarCount\\" must be one of [ALL, number]"`, + `""blogSidebarCount" must be one of [ALL, number]"`, ); }); @@ -154,7 +154,7 @@ describe('validateOptions', () => { it('rejects 42 sidebar title', () => { const userOptions = {blogSidebarTitle: 42}; expect(() => testValidate(userOptions)).toThrowErrorMatchingInlineSnapshot( - `"\\"blogSidebarTitle\\" must be a string"`, + `""blogSidebarTitle" must be a string"`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 2af71ead7b26..2a675b5ecfe5 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -17,7 +17,7 @@ exports[`sidebar site with undefined sidebar 1`] = ` `; exports[`sidebar site with wrong sidebar content 1`] = ` -"Invalid sidebar file at \\"packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json\\". +"Invalid sidebar file at "packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json". These sidebar document ids do not exist: - nonExistent @@ -367,604 +367,604 @@ exports[`simple website content 5`] = ` exports[`simple website content: data 1`] = ` { "category-docs-docs-category-slugs-0fe.json": "{ - \\"title\\": \\"Slugs\\", - \\"slug\\": \\"/category/slugs\\", - \\"permalink\\": \\"/docs/category/slugs\\", - \\"navigation\\": { - \\"previous\\": { - \\"title\\": \\"baz pagination_label\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - \\"next\\": { - \\"title\\": \\"rootAbsoluteSlug\\", - \\"permalink\\": \\"/docs/rootAbsoluteSlug\\" + "title": "Slugs", + "slug": "/category/slugs", + "permalink": "/docs/category/slugs", + "navigation": { + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "rootAbsoluteSlug", + "permalink": "/docs/rootAbsoluteSlug" } } }", "site-docs-doc-with-space-md-e90.json": "{ - \\"unversionedId\\": \\"doc with space\\", - \\"id\\": \\"doc with space\\", - \\"title\\": \\"Hoo hoo, if this path tricks you...\\", - \\"description\\": \\"\\", - \\"source\\": \\"@site/docs/doc with space.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/doc with space\\", - \\"permalink\\": \\"/docs/doc with space\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": {} + "unversionedId": "doc with space", + "id": "doc with space", + "title": "Hoo hoo, if this path tricks you...", + "description": "", + "source": "@site/docs/doc with space.md", + "sourceDirName": ".", + "slug": "/doc with space", + "permalink": "/docs/doc with space", + "tags": [], + "version": "current", + "frontMatter": {} }", "site-docs-foo-bar-md-8c2.json": "{ - \\"unversionedId\\": \\"foo/bar\\", - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"Bar\\", - \\"description\\": \\"This is custom description\\", - \\"source\\": \\"@site/docs/foo/bar.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/bar\\", - \\"permalink\\": \\"/docs/foo/bar\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"id\\": \\"bar\\", - \\"title\\": \\"Bar\\", - \\"description\\": \\"This is custom description\\", - \\"pagination_next\\": null, - \\"pagination_prev\\": null - }, - \\"sidebar\\": \\"docs\\" + "unversionedId": "foo/bar", + "id": "foo/bar", + "title": "Bar", + "description": "This is custom description", + "source": "@site/docs/foo/bar.md", + "sourceDirName": "foo", + "slug": "/foo/bar", + "permalink": "/docs/foo/bar", + "tags": [], + "version": "current", + "frontMatter": { + "id": "bar", + "title": "Bar", + "description": "This is custom description", + "pagination_next": null, + "pagination_prev": null + }, + "sidebar": "docs" }", "site-docs-foo-baz-md-a69.json": "{ - \\"unversionedId\\": \\"foo/baz\\", - \\"id\\": \\"foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Images\\", - \\"source\\": \\"@site/docs/foo/baz.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/bazSlug.html\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\", - \\"tags\\": [ - { - \\"label\\": \\"tag 1\\", - \\"permalink\\": \\"/docs/tags/tag-1\\" - }, - { - \\"label\\": \\"tag 2\\", - \\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\" + "unversionedId": "foo/baz", + "id": "foo/baz", + "title": "baz", + "description": "Images", + "source": "@site/docs/foo/baz.md", + "sourceDirName": "foo", + "slug": "/foo/bazSlug.html", + "permalink": "/docs/foo/bazSlug.html", + "tags": [ + { + "label": "tag 1", + "permalink": "/docs/tags/tag-1" + }, + { + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink" } ], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"id\\": \\"baz\\", - \\"title\\": \\"baz\\", - \\"slug\\": \\"bazSlug.html\\", - \\"pagination_label\\": \\"baz pagination_label\\", - \\"tags\\": [ - \\"tag 1\\", - \\"tag-1\\", + "version": "current", + "frontMatter": { + "id": "baz", + "title": "baz", + "slug": "bazSlug.html", + "pagination_label": "baz pagination_label", + "tags": [ + "tag 1", + "tag-1", { - \\"label\\": \\"tag 2\\", - \\"permalink\\": \\"tag2-custom-permalink\\" + "label": "tag 2", + "permalink": "tag2-custom-permalink" } ] }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"Bar\\", - \\"permalink\\": \\"/docs/foo/bar\\" + "sidebar": "docs", + "previous": { + "title": "Bar", + "permalink": "/docs/foo/bar" }, - \\"next\\": { - \\"title\\": \\"Slugs\\", - \\"permalink\\": \\"/docs/category/slugs\\" + "next": { + "title": "Slugs", + "permalink": "/docs/category/slugs" } }", "site-docs-heading-as-title-md-c6d.json": "{ - \\"unversionedId\\": \\"headingAsTitle\\", - \\"id\\": \\"headingAsTitle\\", - \\"title\\": \\"My heading as title\\", - \\"description\\": \\"\\", - \\"source\\": \\"@site/docs/headingAsTitle.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/headingAsTitle\\", - \\"permalink\\": \\"/docs/headingAsTitle\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": {}, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"rootTryToEscapeSlug\\", - \\"permalink\\": \\"/docs/rootTryToEscapeSlug\\" - }, - \\"next\\": { - \\"title\\": \\"Hello sidebar_label\\", - \\"permalink\\": \\"/docs/\\" + "unversionedId": "headingAsTitle", + "id": "headingAsTitle", + "title": "My heading as title", + "description": "", + "source": "@site/docs/headingAsTitle.md", + "sourceDirName": ".", + "slug": "/headingAsTitle", + "permalink": "/docs/headingAsTitle", + "tags": [], + "version": "current", + "frontMatter": {}, + "sidebar": "docs", + "previous": { + "title": "rootTryToEscapeSlug", + "permalink": "/docs/rootTryToEscapeSlug" + }, + "next": { + "title": "Hello sidebar_label", + "permalink": "/docs/" } }", "site-docs-hello-md-9df.json": "{ - \\"unversionedId\\": \\"hello\\", - \\"id\\": \\"hello\\", - \\"title\\": \\"Hello, World !\\", - \\"description\\": \\"Hi, Endilie here :)\\", - \\"source\\": \\"@site/docs/hello.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/\\", - \\"permalink\\": \\"/docs/\\", - \\"tags\\": [ - { - \\"label\\": \\"tag-1\\", - \\"permalink\\": \\"/docs/tags/tag-1\\" - }, - { - \\"label\\": \\"tag 3\\", - \\"permalink\\": \\"/docs/tags/tag-3\\" + "unversionedId": "hello", + "id": "hello", + "title": "Hello, World !", + "description": "Hi, Endilie here :)", + "source": "@site/docs/hello.md", + "sourceDirName": ".", + "slug": "/", + "permalink": "/docs/", + "tags": [ + { + "label": "tag-1", + "permalink": "/docs/tags/tag-1" + }, + { + "label": "tag 3", + "permalink": "/docs/tags/tag-3" } ], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"id\\": \\"hello\\", - \\"title\\": \\"Hello, World !\\", - \\"sidebar_label\\": \\"Hello sidebar_label\\", - \\"tags\\": [ - \\"tag-1\\", - \\"tag 3\\" + "version": "current", + "frontMatter": { + "id": "hello", + "title": "Hello, World !", + "sidebar_label": "Hello sidebar_label", + "tags": [ + "tag-1", + "tag 3" ], - \\"slug\\": \\"/\\" + "slug": "/" }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"My heading as title\\", - \\"permalink\\": \\"/docs/headingAsTitle\\" + "sidebar": "docs", + "previous": { + "title": "My heading as title", + "permalink": "/docs/headingAsTitle" } }", "site-docs-ipsum-md-c61.json": "{ - \\"unversionedId\\": \\"ipsum\\", - \\"id\\": \\"ipsum\\", - \\"title\\": \\"ipsum\\", - \\"description\\": \\"Lorem ipsum.\\", - \\"source\\": \\"@site/docs/ipsum.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/ipsum\\", - \\"permalink\\": \\"/docs/ipsum\\", - \\"editUrl\\": null, - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"custom_edit_url\\": null + "unversionedId": "ipsum", + "id": "ipsum", + "title": "ipsum", + "description": "Lorem ipsum.", + "source": "@site/docs/ipsum.md", + "sourceDirName": ".", + "slug": "/ipsum", + "permalink": "/docs/ipsum", + "editUrl": null, + "tags": [], + "version": "current", + "frontMatter": { + "custom_edit_url": null } }", "site-docs-lorem-md-b27.json": "{ - \\"unversionedId\\": \\"lorem\\", - \\"id\\": \\"lorem\\", - \\"title\\": \\"lorem\\", - \\"description\\": \\"Lorem ipsum.\\", - \\"source\\": \\"@site/docs/lorem.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/lorem\\", - \\"permalink\\": \\"/docs/lorem\\", - \\"editUrl\\": \\"https://github.com/customUrl/docs/lorem.md\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"custom_edit_url\\": \\"https://github.com/customUrl/docs/lorem.md\\", - \\"unrelated_front_matter\\": \\"won't be part of metadata\\" + "unversionedId": "lorem", + "id": "lorem", + "title": "lorem", + "description": "Lorem ipsum.", + "source": "@site/docs/lorem.md", + "sourceDirName": ".", + "slug": "/lorem", + "permalink": "/docs/lorem", + "editUrl": "https://github.com/customUrl/docs/lorem.md", + "tags": [], + "version": "current", + "frontMatter": { + "custom_edit_url": "https://github.com/customUrl/docs/lorem.md", + "unrelated_front_matter": "won't be part of metadata" } }", "site-docs-root-absolute-slug-md-db5.json": "{ - \\"unversionedId\\": \\"rootAbsoluteSlug\\", - \\"id\\": \\"rootAbsoluteSlug\\", - \\"title\\": \\"rootAbsoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/rootAbsoluteSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootAbsoluteSlug\\", - \\"permalink\\": \\"/docs/rootAbsoluteSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"/rootAbsoluteSlug\\", - \\"pagination_next\\": \\"headingAsTitle\\", - \\"pagination_prev\\": \\"foo/baz\\" - }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"baz pagination_label\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - \\"next\\": { - \\"title\\": \\"My heading as title\\", - \\"permalink\\": \\"/docs/headingAsTitle\\" + "unversionedId": "rootAbsoluteSlug", + "id": "rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + "description": "Lorem", + "source": "@site/docs/rootAbsoluteSlug.md", + "sourceDirName": ".", + "slug": "/rootAbsoluteSlug", + "permalink": "/docs/rootAbsoluteSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "/rootAbsoluteSlug", + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz" + }, + "sidebar": "docs", + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "My heading as title", + "permalink": "/docs/headingAsTitle" } }", "site-docs-root-relative-slug-md-3dd.json": "{ - \\"unversionedId\\": \\"rootRelativeSlug\\", - \\"id\\": \\"rootRelativeSlug\\", - \\"title\\": \\"rootRelativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/rootRelativeSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootRelativeSlug\\", - \\"permalink\\": \\"/docs/rootRelativeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"rootRelativeSlug\\", - \\"pagination_next\\": \\"headingAsTitle\\", - \\"pagination_prev\\": \\"foo/baz\\" - }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"baz pagination_label\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - \\"next\\": { - \\"title\\": \\"My heading as title\\", - \\"permalink\\": \\"/docs/headingAsTitle\\" + "unversionedId": "rootRelativeSlug", + "id": "rootRelativeSlug", + "title": "rootRelativeSlug", + "description": "Lorem", + "source": "@site/docs/rootRelativeSlug.md", + "sourceDirName": ".", + "slug": "/rootRelativeSlug", + "permalink": "/docs/rootRelativeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "rootRelativeSlug", + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz" + }, + "sidebar": "docs", + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "My heading as title", + "permalink": "/docs/headingAsTitle" } }", "site-docs-root-resolved-slug-md-4d1.json": "{ - \\"unversionedId\\": \\"rootResolvedSlug\\", - \\"id\\": \\"rootResolvedSlug\\", - \\"title\\": \\"rootResolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/rootResolvedSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/hey/rootResolvedSlug\\", - \\"permalink\\": \\"/docs/hey/rootResolvedSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"./hey/ho/../rootResolvedSlug\\", - \\"pagination_next\\": \\"headingAsTitle\\", - \\"pagination_prev\\": \\"foo/baz\\" - }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"baz pagination_label\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - \\"next\\": { - \\"title\\": \\"My heading as title\\", - \\"permalink\\": \\"/docs/headingAsTitle\\" + "unversionedId": "rootResolvedSlug", + "id": "rootResolvedSlug", + "title": "rootResolvedSlug", + "description": "Lorem", + "source": "@site/docs/rootResolvedSlug.md", + "sourceDirName": ".", + "slug": "/hey/rootResolvedSlug", + "permalink": "/docs/hey/rootResolvedSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "./hey/ho/../rootResolvedSlug", + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz" + }, + "sidebar": "docs", + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "My heading as title", + "permalink": "/docs/headingAsTitle" } }", "site-docs-root-try-to-escape-slug-md-9ee.json": "{ - \\"unversionedId\\": \\"rootTryToEscapeSlug\\", - \\"id\\": \\"rootTryToEscapeSlug\\", - \\"title\\": \\"rootTryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/rootTryToEscapeSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootTryToEscapeSlug\\", - \\"permalink\\": \\"/docs/rootTryToEscapeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\", - \\"pagination_next\\": \\"headingAsTitle\\", - \\"pagination_prev\\": \\"foo/baz\\" - }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"baz pagination_label\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - \\"next\\": { - \\"title\\": \\"My heading as title\\", - \\"permalink\\": \\"/docs/headingAsTitle\\" + "unversionedId": "rootTryToEscapeSlug", + "id": "rootTryToEscapeSlug", + "title": "rootTryToEscapeSlug", + "description": "Lorem", + "source": "@site/docs/rootTryToEscapeSlug.md", + "sourceDirName": ".", + "slug": "/rootTryToEscapeSlug", + "permalink": "/docs/rootTryToEscapeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "../../../../../../../../rootTryToEscapeSlug", + "pagination_next": "headingAsTitle", + "pagination_prev": "foo/baz" + }, + "sidebar": "docs", + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "My heading as title", + "permalink": "/docs/headingAsTitle" } }", "site-docs-slugs-absolute-slug-md-4e8.json": "{ - \\"unversionedId\\": \\"slugs/absoluteSlug\\", - \\"id\\": \\"slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/absoluteSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/absoluteSlug\\", - \\"permalink\\": \\"/docs/absoluteSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"/absoluteSlug\\" + "unversionedId": "slugs/absoluteSlug", + "id": "slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem", + "source": "@site/docs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "slug": "/absoluteSlug", + "permalink": "/docs/absoluteSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "/absoluteSlug" } }", "site-docs-slugs-relative-slug-md-d1c.json": "{ - \\"unversionedId\\": \\"slugs/relativeSlug\\", - \\"id\\": \\"slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/relativeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/relativeSlug\\", - \\"permalink\\": \\"/docs/slugs/relativeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"relativeSlug\\" + "unversionedId": "slugs/relativeSlug", + "id": "slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem", + "source": "@site/docs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/relativeSlug", + "permalink": "/docs/slugs/relativeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "relativeSlug" } }", "site-docs-slugs-resolved-slug-md-02b.json": "{ - \\"unversionedId\\": \\"slugs/resolvedSlug\\", - \\"id\\": \\"slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/resolvedSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/hey/resolvedSlug\\", - \\"permalink\\": \\"/docs/slugs/hey/resolvedSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"./hey/ho/../resolvedSlug\\" + "unversionedId": "slugs/resolvedSlug", + "id": "slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem", + "source": "@site/docs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/hey/resolvedSlug", + "permalink": "/docs/slugs/hey/resolvedSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug" } }", "site-docs-slugs-try-to-escape-slug-md-70d.json": "{ - \\"unversionedId\\": \\"slugs/tryToEscapeSlug\\", - \\"id\\": \\"slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/tryToEscapeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/tryToEscapeSlug\\", - \\"permalink\\": \\"/docs/tryToEscapeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\" + "unversionedId": "slugs/tryToEscapeSlug", + "id": "slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem", + "source": "@site/docs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "slug": "/tryToEscapeSlug", + "permalink": "/docs/tryToEscapeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug" } }", "tag-docs-tags-tag-1-b3f.json": "{ - \\"label\\": \\"tag 1\\", - \\"permalink\\": \\"/docs/tags/tag-1\\", - \\"allTagsPath\\": \\"/docs/tags\\", - \\"count\\": 2, - \\"items\\": [ - { - \\"id\\": \\"foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Images\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" - }, - { - \\"id\\": \\"hello\\", - \\"title\\": \\"Hello, World !\\", - \\"description\\": \\"Hi, Endilie here :)\\", - \\"permalink\\": \\"/docs/\\" + "label": "tag 1", + "permalink": "/docs/tags/tag-1", + "allTagsPath": "/docs/tags", + "count": 2, + "items": [ + { + "id": "foo/baz", + "title": "baz", + "description": "Images", + "permalink": "/docs/foo/bazSlug.html" + }, + { + "id": "hello", + "title": "Hello, World !", + "description": "Hi, Endilie here :)", + "permalink": "/docs/" } ] }", "tag-docs-tags-tag-2-custom-permalink-825.json": "{ - \\"label\\": \\"tag 2\\", - \\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\", - \\"allTagsPath\\": \\"/docs/tags\\", - \\"count\\": 1, - \\"items\\": [ - { - \\"id\\": \\"foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Images\\", - \\"permalink\\": \\"/docs/foo/bazSlug.html\\" + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink", + "allTagsPath": "/docs/tags", + "count": 1, + "items": [ + { + "id": "foo/baz", + "title": "baz", + "description": "Images", + "permalink": "/docs/foo/bazSlug.html" } ] }", "tag-docs-tags-tag-3-ab5.json": "{ - \\"label\\": \\"tag 3\\", - \\"permalink\\": \\"/docs/tags/tag-3\\", - \\"allTagsPath\\": \\"/docs/tags\\", - \\"count\\": 1, - \\"items\\": [ - { - \\"id\\": \\"hello\\", - \\"title\\": \\"Hello, World !\\", - \\"description\\": \\"Hi, Endilie here :)\\", - \\"permalink\\": \\"/docs/\\" + "label": "tag 3", + "permalink": "/docs/tags/tag-3", + "allTagsPath": "/docs/tags", + "count": 1, + "items": [ + { + "id": "hello", + "title": "Hello, World !", + "description": "Hi, Endilie here :)", + "permalink": "/docs/" } ] }", "tags-list-current-prop-15a.json": "[ { - \\"label\\": \\"tag 1\\", - \\"permalink\\": \\"/docs/tags/tag-1\\", - \\"count\\": 2 + "label": "tag 1", + "permalink": "/docs/tags/tag-1", + "count": 2 }, { - \\"label\\": \\"tag 2\\", - \\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\", - \\"count\\": 1 + "label": "tag 2", + "permalink": "/docs/tags/tag2-custom-permalink", + "count": 1 }, { - \\"label\\": \\"tag 3\\", - \\"permalink\\": \\"/docs/tags/tag-3\\", - \\"count\\": 1 + "label": "tag 3", + "permalink": "/docs/tags/tag-3", + "count": 1 } ]", "version-current-metadata-prop-751.json": "{ - \\"pluginId\\": \\"default\\", - \\"version\\": \\"current\\", - \\"label\\": \\"Next\\", - \\"banner\\": null, - \\"badge\\": false, - \\"className\\": \\"docs-version-current\\", - \\"isLast\\": true, - \\"docsSidebars\\": { - \\"docs\\": [ + "pluginId": "default", + "version": "current", + "label": "Next", + "banner": null, + "badge": false, + "className": "docs-version-current", + "isLast": true, + "docsSidebars": { + "docs": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"Test\\", - \\"items\\": [ + "type": "category", + "label": "Test", + "items": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"foo\\", - \\"items\\": [ + "type": "category", + "label": "foo", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"Bar\\", - \\"href\\": \\"/docs/foo/bar\\", - \\"docId\\": \\"foo/bar\\" + "type": "link", + "label": "Bar", + "href": "/docs/foo/bar", + "docId": "foo/bar" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"baz\\", - \\"href\\": \\"/docs/foo/bazSlug.html\\", - \\"docId\\": \\"foo/baz\\" + "type": "link", + "label": "baz", + "href": "/docs/foo/bazSlug.html", + "docId": "foo/baz" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true }, { - \\"type\\": \\"category\\", - \\"label\\": \\"Slugs\\", - \\"items\\": [ + "type": "category", + "label": "Slugs", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"rootAbsoluteSlug\\", - \\"href\\": \\"/docs/rootAbsoluteSlug\\", - \\"docId\\": \\"rootAbsoluteSlug\\" + "type": "link", + "label": "rootAbsoluteSlug", + "href": "/docs/rootAbsoluteSlug", + "docId": "rootAbsoluteSlug" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"rootRelativeSlug\\", - \\"href\\": \\"/docs/rootRelativeSlug\\", - \\"docId\\": \\"rootRelativeSlug\\" + "type": "link", + "label": "rootRelativeSlug", + "href": "/docs/rootRelativeSlug", + "docId": "rootRelativeSlug" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"rootResolvedSlug\\", - \\"href\\": \\"/docs/hey/rootResolvedSlug\\", - \\"docId\\": \\"rootResolvedSlug\\" + "type": "link", + "label": "rootResolvedSlug", + "href": "/docs/hey/rootResolvedSlug", + "docId": "rootResolvedSlug" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"rootTryToEscapeSlug\\", - \\"href\\": \\"/docs/rootTryToEscapeSlug\\", - \\"docId\\": \\"rootTryToEscapeSlug\\" + "type": "link", + "label": "rootTryToEscapeSlug", + "href": "/docs/rootTryToEscapeSlug", + "docId": "rootTryToEscapeSlug" } ], - \\"collapsed\\": true, - \\"collapsible\\": true, - \\"href\\": \\"/docs/category/slugs\\" + "collapsed": true, + "collapsible": true, + "href": "/docs/category/slugs" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"My heading as title\\", - \\"href\\": \\"/docs/headingAsTitle\\", - \\"docId\\": \\"headingAsTitle\\" + "type": "link", + "label": "My heading as title", + "href": "/docs/headingAsTitle", + "docId": "headingAsTitle" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"GitHub\\", - \\"href\\": \\"https://github.com\\" + "type": "link", + "label": "GitHub", + "href": "https://github.com" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"Hello sidebar_label\\", - \\"href\\": \\"/docs/\\", - \\"docId\\": \\"hello\\" + "type": "link", + "label": "Hello sidebar_label", + "href": "/docs/", + "docId": "hello" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true }, { - \\"type\\": \\"category\\", - \\"label\\": \\"Guides\\", - \\"items\\": [ + "type": "category", + "label": "Guides", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"Hello sidebar_label\\", - \\"href\\": \\"/docs/\\", - \\"docId\\": \\"hello\\" + "type": "link", + "label": "Hello sidebar_label", + "href": "/docs/", + "docId": "hello" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true } ] }, - \\"docs\\": { - \\"doc with space\\": { - \\"id\\": \\"doc with space\\", - \\"title\\": \\"Hoo hoo, if this path tricks you...\\", - \\"description\\": \\"\\" - }, - \\"foo/bar\\": { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"Bar\\", - \\"description\\": \\"This is custom description\\", - \\"sidebar\\": \\"docs\\" - }, - \\"foo/baz\\": { - \\"id\\": \\"foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Images\\", - \\"sidebar\\": \\"docs\\" - }, - \\"headingAsTitle\\": { - \\"id\\": \\"headingAsTitle\\", - \\"title\\": \\"My heading as title\\", - \\"description\\": \\"\\", - \\"sidebar\\": \\"docs\\" - }, - \\"hello\\": { - \\"id\\": \\"hello\\", - \\"title\\": \\"Hello, World !\\", - \\"description\\": \\"Hi, Endilie here :)\\", - \\"sidebar\\": \\"docs\\" - }, - \\"ipsum\\": { - \\"id\\": \\"ipsum\\", - \\"title\\": \\"ipsum\\", - \\"description\\": \\"Lorem ipsum.\\" - }, - \\"lorem\\": { - \\"id\\": \\"lorem\\", - \\"title\\": \\"lorem\\", - \\"description\\": \\"Lorem ipsum.\\" - }, - \\"rootAbsoluteSlug\\": { - \\"id\\": \\"rootAbsoluteSlug\\", - \\"title\\": \\"rootAbsoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"sidebar\\": \\"docs\\" - }, - \\"rootRelativeSlug\\": { - \\"id\\": \\"rootRelativeSlug\\", - \\"title\\": \\"rootRelativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"sidebar\\": \\"docs\\" - }, - \\"rootResolvedSlug\\": { - \\"id\\": \\"rootResolvedSlug\\", - \\"title\\": \\"rootResolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"sidebar\\": \\"docs\\" - }, - \\"rootTryToEscapeSlug\\": { - \\"id\\": \\"rootTryToEscapeSlug\\", - \\"title\\": \\"rootTryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"sidebar\\": \\"docs\\" - }, - \\"slugs/absoluteSlug\\": { - \\"id\\": \\"slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/relativeSlug\\": { - \\"id\\": \\"slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/resolvedSlug\\": { - \\"id\\": \\"slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/tryToEscapeSlug\\": { - \\"id\\": \\"slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\" + "docs": { + "doc with space": { + "id": "doc with space", + "title": "Hoo hoo, if this path tricks you...", + "description": "" + }, + "foo/bar": { + "id": "foo/bar", + "title": "Bar", + "description": "This is custom description", + "sidebar": "docs" + }, + "foo/baz": { + "id": "foo/baz", + "title": "baz", + "description": "Images", + "sidebar": "docs" + }, + "headingAsTitle": { + "id": "headingAsTitle", + "title": "My heading as title", + "description": "", + "sidebar": "docs" + }, + "hello": { + "id": "hello", + "title": "Hello, World !", + "description": "Hi, Endilie here :)", + "sidebar": "docs" + }, + "ipsum": { + "id": "ipsum", + "title": "ipsum", + "description": "Lorem ipsum." + }, + "lorem": { + "id": "lorem", + "title": "lorem", + "description": "Lorem ipsum." + }, + "rootAbsoluteSlug": { + "id": "rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + "description": "Lorem", + "sidebar": "docs" + }, + "rootRelativeSlug": { + "id": "rootRelativeSlug", + "title": "rootRelativeSlug", + "description": "Lorem", + "sidebar": "docs" + }, + "rootResolvedSlug": { + "id": "rootResolvedSlug", + "title": "rootResolvedSlug", + "description": "Lorem", + "sidebar": "docs" + }, + "rootTryToEscapeSlug": { + "id": "rootTryToEscapeSlug", + "title": "rootTryToEscapeSlug", + "description": "Lorem", + "sidebar": "docs" + }, + "slugs/absoluteSlug": { + "id": "slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem" + }, + "slugs/relativeSlug": { + "id": "slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem" + }, + "slugs/resolvedSlug": { + "id": "slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem" + }, + "slugs/tryToEscapeSlug": { + "id": "slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem" } } }", @@ -2361,86 +2361,86 @@ exports[`versioned website (community) content: current version sidebars 1`] = ` exports[`versioned website (community) content: data 1`] = ` { "site-community-versioned-docs-version-1-0-0-team-md-359.json": "{ - \\"unversionedId\\": \\"team\\", - \\"id\\": \\"version-1.0.0/team\\", - \\"title\\": \\"team\\", - \\"description\\": \\"Team 1.0.0\\", - \\"source\\": \\"@site/community_versioned_docs/version-1.0.0/team.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/team\\", - \\"permalink\\": \\"/community/team\\", - \\"tags\\": [], - \\"version\\": \\"1.0.0\\", - \\"frontMatter\\": {}, - \\"sidebar\\": \\"version-1.0.0/community\\" + "unversionedId": "team", + "id": "version-1.0.0/team", + "title": "team", + "description": "Team 1.0.0", + "source": "@site/community_versioned_docs/version-1.0.0/team.md", + "sourceDirName": ".", + "slug": "/team", + "permalink": "/community/team", + "tags": [], + "version": "1.0.0", + "frontMatter": {}, + "sidebar": "version-1.0.0/community" }", "site-i-18-n-en-docusaurus-plugin-content-docs-community-current-team-md-7e5.json": "{ - \\"unversionedId\\": \\"team\\", - \\"id\\": \\"team\\", - \\"title\\": \\"Team title translated\\", - \\"description\\": \\"Team current version (translated)\\", - \\"source\\": \\"@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/team\\", - \\"permalink\\": \\"/community/next/team\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"title\\": \\"Team title translated\\" - }, - \\"sidebar\\": \\"community\\" + "unversionedId": "team", + "id": "team", + "title": "Team title translated", + "description": "Team current version (translated)", + "source": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", + "sourceDirName": ".", + "slug": "/team", + "permalink": "/community/next/team", + "tags": [], + "version": "current", + "frontMatter": { + "title": "Team title translated" + }, + "sidebar": "community" }", "version-1-0-0-metadata-prop-608.json": "{ - \\"pluginId\\": \\"community\\", - \\"version\\": \\"1.0.0\\", - \\"label\\": \\"1.0.0\\", - \\"banner\\": null, - \\"badge\\": true, - \\"className\\": \\"docs-version-1.0.0\\", - \\"isLast\\": true, - \\"docsSidebars\\": { - \\"version-1.0.0/community\\": [ + "pluginId": "community", + "version": "1.0.0", + "label": "1.0.0", + "banner": null, + "badge": true, + "className": "docs-version-1.0.0", + "isLast": true, + "docsSidebars": { + "version-1.0.0/community": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"team\\", - \\"href\\": \\"/community/team\\", - \\"docId\\": \\"team\\" + "type": "link", + "label": "team", + "href": "/community/team", + "docId": "team" } ] }, - \\"docs\\": { - \\"team\\": { - \\"id\\": \\"team\\", - \\"title\\": \\"team\\", - \\"description\\": \\"Team 1.0.0\\", - \\"sidebar\\": \\"version-1.0.0/community\\" + "docs": { + "team": { + "id": "team", + "title": "team", + "description": "Team 1.0.0", + "sidebar": "version-1.0.0/community" } } }", "version-current-metadata-prop-751.json": "{ - \\"pluginId\\": \\"community\\", - \\"version\\": \\"current\\", - \\"label\\": \\"Next\\", - \\"banner\\": \\"unreleased\\", - \\"badge\\": true, - \\"className\\": \\"docs-version-current\\", - \\"isLast\\": false, - \\"docsSidebars\\": { - \\"community\\": [ + "pluginId": "community", + "version": "current", + "label": "Next", + "banner": "unreleased", + "badge": true, + "className": "docs-version-current", + "isLast": false, + "docsSidebars": { + "community": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"Team title translated\\", - \\"href\\": \\"/community/next/team\\", - \\"docId\\": \\"team\\" + "type": "link", + "label": "Team title translated", + "href": "/community/next/team", + "docId": "team" } ] }, - \\"docs\\": { - \\"team\\": { - \\"id\\": \\"team\\", - \\"title\\": \\"Team title translated\\", - \\"description\\": \\"Team current version (translated)\\", - \\"sidebar\\": \\"community\\" + "docs": { + "team": { + "id": "team", + "title": "Team title translated", + "description": "Team current version (translated)", + "sidebar": "community" } } }", @@ -2833,670 +2833,670 @@ exports[`versioned website content: current version sidebars 1`] = ` exports[`versioned website content: data 1`] = ` { "site-docs-foo-bar-md-8c2.json": "{ - \\"unversionedId\\": \\"foo/bar\\", - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"This is next version of bar.\\", - \\"source\\": \\"@site/docs/foo/bar.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/barSlug\\", - \\"permalink\\": \\"/docs/next/foo/barSlug\\", - \\"tags\\": [ + "unversionedId": "foo/bar", + "id": "foo/bar", + "title": "bar", + "description": "This is next version of bar.", + "source": "@site/docs/foo/bar.md", + "sourceDirName": "foo", + "slug": "/foo/barSlug", + "permalink": "/docs/next/foo/barSlug", + "tags": [ { - \\"label\\": \\"barTag 1\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-1\\" + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1" }, { - \\"label\\": \\"barTag-2\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-2\\" + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2" }, { - \\"label\\": \\"barTag 3\\", - \\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\" + "label": "barTag 3", + "permalink": "/docs/next/tags/barTag-3-permalink" } ], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"barSlug\\", - \\"tags\\": [ - \\"barTag 1\\", - \\"barTag-2\\", + "version": "current", + "frontMatter": { + "slug": "barSlug", + "tags": [ + "barTag 1", + "barTag-2", { - \\"label\\": \\"barTag 3\\", - \\"permalink\\": \\"barTag-3-permalink\\" + "label": "barTag 3", + "permalink": "barTag-3-permalink" } ] }, - \\"sidebar\\": \\"docs\\", - \\"next\\": { - \\"title\\": \\"hello\\", - \\"permalink\\": \\"/docs/next/\\" + "sidebar": "docs", + "next": { + "title": "hello", + "permalink": "/docs/next/" } }", "site-docs-hello-md-9df.json": "{ - \\"unversionedId\\": \\"hello\\", - \\"id\\": \\"hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello next !\\", - \\"source\\": \\"@site/docs/hello.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/\\", - \\"permalink\\": \\"/docs/next/\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"/\\" - }, - \\"sidebar\\": \\"docs\\", - \\"previous\\": { - \\"title\\": \\"bar\\", - \\"permalink\\": \\"/docs/next/foo/barSlug\\" + "unversionedId": "hello", + "id": "hello", + "title": "hello", + "description": "Hello next !", + "source": "@site/docs/hello.md", + "sourceDirName": ".", + "slug": "/", + "permalink": "/docs/next/", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "/" + }, + "sidebar": "docs", + "previous": { + "title": "bar", + "permalink": "/docs/next/foo/barSlug" } }", "site-docs-slugs-absolute-slug-md-4e8.json": "{ - \\"unversionedId\\": \\"slugs/absoluteSlug\\", - \\"id\\": \\"slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/absoluteSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/absoluteSlug\\", - \\"permalink\\": \\"/docs/next/absoluteSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"/absoluteSlug\\" + "unversionedId": "slugs/absoluteSlug", + "id": "slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem", + "source": "@site/docs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "slug": "/absoluteSlug", + "permalink": "/docs/next/absoluteSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "/absoluteSlug" } }", "site-docs-slugs-relative-slug-md-d1c.json": "{ - \\"unversionedId\\": \\"slugs/relativeSlug\\", - \\"id\\": \\"slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/relativeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/relativeSlug\\", - \\"permalink\\": \\"/docs/next/slugs/relativeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"relativeSlug\\" + "unversionedId": "slugs/relativeSlug", + "id": "slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem", + "source": "@site/docs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/relativeSlug", + "permalink": "/docs/next/slugs/relativeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "relativeSlug" } }", "site-docs-slugs-resolved-slug-md-02b.json": "{ - \\"unversionedId\\": \\"slugs/resolvedSlug\\", - \\"id\\": \\"slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/resolvedSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/hey/resolvedSlug\\", - \\"permalink\\": \\"/docs/next/slugs/hey/resolvedSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"./hey/ho/../resolvedSlug\\" + "unversionedId": "slugs/resolvedSlug", + "id": "slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem", + "source": "@site/docs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/hey/resolvedSlug", + "permalink": "/docs/next/slugs/hey/resolvedSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug" } }", "site-docs-slugs-try-to-escape-slug-md-70d.json": "{ - \\"unversionedId\\": \\"slugs/tryToEscapeSlug\\", - \\"id\\": \\"slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/docs/slugs/tryToEscapeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/tryToEscapeSlug\\", - \\"permalink\\": \\"/docs/next/tryToEscapeSlug\\", - \\"tags\\": [], - \\"version\\": \\"current\\", - \\"frontMatter\\": { - \\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\" + "unversionedId": "slugs/tryToEscapeSlug", + "id": "slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem", + "source": "@site/docs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "slug": "/tryToEscapeSlug", + "permalink": "/docs/next/tryToEscapeSlug", + "tags": [], + "version": "current", + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug" } }", "site-i-18-n-en-docusaurus-plugin-content-docs-version-1-0-0-hello-md-fe5.json": "{ - \\"unversionedId\\": \\"hello\\", - \\"id\\": \\"version-1.0.0/hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello 1.0.0 ! (translated en)\\", - \\"source\\": \\"@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/\\", - \\"permalink\\": \\"/docs/1.0.0/\\", - \\"tags\\": [], - \\"version\\": \\"1.0.0\\", - \\"frontMatter\\": { - \\"slug\\": \\"/\\" - }, - \\"sidebar\\": \\"version-1.0.0/docs\\", - \\"previous\\": { - \\"title\\": \\"baz\\", - \\"permalink\\": \\"/docs/1.0.0/foo/baz\\" + "unversionedId": "hello", + "id": "version-1.0.0/hello", + "title": "hello", + "description": "Hello 1.0.0 ! (translated en)", + "source": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", + "sourceDirName": ".", + "slug": "/", + "permalink": "/docs/1.0.0/", + "tags": [], + "version": "1.0.0", + "frontMatter": { + "slug": "/" + }, + "sidebar": "version-1.0.0/docs", + "previous": { + "title": "baz", + "permalink": "/docs/1.0.0/foo/baz" } }", "site-versioned-docs-version-1-0-0-foo-bar-md-7a6.json": "{ - \\"unversionedId\\": \\"foo/bar\\", - \\"id\\": \\"version-1.0.0/foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"Bar 1.0.0 !\\", - \\"source\\": \\"@site/versioned_docs/version-1.0.0/foo/bar.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/barSlug\\", - \\"permalink\\": \\"/docs/1.0.0/foo/barSlug\\", - \\"tags\\": [], - \\"version\\": \\"1.0.0\\", - \\"frontMatter\\": { - \\"slug\\": \\"barSlug\\" - }, - \\"sidebar\\": \\"version-1.0.0/docs\\", - \\"next\\": { - \\"title\\": \\"baz\\", - \\"permalink\\": \\"/docs/1.0.0/foo/baz\\" + "unversionedId": "foo/bar", + "id": "version-1.0.0/foo/bar", + "title": "bar", + "description": "Bar 1.0.0 !", + "source": "@site/versioned_docs/version-1.0.0/foo/bar.md", + "sourceDirName": "foo", + "slug": "/foo/barSlug", + "permalink": "/docs/1.0.0/foo/barSlug", + "tags": [], + "version": "1.0.0", + "frontMatter": { + "slug": "barSlug" + }, + "sidebar": "version-1.0.0/docs", + "next": { + "title": "baz", + "permalink": "/docs/1.0.0/foo/baz" } }", "site-versioned-docs-version-1-0-0-foo-baz-md-883.json": "{ - \\"unversionedId\\": \\"foo/baz\\", - \\"id\\": \\"version-1.0.0/foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Baz 1.0.0 ! This will be deleted in next subsequent versions.\\", - \\"source\\": \\"@site/versioned_docs/version-1.0.0/foo/baz.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/baz\\", - \\"permalink\\": \\"/docs/1.0.0/foo/baz\\", - \\"tags\\": [], - \\"version\\": \\"1.0.0\\", - \\"frontMatter\\": {}, - \\"sidebar\\": \\"version-1.0.0/docs\\", - \\"previous\\": { - \\"title\\": \\"bar\\", - \\"permalink\\": \\"/docs/1.0.0/foo/barSlug\\" - }, - \\"next\\": { - \\"title\\": \\"hello\\", - \\"permalink\\": \\"/docs/1.0.0/\\" + "unversionedId": "foo/baz", + "id": "version-1.0.0/foo/baz", + "title": "baz", + "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", + "source": "@site/versioned_docs/version-1.0.0/foo/baz.md", + "sourceDirName": "foo", + "slug": "/foo/baz", + "permalink": "/docs/1.0.0/foo/baz", + "tags": [], + "version": "1.0.0", + "frontMatter": {}, + "sidebar": "version-1.0.0/docs", + "previous": { + "title": "bar", + "permalink": "/docs/1.0.0/foo/barSlug" + }, + "next": { + "title": "hello", + "permalink": "/docs/1.0.0/" } }", "site-versioned-docs-version-1-0-1-foo-bar-md-7a3.json": "{ - \\"unversionedId\\": \\"foo/bar\\", - \\"id\\": \\"version-1.0.1/foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"Bar 1.0.1 !\\", - \\"source\\": \\"@site/versioned_docs/version-1.0.1/foo/bar.md\\", - \\"sourceDirName\\": \\"foo\\", - \\"slug\\": \\"/foo/bar\\", - \\"permalink\\": \\"/docs/foo/bar\\", - \\"tags\\": [], - \\"version\\": \\"1.0.1\\", - \\"frontMatter\\": {}, - \\"sidebar\\": \\"VersionedSideBarNameDoesNotMatter/docs\\", - \\"next\\": { - \\"title\\": \\"hello\\", - \\"permalink\\": \\"/docs/\\" + "unversionedId": "foo/bar", + "id": "version-1.0.1/foo/bar", + "title": "bar", + "description": "Bar 1.0.1 !", + "source": "@site/versioned_docs/version-1.0.1/foo/bar.md", + "sourceDirName": "foo", + "slug": "/foo/bar", + "permalink": "/docs/foo/bar", + "tags": [], + "version": "1.0.1", + "frontMatter": {}, + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "next": { + "title": "hello", + "permalink": "/docs/" } }", "site-versioned-docs-version-1-0-1-hello-md-0c7.json": "{ - \\"unversionedId\\": \\"hello\\", - \\"id\\": \\"version-1.0.1/hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello 1.0.1 !\\", - \\"source\\": \\"@site/versioned_docs/version-1.0.1/hello.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/\\", - \\"permalink\\": \\"/docs/\\", - \\"tags\\": [], - \\"version\\": \\"1.0.1\\", - \\"frontMatter\\": { - \\"slug\\": \\"/\\" - }, - \\"sidebar\\": \\"VersionedSideBarNameDoesNotMatter/docs\\", - \\"previous\\": { - \\"title\\": \\"bar\\", - \\"permalink\\": \\"/docs/foo/bar\\" + "unversionedId": "hello", + "id": "version-1.0.1/hello", + "title": "hello", + "description": "Hello 1.0.1 !", + "source": "@site/versioned_docs/version-1.0.1/hello.md", + "sourceDirName": ".", + "slug": "/", + "permalink": "/docs/", + "tags": [], + "version": "1.0.1", + "frontMatter": { + "slug": "/" + }, + "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "previous": { + "title": "bar", + "permalink": "/docs/foo/bar" } }", "site-versioned-docs-version-with-slugs-root-absolute-slug-md-4d2.json": "{ - \\"unversionedId\\": \\"rootAbsoluteSlug\\", - \\"id\\": \\"version-withSlugs/rootAbsoluteSlug\\", - \\"title\\": \\"rootAbsoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootAbsoluteSlug\\", - \\"permalink\\": \\"/docs/withSlugs/rootAbsoluteSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"/rootAbsoluteSlug\\" - }, - \\"sidebar\\": \\"version-1.0.1/docs\\" + "unversionedId": "rootAbsoluteSlug", + "id": "version-withSlugs/rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", + "sourceDirName": ".", + "slug": "/rootAbsoluteSlug", + "permalink": "/docs/withSlugs/rootAbsoluteSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "/rootAbsoluteSlug" + }, + "sidebar": "version-1.0.1/docs" }", "site-versioned-docs-version-with-slugs-root-relative-slug-md-32a.json": "{ - \\"unversionedId\\": \\"rootRelativeSlug\\", - \\"id\\": \\"version-withSlugs/rootRelativeSlug\\", - \\"title\\": \\"rootRelativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/rootRelativeSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootRelativeSlug\\", - \\"permalink\\": \\"/docs/withSlugs/rootRelativeSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"rootRelativeSlug\\" + "unversionedId": "rootRelativeSlug", + "id": "version-withSlugs/rootRelativeSlug", + "title": "rootRelativeSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md", + "sourceDirName": ".", + "slug": "/rootRelativeSlug", + "permalink": "/docs/withSlugs/rootRelativeSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "rootRelativeSlug" } }", "site-versioned-docs-version-with-slugs-root-resolved-slug-md-aee.json": "{ - \\"unversionedId\\": \\"rootResolvedSlug\\", - \\"id\\": \\"version-withSlugs/rootResolvedSlug\\", - \\"title\\": \\"rootResolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/rootResolvedSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/hey/rootResolvedSlug\\", - \\"permalink\\": \\"/docs/withSlugs/hey/rootResolvedSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"./hey/ho/../rootResolvedSlug\\" + "unversionedId": "rootResolvedSlug", + "id": "version-withSlugs/rootResolvedSlug", + "title": "rootResolvedSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md", + "sourceDirName": ".", + "slug": "/hey/rootResolvedSlug", + "permalink": "/docs/withSlugs/hey/rootResolvedSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "./hey/ho/../rootResolvedSlug" } }", "site-versioned-docs-version-with-slugs-root-try-to-escape-slug-md-b5d.json": "{ - \\"unversionedId\\": \\"rootTryToEscapeSlug\\", - \\"id\\": \\"version-withSlugs/rootTryToEscapeSlug\\", - \\"title\\": \\"rootTryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md\\", - \\"sourceDirName\\": \\".\\", - \\"slug\\": \\"/rootTryToEscapeSlug\\", - \\"permalink\\": \\"/docs/withSlugs/rootTryToEscapeSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\" + "unversionedId": "rootTryToEscapeSlug", + "id": "version-withSlugs/rootTryToEscapeSlug", + "title": "rootTryToEscapeSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md", + "sourceDirName": ".", + "slug": "/rootTryToEscapeSlug", + "permalink": "/docs/withSlugs/rootTryToEscapeSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "../../../../../../../../rootTryToEscapeSlug" } }", "site-versioned-docs-version-with-slugs-slugs-absolute-slug-md-47a.json": "{ - \\"unversionedId\\": \\"slugs/absoluteSlug\\", - \\"id\\": \\"version-withSlugs/slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/absoluteSlug\\", - \\"permalink\\": \\"/docs/withSlugs/absoluteSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"/absoluteSlug\\" + "unversionedId": "slugs/absoluteSlug", + "id": "version-withSlugs/slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md", + "sourceDirName": "slugs", + "slug": "/absoluteSlug", + "permalink": "/docs/withSlugs/absoluteSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "/absoluteSlug" } }", "site-versioned-docs-version-with-slugs-slugs-relative-slug-md-a95.json": "{ - \\"unversionedId\\": \\"slugs/relativeSlug\\", - \\"id\\": \\"version-withSlugs/slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/relativeSlug\\", - \\"permalink\\": \\"/docs/withSlugs/slugs/relativeSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"relativeSlug\\" + "unversionedId": "slugs/relativeSlug", + "id": "version-withSlugs/slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/relativeSlug", + "permalink": "/docs/withSlugs/slugs/relativeSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "relativeSlug" } }", "site-versioned-docs-version-with-slugs-slugs-resolved-slug-md-5a1.json": "{ - \\"unversionedId\\": \\"slugs/resolvedSlug\\", - \\"id\\": \\"version-withSlugs/slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/slugs/hey/resolvedSlug\\", - \\"permalink\\": \\"/docs/withSlugs/slugs/hey/resolvedSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"./hey/ho/../resolvedSlug\\" + "unversionedId": "slugs/resolvedSlug", + "id": "version-withSlugs/slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md", + "sourceDirName": "slugs", + "slug": "/slugs/hey/resolvedSlug", + "permalink": "/docs/withSlugs/slugs/hey/resolvedSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "./hey/ho/../resolvedSlug" } }", "site-versioned-docs-version-with-slugs-slugs-try-to-escape-slug-md-4e1.json": "{ - \\"unversionedId\\": \\"slugs/tryToEscapeSlug\\", - \\"id\\": \\"version-withSlugs/slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\", - \\"source\\": \\"@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md\\", - \\"sourceDirName\\": \\"slugs\\", - \\"slug\\": \\"/tryToEscapeSlug\\", - \\"permalink\\": \\"/docs/withSlugs/tryToEscapeSlug\\", - \\"tags\\": [], - \\"version\\": \\"withSlugs\\", - \\"frontMatter\\": { - \\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\" + "unversionedId": "slugs/tryToEscapeSlug", + "id": "version-withSlugs/slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem", + "source": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md", + "sourceDirName": "slugs", + "slug": "/tryToEscapeSlug", + "permalink": "/docs/withSlugs/tryToEscapeSlug", + "tags": [], + "version": "withSlugs", + "frontMatter": { + "slug": "../../../../../../../../tryToEscapeSlug" } }", "tag-docs-next-tags-bar-tag-1-a8f.json": "{ - \\"label\\": \\"barTag 1\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-1\\", - \\"allTagsPath\\": \\"/docs/next/tags\\", - \\"count\\": 1, - \\"items\\": [ - { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"This is next version of bar.\\", - \\"permalink\\": \\"/docs/next/foo/barSlug\\" + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1", + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "id": "foo/bar", + "title": "bar", + "description": "This is next version of bar.", + "permalink": "/docs/next/foo/barSlug" } ] }", "tag-docs-next-tags-bar-tag-2-216.json": "{ - \\"label\\": \\"barTag-2\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-2\\", - \\"allTagsPath\\": \\"/docs/next/tags\\", - \\"count\\": 1, - \\"items\\": [ - { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"This is next version of bar.\\", - \\"permalink\\": \\"/docs/next/foo/barSlug\\" + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2", + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "id": "foo/bar", + "title": "bar", + "description": "This is next version of bar.", + "permalink": "/docs/next/foo/barSlug" } ] }", "tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{ - \\"label\\": \\"barTag 3\\", - \\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\", - \\"allTagsPath\\": \\"/docs/next/tags\\", - \\"count\\": 1, - \\"items\\": [ - { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"This is next version of bar.\\", - \\"permalink\\": \\"/docs/next/foo/barSlug\\" + "label": "barTag 3", + "permalink": "/docs/next/tags/barTag-3-permalink", + "allTagsPath": "/docs/next/tags", + "count": 1, + "items": [ + { + "id": "foo/bar", + "title": "bar", + "description": "This is next version of bar.", + "permalink": "/docs/next/foo/barSlug" } ] }", "tags-list-current-prop-15a.json": "[ { - \\"label\\": \\"barTag 1\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-1\\", - \\"count\\": 1 + "label": "barTag 1", + "permalink": "/docs/next/tags/bar-tag-1", + "count": 1 }, { - \\"label\\": \\"barTag-2\\", - \\"permalink\\": \\"/docs/next/tags/bar-tag-2\\", - \\"count\\": 1 + "label": "barTag-2", + "permalink": "/docs/next/tags/bar-tag-2", + "count": 1 }, { - \\"label\\": \\"barTag 3\\", - \\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\", - \\"count\\": 1 + "label": "barTag 3", + "permalink": "/docs/next/tags/barTag-3-permalink", + "count": 1 } ]", "version-1-0-0-metadata-prop-608.json": "{ - \\"pluginId\\": \\"default\\", - \\"version\\": \\"1.0.0\\", - \\"label\\": \\"1.0.0\\", - \\"banner\\": \\"unmaintained\\", - \\"badge\\": true, - \\"className\\": \\"docs-version-1.0.0\\", - \\"isLast\\": false, - \\"docsSidebars\\": { - \\"version-1.0.0/docs\\": [ + "pluginId": "default", + "version": "1.0.0", + "label": "1.0.0", + "banner": "unmaintained", + "badge": true, + "className": "docs-version-1.0.0", + "isLast": false, + "docsSidebars": { + "version-1.0.0/docs": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"Test\\", - \\"items\\": [ + "type": "category", + "label": "Test", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"bar\\", - \\"href\\": \\"/docs/1.0.0/foo/barSlug\\", - \\"docId\\": \\"foo/bar\\" + "type": "link", + "label": "bar", + "href": "/docs/1.0.0/foo/barSlug", + "docId": "foo/bar" }, { - \\"type\\": \\"link\\", - \\"label\\": \\"baz\\", - \\"href\\": \\"/docs/1.0.0/foo/baz\\", - \\"docId\\": \\"foo/baz\\" + "type": "link", + "label": "baz", + "href": "/docs/1.0.0/foo/baz", + "docId": "foo/baz" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true }, { - \\"type\\": \\"category\\", - \\"label\\": \\"Guides\\", - \\"items\\": [ + "type": "category", + "label": "Guides", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"hello\\", - \\"href\\": \\"/docs/1.0.0/\\", - \\"docId\\": \\"hello\\" + "type": "link", + "label": "hello", + "href": "/docs/1.0.0/", + "docId": "hello" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true } ] }, - \\"docs\\": { - \\"foo/bar\\": { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"Bar 1.0.0 !\\", - \\"sidebar\\": \\"version-1.0.0/docs\\" - }, - \\"foo/baz\\": { - \\"id\\": \\"foo/baz\\", - \\"title\\": \\"baz\\", - \\"description\\": \\"Baz 1.0.0 ! This will be deleted in next subsequent versions.\\", - \\"sidebar\\": \\"version-1.0.0/docs\\" - }, - \\"hello\\": { - \\"id\\": \\"hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello 1.0.0 ! (translated en)\\", - \\"sidebar\\": \\"version-1.0.0/docs\\" + "docs": { + "foo/bar": { + "id": "foo/bar", + "title": "bar", + "description": "Bar 1.0.0 !", + "sidebar": "version-1.0.0/docs" + }, + "foo/baz": { + "id": "foo/baz", + "title": "baz", + "description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.", + "sidebar": "version-1.0.0/docs" + }, + "hello": { + "id": "hello", + "title": "hello", + "description": "Hello 1.0.0 ! (translated en)", + "sidebar": "version-1.0.0/docs" } } }", "version-1-0-1-metadata-prop-e87.json": "{ - \\"pluginId\\": \\"default\\", - \\"version\\": \\"1.0.1\\", - \\"label\\": \\"1.0.1\\", - \\"banner\\": null, - \\"badge\\": true, - \\"className\\": \\"docs-version-1.0.1\\", - \\"isLast\\": true, - \\"docsSidebars\\": { - \\"VersionedSideBarNameDoesNotMatter/docs\\": [ + "pluginId": "default", + "version": "1.0.1", + "label": "1.0.1", + "banner": null, + "badge": true, + "className": "docs-version-1.0.1", + "isLast": true, + "docsSidebars": { + "VersionedSideBarNameDoesNotMatter/docs": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"Test\\", - \\"items\\": [ + "type": "category", + "label": "Test", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"bar\\", - \\"href\\": \\"/docs/foo/bar\\", - \\"docId\\": \\"foo/bar\\" + "type": "link", + "label": "bar", + "href": "/docs/foo/bar", + "docId": "foo/bar" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true }, { - \\"type\\": \\"category\\", - \\"label\\": \\"Guides\\", - \\"items\\": [ + "type": "category", + "label": "Guides", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"hello\\", - \\"href\\": \\"/docs/\\", - \\"docId\\": \\"hello\\" + "type": "link", + "label": "hello", + "href": "/docs/", + "docId": "hello" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true } ] }, - \\"docs\\": { - \\"foo/bar\\": { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"Bar 1.0.1 !\\", - \\"sidebar\\": \\"VersionedSideBarNameDoesNotMatter/docs\\" - }, - \\"hello\\": { - \\"id\\": \\"hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello 1.0.1 !\\", - \\"sidebar\\": \\"VersionedSideBarNameDoesNotMatter/docs\\" + "docs": { + "foo/bar": { + "id": "foo/bar", + "title": "bar", + "description": "Bar 1.0.1 !", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs" + }, + "hello": { + "id": "hello", + "title": "hello", + "description": "Hello 1.0.1 !", + "sidebar": "VersionedSideBarNameDoesNotMatter/docs" } } }", "version-current-metadata-prop-751.json": "{ - \\"pluginId\\": \\"default\\", - \\"version\\": \\"current\\", - \\"label\\": \\"Next\\", - \\"banner\\": \\"unreleased\\", - \\"badge\\": true, - \\"className\\": \\"docs-version-current\\", - \\"isLast\\": false, - \\"docsSidebars\\": { - \\"docs\\": [ + "pluginId": "default", + "version": "current", + "label": "Next", + "banner": "unreleased", + "badge": true, + "className": "docs-version-current", + "isLast": false, + "docsSidebars": { + "docs": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"Test\\", - \\"items\\": [ + "type": "category", + "label": "Test", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"bar\\", - \\"href\\": \\"/docs/next/foo/barSlug\\", - \\"docId\\": \\"foo/bar\\" + "type": "link", + "label": "bar", + "href": "/docs/next/foo/barSlug", + "docId": "foo/bar" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true }, { - \\"type\\": \\"category\\", - \\"label\\": \\"Guides\\", - \\"items\\": [ + "type": "category", + "label": "Guides", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"hello\\", - \\"href\\": \\"/docs/next/\\", - \\"docId\\": \\"hello\\" + "type": "link", + "label": "hello", + "href": "/docs/next/", + "docId": "hello" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true } ] }, - \\"docs\\": { - \\"foo/bar\\": { - \\"id\\": \\"foo/bar\\", - \\"title\\": \\"bar\\", - \\"description\\": \\"This is next version of bar.\\", - \\"sidebar\\": \\"docs\\" - }, - \\"hello\\": { - \\"id\\": \\"hello\\", - \\"title\\": \\"hello\\", - \\"description\\": \\"Hello next !\\", - \\"sidebar\\": \\"docs\\" - }, - \\"slugs/absoluteSlug\\": { - \\"id\\": \\"slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/relativeSlug\\": { - \\"id\\": \\"slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/resolvedSlug\\": { - \\"id\\": \\"slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/tryToEscapeSlug\\": { - \\"id\\": \\"slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\" + "docs": { + "foo/bar": { + "id": "foo/bar", + "title": "bar", + "description": "This is next version of bar.", + "sidebar": "docs" + }, + "hello": { + "id": "hello", + "title": "hello", + "description": "Hello next !", + "sidebar": "docs" + }, + "slugs/absoluteSlug": { + "id": "slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem" + }, + "slugs/relativeSlug": { + "id": "slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem" + }, + "slugs/resolvedSlug": { + "id": "slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem" + }, + "slugs/tryToEscapeSlug": { + "id": "slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem" } } }", "version-with-slugs-metadata-prop-2bf.json": "{ - \\"pluginId\\": \\"default\\", - \\"version\\": \\"withSlugs\\", - \\"label\\": \\"withSlugs\\", - \\"banner\\": \\"unmaintained\\", - \\"badge\\": true, - \\"className\\": \\"docs-version-withSlugs\\", - \\"isLast\\": false, - \\"docsSidebars\\": { - \\"version-1.0.1/docs\\": [ + "pluginId": "default", + "version": "withSlugs", + "label": "withSlugs", + "banner": "unmaintained", + "badge": true, + "className": "docs-version-withSlugs", + "isLast": false, + "docsSidebars": { + "version-1.0.1/docs": [ { - \\"type\\": \\"category\\", - \\"label\\": \\"Test\\", - \\"items\\": [ + "type": "category", + "label": "Test", + "items": [ { - \\"type\\": \\"link\\", - \\"label\\": \\"rootAbsoluteSlug\\", - \\"href\\": \\"/docs/withSlugs/rootAbsoluteSlug\\", - \\"docId\\": \\"rootAbsoluteSlug\\" + "type": "link", + "label": "rootAbsoluteSlug", + "href": "/docs/withSlugs/rootAbsoluteSlug", + "docId": "rootAbsoluteSlug" } ], - \\"collapsed\\": true, - \\"collapsible\\": true + "collapsed": true, + "collapsible": true } ] }, - \\"docs\\": { - \\"rootAbsoluteSlug\\": { - \\"id\\": \\"rootAbsoluteSlug\\", - \\"title\\": \\"rootAbsoluteSlug\\", - \\"description\\": \\"Lorem\\", - \\"sidebar\\": \\"version-1.0.1/docs\\" - }, - \\"rootRelativeSlug\\": { - \\"id\\": \\"rootRelativeSlug\\", - \\"title\\": \\"rootRelativeSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"rootResolvedSlug\\": { - \\"id\\": \\"rootResolvedSlug\\", - \\"title\\": \\"rootResolvedSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"rootTryToEscapeSlug\\": { - \\"id\\": \\"rootTryToEscapeSlug\\", - \\"title\\": \\"rootTryToEscapeSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/absoluteSlug\\": { - \\"id\\": \\"slugs/absoluteSlug\\", - \\"title\\": \\"absoluteSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/relativeSlug\\": { - \\"id\\": \\"slugs/relativeSlug\\", - \\"title\\": \\"relativeSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/resolvedSlug\\": { - \\"id\\": \\"slugs/resolvedSlug\\", - \\"title\\": \\"resolvedSlug\\", - \\"description\\": \\"Lorem\\" - }, - \\"slugs/tryToEscapeSlug\\": { - \\"id\\": \\"slugs/tryToEscapeSlug\\", - \\"title\\": \\"tryToEscapeSlug\\", - \\"description\\": \\"Lorem\\" + "docs": { + "rootAbsoluteSlug": { + "id": "rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + "description": "Lorem", + "sidebar": "version-1.0.1/docs" + }, + "rootRelativeSlug": { + "id": "rootRelativeSlug", + "title": "rootRelativeSlug", + "description": "Lorem" + }, + "rootResolvedSlug": { + "id": "rootResolvedSlug", + "title": "rootResolvedSlug", + "description": "Lorem" + }, + "rootTryToEscapeSlug": { + "id": "rootTryToEscapeSlug", + "title": "rootTryToEscapeSlug", + "description": "Lorem" + }, + "slugs/absoluteSlug": { + "id": "slugs/absoluteSlug", + "title": "absoluteSlug", + "description": "Lorem" + }, + "slugs/relativeSlug": { + "id": "slugs/relativeSlug", + "title": "relativeSlug", + "description": "Lorem" + }, + "slugs/resolvedSlug": { + "id": "slugs/resolvedSlug", + "title": "resolvedSlug", + "description": "Lorem" + }, + "slugs/tryToEscapeSlug": { + "id": "slugs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + "description": "Lorem" } } }", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 27d56ecee103..6b684e82b8a9 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -82,12 +82,12 @@ describe('docsVersion', () => { await expect(() => cliDocsVersionCommand('..', DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[docs]: invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0."`, + `"[docs]: invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0."`, ); await expect(() => cliDocsVersionCommand('.', DEFAULT_OPTIONS, {siteDir: simpleSiteDir}), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[docs]: invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0."`, + `"[docs]: invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0."`, ); }); @@ -133,7 +133,7 @@ describe('docsVersion', () => { i18n: {locales: ['en', 'zh-Hans'], defaultLocale: 'en'}, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[docs]: no docs found in \\"/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs\\"."`, + `"[docs]: no docs found in "/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docs"."`, ); }); @@ -249,7 +249,7 @@ describe('docsVersion', () => { ), ); expect(warnMock.mock.calls[0][0]).toMatchInlineSnapshot( - `"[WARNING] [docs]: no docs found in \\"/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current\\". Skipping."`, + `"[WARNING] [docs]: no docs found in "/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/i18n/zh-Hans/docusaurus-plugin-content-docs/current". Skipping."`, ); warnMock.mockRestore(); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 0623a345cc2f..6d4e02f8a629 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -487,7 +487,7 @@ describe('simple site', () => { }), ), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Document id \\"Hello/world\\" cannot include slash."`, + `"Document id "Hello/world" cannot include slash."`, ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 1ad236a88638..46d87d936ef9 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -143,10 +143,11 @@ describe('sidebar', () => { }, }), ); + await plugin.loadContent!(); }).rejects.toThrowErrorMatchingInlineSnapshot(` - "The path to the sidebar file does not exist at \\"wrong-path-sidebar.json\\". - Please set the docs \\"sidebarPath\\" field in your config file to: + "The path to the sidebar file does not exist at "wrong-path-sidebar.json". + Please set the docs "sidebarPath" field in your config file to: - a sidebars path that exists - false: to disable the sidebar - undefined: for Docusaurus to generate it automatically" @@ -203,7 +204,7 @@ describe('empty/no docs website', () => { await expect( plugin.loadContent!(), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Docs version \\"current\\" has no docs! At least one doc should exist at \\"docs\\"."`, + `"Docs version "current" has no docs! At least one doc should exist at "docs"."`, ); }); @@ -220,7 +221,7 @@ describe('empty/no docs website', () => { }), ), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"The docs folder does not exist for version \\"current\\". A docs folder is expected to be found at path/does/not/exist."`, + `"The docs folder does not exist for version "current". A docs folder is expected to be found at path/does/not/exist."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 8f21906faa5e..eec906acb515 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -117,7 +117,7 @@ describe('normalizeDocsPluginOptions', () => { expect(() => testValidate(admonitionsTrue), ).toThrowErrorMatchingInlineSnapshot( - `"\\"admonitions\\" contains an invalid value"`, + `""admonitions" contains an invalid value"`, ); }); @@ -151,9 +151,9 @@ describe('normalizeDocsPluginOptions', () => { remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]], }), ).toThrowErrorMatchingInlineSnapshot(` - "\\"remarkPlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: - - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or - - A simple module, like \`require(\\"remark-math\\")\`" + ""remarkPlugins[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or + - A simple module, like \`require("remark-math")\`" `); }); @@ -169,46 +169,42 @@ describe('normalizeDocsPluginOptions', () => { ], }), ).toThrowErrorMatchingInlineSnapshot(` - "\\"rehypePlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: - - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or - - A simple module, like \`require(\\"remark-math\\")\`" + ""rehypePlugins[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or + - A simple module, like \`require("remark-math")\`" `); }); it('rejects bad path inputs', () => { expect(() => testValidate({path: 2})).toThrowErrorMatchingInlineSnapshot( - `"\\"path\\" must be a string"`, + `""path" must be a string"`, ); }); it('rejects bad include inputs', () => { expect(() => testValidate({include: '**/*.{md,mdx}'}), - ).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`); + ).toThrowErrorMatchingInlineSnapshot(`""include" must be an array"`); }); it('rejects bad showLastUpdateTime inputs', () => { expect(() => testValidate({showLastUpdateTime: 'true'}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"showLastUpdateTime\\" must be a boolean"`, + `""showLastUpdateTime" must be a boolean"`, ); }); it('rejects bad remarkPlugins input', () => { expect(() => testValidate({remarkPlugins: 'remark-math'}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"remarkPlugins\\" must be an array"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""remarkPlugins" must be an array"`); }); it('rejects bad lastVersion', () => { expect(() => testValidate({lastVersion: false}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"lastVersion\\" must be a string"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""lastVersion" must be a string"`); }); it('rejects bad versions', () => { @@ -218,6 +214,7 @@ describe('normalizeDocsPluginOptions', () => { current: { hey: 3, }, + version1: { path: 'hello', label: 'world', @@ -225,7 +222,7 @@ describe('normalizeDocsPluginOptions', () => { }, }), ).toThrowErrorMatchingInlineSnapshot( - `"\\"versions.current.hey\\" is not allowed"`, + `""versions.current.hey" is not allowed"`, ); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts index 25ee077dad10..607464d8702e 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/slug.test.ts @@ -120,7 +120,7 @@ describe('getSlug', () => { frontMatterSlug: '//', }), ).toThrowErrorMatchingInlineSnapshot(` - "We couldn't compute a valid slug for document with ID \\"my dôc\\" in \\"/dir with spâce/hey $hello\\" directory. + "We couldn't compute a valid slug for document with ID "my dôc" in "/dir with spâce/hey $hello" directory. The slug we computed looks invalid: //. Maybe your slug front matter is incorrect or there are special characters in the file path? By using front matter to set a custom slug, you should be able to fix this error: diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts index 5209f7dfea05..059d5b87c718 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/versions.test.ts @@ -187,10 +187,11 @@ describe('readVersionsMetadata', () => { unknownVersionName2: {label: 'unknownVersionName2'}, }, }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"versions\\": unknown versions (unknownVersionName1,unknownVersionName2) found. Available version names are: current"`, + `"Invalid docs option "versions": unknown versions (unknownVersionName1,unknownVersionName2) found. Available version names are: current"`, ); }); @@ -203,7 +204,7 @@ describe('readVersionsMetadata', () => { context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Docs: using \\"disableVersioning: true\\" option on a non-versioned site does not make sense."`, + `"Docs: using "disableVersioning: true" option on a non-versioned site does not make sense."`, ); }); @@ -216,7 +217,7 @@ describe('readVersionsMetadata', () => { context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: false\\"."`, + `"It is not possible to use docs without any version. Please check the configuration of these options: "includeCurrentVersion: false", "disableVersioning: false"."`, ); }); }); @@ -557,10 +558,11 @@ describe('readVersionsMetadata', () => { includeCurrentVersion: false, disableVersioning: true, }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, + `"It is not possible to use docs without any version. Please check the configuration of these options: "includeCurrentVersion: false", "disableVersioning: true"."`, ); }); @@ -573,10 +575,11 @@ describe('readVersionsMetadata', () => { ...defaultOptions, onlyIncludeVersions: [], }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"onlyIncludeVersions\\": an empty array is not allowed, at least one version is needed."`, + `"Invalid docs option "onlyIncludeVersions": an empty array is not allowed, at least one version is needed."`, ); }); @@ -589,10 +592,11 @@ describe('readVersionsMetadata', () => { ...defaultOptions, onlyIncludeVersions: ['unknownVersion1', 'unknownVersion2'], }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"onlyIncludeVersions\\": unknown versions (unknownVersion1,unknownVersion2) found. Available version names are: current, 1.0.1, 1.0.0, withSlugs"`, + `"Invalid docs option "onlyIncludeVersions": unknown versions (unknownVersion1,unknownVersion2) found. Available version names are: current, 1.0.1, 1.0.0, withSlugs"`, ); }); @@ -606,10 +610,11 @@ describe('readVersionsMetadata', () => { lastVersion: '1.0.1', onlyIncludeVersions: ['current', '1.0.0'], }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid docs option \\"lastVersion\\": if you use both the \\"onlyIncludeVersions\\" and \\"lastVersion\\" options, then \\"lastVersion\\" must be present in the provided \\"onlyIncludeVersions\\" array."`, + `"Invalid docs option "lastVersion": if you use both the "onlyIncludeVersions" and "lastVersion" options, then "lastVersion" must be present in the provided "onlyIncludeVersions" array."`, ); }); @@ -627,7 +632,7 @@ describe('readVersionsMetadata', () => { context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"The versions file should contain an array of version names! Found content: {\\"invalid\\":\\"json\\"}"`, + `"The versions file should contain an array of version names! Found content: {"invalid":"json"}"`, ); jsonMock.mockImplementationOnce(() => [1.1]); @@ -637,7 +642,7 @@ describe('readVersionsMetadata', () => { context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Versions should be strings. Found type \\"number\\" for version \\"1.1\\"."`, + `"Versions should be strings. Found type "number" for version "1.1"."`, ); jsonMock.mockImplementationOnce(() => [' ']); @@ -646,9 +651,7 @@ describe('readVersionsMetadata', () => { options: defaultOptions, context: defaultContext, }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid version \\" \\"."`, - ); + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Invalid version " "."`); jsonMock.mockRestore(); }); }); @@ -772,10 +775,11 @@ describe('readVersionsMetadata', () => { includeCurrentVersion: false, disableVersioning: true, }, + context: defaultContext, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"It is not possible to use docs without any version. Please check the configuration of these options: \\"includeCurrentVersion: false\\", \\"disableVersioning: true\\"."`, + `"It is not possible to use docs without any version. Please check the configuration of these options: "includeCurrentVersion: false", "disableVersioning: true"."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts index 9663b014627c..5ca427b76621 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/__tests__/docsClientUtils.test.ts @@ -38,12 +38,12 @@ describe('docsClientUtils', () => { expect(() => getActivePlugin(data, '/', {failfast: true}), ).toThrowErrorMatchingInlineSnapshot( - `"Can't find active docs plugin for \\"/\\" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`, + `"Can't find active docs plugin for "/" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`, ); expect(() => getActivePlugin(data, '/xyz', {failfast: true}), ).toThrowErrorMatchingInlineSnapshot( - `"Can't find active docs plugin for \\"/xyz\\" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`, + `"Can't find active docs plugin for "/xyz" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: /ios, /android"`, ); const activePluginIos: ActivePlugin = { diff --git a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts index f106ea6edb9d..451bec66ccac 100644 --- a/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/linkify.test.ts @@ -200,7 +200,7 @@ describe('linkify', () => { await expect(() => transform(doc1), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unexpected error: Markdown file at \\"/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md\\" does not belong to any docs version!"`, + `"Unexpected error: Markdown file at "/packages/docusaurus-plugin-content-docs/src/markdown/__tests__/__fixtures__/outside/doc1.md" does not belong to any docs version!"`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts index ec19a5c4fb69..b94ffea65bdf 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/index.test.ts @@ -62,7 +62,7 @@ describe('loadSidebars', () => { await expect(() => loadSidebars(sidebarPath, params), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid sidebar items collection \`\\"doc1\\"\` in \`items\` of the category Category Label: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, + `"Invalid sidebar items collection \`"doc1"\` in \`items\` of the category Category Label: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); }); @@ -131,7 +131,7 @@ describe('loadSidebars', () => { contentPathLocalized: path.join(fixtureDir, 'invalid-docs'), }, }), - ).rejects.toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" is not allowed"`); + ).rejects.toThrowErrorMatchingInlineSnapshot(`""foo" is not allowed"`); expect(consoleWarnMock).toBeCalledWith( expect.stringMatching( /.*\[WARNING\].* There are more than one category metadata files for .*foo.*: foo\/_category_.json, foo\/_category_.yml. The behavior is undetermined./, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts index 66a27886d0ba..f9413e73f68e 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/normalization.test.ts @@ -46,7 +46,7 @@ describe('normalization', () => { }, }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid sidebar items collection \`{\\"type\\":\\"autogenerated\\",\\"dirName\\":\\"foo\\"}\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, + `"Invalid sidebar items collection \`{"type":"autogenerated","dirName":"foo"}\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); expect(() => @@ -62,7 +62,7 @@ describe('normalization', () => { ], }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid sidebar items collection \`{\\"type\\":\\"category\\",\\"items\\":[\\"bar\\",\\"baz\\"]}\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, + `"Invalid sidebar items collection \`{"type":"category","items":["bar","baz"]}\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); expect(() => @@ -75,7 +75,7 @@ describe('normalization', () => { ], }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid sidebar items collection \`\\"bar\\"\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, + `"Invalid sidebar items collection \`"bar"\` in \`items\` of the category Category: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); expect(() => @@ -83,8 +83,7 @@ describe('normalization', () => { sidebar: 'item', }), ).toThrowErrorMatchingInlineSnapshot( - // cSpell:ignore msidebar - `"Invalid sidebar items collection \`\\"item\\"\` in sidebar sidebar: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, + `"Invalid sidebar items collection \`"item"\` in sidebar sidebar: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a \`type\` property). See https://docusaurus.io/docs/sidebar/items for all valid syntaxes."`, ); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts index c5a09a6be6f6..d8f5fcab0d9e 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts @@ -13,11 +13,11 @@ describe('validateSidebars', () => { expect(() => validateSidebars({sidebar: [{type: 42}]})) .toThrowErrorMatchingInlineSnapshot(` "{ - \\"type\\": 42, - \\"undefined\\" [1]: -- missing -- + "type": 42, + "undefined" [1]: -- missing -- } -  - [1] Unknown sidebar item type \\"42\\"." + + [1] Unknown sidebar item type "42"." `); }); @@ -53,20 +53,21 @@ describe('validateSidebars', () => { }, ], }), + // eslint-disable-next-line jest/no-large-snapshots ).toThrowErrorMatchingInlineSnapshot(` "{ - \\"type\\": \\"category\\", - \\"items\\": [ + "type": "category", + "items": [ { - \\"type\\": \\"doc\\", - \\"id\\": \\"doc1\\" + "type": "doc", + "id": "doc1" } ], - \\"label\\" [1]: true + "label" [1]: true } -  - [1] \\"label\\" must be a string" + + [1] "label" must be a string" `); }); @@ -82,14 +83,14 @@ describe('validateSidebars', () => { ], }), ).toThrowErrorMatchingInlineSnapshot(` - "{ - \\"type\\": \\"link\\", - \\"href\\": \\"https://github.com\\", - \\"label\\" [1]: false - } -  - [1] \\"label\\" must be a string" - `); + "{ + "type": "link", + "href": "https://github.com", + "label" [1]: false + } + + [1] "label" must be a string" + `); }); it('sidebars link wrong href', () => { @@ -104,16 +105,16 @@ describe('validateSidebars', () => { ], }), ).toThrowErrorMatchingInlineSnapshot(` - "{ - \\"type\\": \\"link\\", - \\"label\\": \\"GitHub\\", - \\"href\\" [1]: [ - \\"example.com\\" - ] - } -  - [1] \\"href\\" contains an invalid value" - `); + "{ + "type": "link", + "label": "GitHub", + "href" [1]: [ + "example.com" + ] + } + + [1] "href" contains an invalid value" + `); }); it('sidebars with unknown sidebar item type', () => { @@ -126,13 +127,13 @@ describe('validateSidebars', () => { ], }), ).toThrowErrorMatchingInlineSnapshot(` - "{ - \\"type\\": \\"superman\\", - \\"undefined\\" [1]: -- missing -- - } -  - [1] Unknown sidebar item type \\"superman\\"." - `); + "{ + "type": "superman", + "undefined" [1]: -- missing -- + } + + [1] Unknown sidebar item type "superman"." + `); }); it('sidebars category missing items', () => { @@ -152,12 +153,12 @@ describe('validateSidebars', () => { }), ).toThrowErrorMatchingInlineSnapshot(` "{ - \\"type\\": \\"category\\", - \\"label\\": \\"category\\", - \\"items\\" [1]: -- missing -- + "type": "category", + "label": "category", + "items" [1]: -- missing -- } -  - [1] \\"items\\" is required" + + [1] "items" is required" `); }); @@ -180,13 +181,13 @@ describe('validateSidebars', () => { }), ).toThrowErrorMatchingInlineSnapshot(` "{ - \\"type\\": \\"category\\", - \\"label\\": \\"category\\", - \\"items\\": [], - \\"href\\" [1]: \\"https://google.com\\" + "type": "category", + "label": "category", + "items": [], + "href" [1]: "https://google.com" } -  - [1] \\"href\\" is not allowed" + + [1] "href" is not allowed" `); }); @@ -217,15 +218,15 @@ describe('validateSidebars', () => { ], }), ).toThrowErrorMatchingInlineSnapshot(` - "{ - \\"type\\": \\"doc\\", - \\"id\\" [1]: [ - \\"doc1\\" - ] - } -  - [1] \\"id\\" must be a string" - `); + "{ + "type": "doc", + "id" [1]: [ + "doc1" + ] + } + + [1] "id" must be a string" + `); }); it('html type requires a value', () => { @@ -240,11 +241,11 @@ describe('validateSidebars', () => { expect(() => validateSidebars(sidebars)) .toThrowErrorMatchingInlineSnapshot(` "{ - \\"type\\": \\"html\\", - \\"value\\" [1]: -- missing -- + "type": "html", + "value" [1]: -- missing -- } -  - [1] \\"value\\" is required" + + [1] "value" is required" `); }); @@ -269,9 +270,7 @@ describe('validateCategoryMetadataFile', () => { it('throw for bad value', async () => { expect(() => validateCategoryMetadataFile(42), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`); }); it('accept empty object', async () => { @@ -314,8 +313,6 @@ describe('validateCategoryMetadataFile', () => { }; expect(() => validateCategoryMetadataFile(content), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"link.permalink\\" is not allowed"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""link.permalink" is not allowed"`); }); }); diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts index 5038527034cb..9365b614cd9f 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/options.test.ts @@ -49,6 +49,6 @@ describe('normalizePagesPluginOptions', () => { // @ts-expect-error: bad attribute path: 42, }); - }).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`); + }).toThrowErrorMatchingInlineSnapshot(`""path" must be a string"`); }); }); diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts index 5e38548b699d..9e93e57de8ec 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts @@ -39,7 +39,7 @@ describe('validateOptions', () => { expect(() => testValidate({priority: 2}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"priority\\" must be less than or equal to 1"`, + `""priority" must be less than or equal to 1"`, ); }); @@ -47,20 +47,18 @@ describe('validateOptions', () => { expect(() => testValidate({changefreq: 'annually'}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"changefreq\\" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`, + `""changefreq" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`, ); }); it('rejects bad ignorePatterns inputs', () => { expect(() => testValidate({ignorePatterns: '/search'}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"ignorePatterns\\" must be an array"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""ignorePatterns" must be an array"`); expect(() => testValidate({ignorePatterns: [/^\/search/]}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"ignorePatterns[0]\\" must be a string"`, + `""ignorePatterns[0]" must be a string"`, ); }); }); diff --git a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap index d00ba962a458..b8e77588d05b 100644 --- a/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-remark-plugin-npm2yarn/src/__tests__/__snapshots__/index.test.ts.snap @@ -6,14 +6,14 @@ exports[`npm2yarn plugin does not re-import tabs components when already importe import TabItem from '@theme/TabItem'; - + \`\`\`bash $ npm install --global docusaurus \`\`\` - + \`\`\`bash $ yarn add --global docusaurus @@ -26,14 +26,14 @@ import TabItem from '@theme/TabItem'; exports[`npm2yarn plugin does not re-import tabs components when already imported below 1`] = ` " - + \`\`\`bash $ npm install --global docusaurus \`\`\` - + \`\`\`bash $ yarn add --global docusaurus @@ -68,14 +68,14 @@ exports[`npm2yarn plugin works on installation file 1`] = ` import TabItem from '@theme/TabItem'; - + \`\`\`bash $ npm install --global docusaurus \`\`\` - + \`\`\`bash $ yarn add --global docusaurus @@ -95,14 +95,14 @@ import TabItem from '@theme/TabItem'; A plugin is usually a npm package, so you install them like other npm packages using npm. - + \`\`\`bash npm install --save docusaurus-plugin-name \`\`\` - + \`\`\`bash yarn add docusaurus-plugin-name @@ -121,15 +121,15 @@ import TabItem from '@theme/TabItem'; A plugin is usually a npm package, so you install them like other npm packages using npm. - - + + \`\`\`bash npm install --save docusaurus-plugin-name \`\`\` - + \`\`\`bash yarn add docusaurus-plugin-name diff --git a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts index 6fe62bb524ec..10c4f62d1bcf 100644 --- a/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-classic/src/__tests__/validateThemeConfig.test.ts @@ -295,7 +295,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig(config), ).toThrowErrorMatchingInlineSnapshot( - `"\\"navbar.items[0].items[0].position\\" is not allowed"`, + `""navbar.items[0].items[0].position" is not allowed"`, ); }); @@ -315,7 +315,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig(config), ).toThrowErrorMatchingInlineSnapshot( - `"One and only one between \\"to\\" and \\"href\\" should be provided"`, + `"One and only one between "to" and "href" should be provided"`, ); }); @@ -514,7 +514,7 @@ describe('themeConfig', () => { customCss: 42, }), ).toThrowErrorMatchingInlineSnapshot( - `"\\"customCss\\" must be one of [array, string]"`, + `""customCss" must be one of [array, string]"`, ); }); }); @@ -624,7 +624,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be an integer"`, + `""tableOfContents.minHeadingLevel" must be an integer"`, ); }); @@ -635,7 +635,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be an integer"`, + `""tableOfContents.maxHeadingLevel" must be an integer"`, ); }); @@ -646,7 +646,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be greater than or equal to 2"`, + `""tableOfContents.minHeadingLevel" must be greater than or equal to 2"`, ); }); @@ -657,7 +657,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, + `""tableOfContents.minHeadingLevel" must be less than or equal to ref:maxHeadingLevel"`, ); }); @@ -668,7 +668,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be greater than or equal to 2"`, + `""tableOfContents.maxHeadingLevel" must be greater than or equal to 2"`, ); }); @@ -679,7 +679,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.maxHeadingLevel\\" must be less than or equal to 6"`, + `""tableOfContents.maxHeadingLevel" must be less than or equal to 6"`, ); }); @@ -691,7 +691,7 @@ describe('themeConfig', () => { expect(() => testValidateThemeConfig({tableOfContents}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"tableOfContents.minHeadingLevel\\" must be less than or equal to ref:maxHeadingLevel"`, + `""tableOfContents.minHeadingLevel" must be less than or equal to ref:maxHeadingLevel"`, ); }); }); diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx index 52966b9c2fa6..b609058e80c6 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/__tests__/index.test.tsx @@ -24,7 +24,7 @@ describe('Tabs', () => { , ); }).toThrowErrorMatchingInlineSnapshot( - `"Docusaurus error: Bad child
    : all children of the component should be , and every should have a unique \\"value\\" prop."`, + `"Docusaurus error: Bad child
    : all children of the component should be , and every should have a unique "value" prop."`, ); }); it('rejects bad Tabs defaultValue', () => { @@ -36,7 +36,7 @@ describe('Tabs', () => { , ); }).toThrowErrorMatchingInlineSnapshot( - `"Docusaurus error: The has a defaultValue \\"bad\\" but none of its children has the corresponding value. Available values are: v1, v2. If you intend to show no default tab, use defaultValue={null} instead."`, + `"Docusaurus error: The has a defaultValue "bad" but none of its children has the corresponding value. Available values are: v1, v2. If you intend to show no default tab, use defaultValue={null} instead."`, ); }); it('rejects duplicate values', () => { @@ -52,7 +52,7 @@ describe('Tabs', () => { , ); }).toThrowErrorMatchingInlineSnapshot( - `"Docusaurus error: Duplicate values \\"v1, v2\\" found in . Every value needs to be unique."`, + `"Docusaurus error: Duplicate values "v1, v2" found in . Every value needs to be unique."`, ); }); it('accepts valid Tabs config', () => { diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap index bca094fc9ec4..8b5e1adee6ee 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap +++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap @@ -126,7 +126,7 @@ dddd \`\`\`js // highlight-next-line -console.log(\\"preserved\\"); +console.log("preserved"); \`\`\`", "highlightLines": [ 1, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx index 13777535a6e4..10c471d2eb1e 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/usePluralForm.test.tsx @@ -69,7 +69,7 @@ describe('usePluralForm', () => { expect(mockUsePluralForm().selectMessage(1, 'one|many')).toBe('one'); expect(mockUsePluralForm().selectMessage(10, 'one|many')).toBe('many'); expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(` - "Failed to use Intl.PluralRules for locale \\"zh-Hans\\". + "Failed to use Intl.PluralRules for locale "zh-Hans". Docusaurus will fallback to the default (English) implementation. Error: pluralRules.resolvedOptions is not a function " diff --git a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts index 33fe017f0fd9..af6b72731932 100644 --- a/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-live-codeblock/src/__tests__/validateThemeConfig.test.ts @@ -77,7 +77,7 @@ describe('validateThemeConfig', () => { expect(() => testValidateThemeConfig({liveCodeBlock}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"liveCodeBlock.playgroundPosition\\" must be one of [top, bottom]"`, + `""liveCodeBlock.playgroundPosition" must be one of [top, bottom]"`, ); }); it('playgroundPosition invalid boolean', () => { @@ -85,7 +85,7 @@ describe('validateThemeConfig', () => { expect(() => testValidateThemeConfig({liveCodeBlock}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"liveCodeBlock.playgroundPosition\\" must be one of [top, bottom]"`, + `""liveCodeBlock.playgroundPosition" must be one of [top, bottom]"`, ); }); }); diff --git a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts index 6d0cb4cfca1c..71c13896b4d3 100644 --- a/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts +++ b/packages/docusaurus-theme-search-algolia/src/__tests__/validateThemeConfig.test.ts @@ -56,33 +56,27 @@ describe('validateThemeConfig', () => { const algolia = undefined; expect(() => testValidateThemeConfig({algolia}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"themeConfig.algolia\\" is required"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""themeConfig.algolia" is required"`); }); it('undefined config 2', () => { expect(() => testValidateThemeConfig({}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"themeConfig.algolia\\" is required"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""themeConfig.algolia" is required"`); }); it('missing indexName config', () => { const algolia = {apiKey: 'apiKey', appId: 'BH4D9OD16A'}; expect(() => testValidateThemeConfig({algolia}), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"algolia.indexName\\" is required"`, - ); + ).toThrowErrorMatchingInlineSnapshot(`""algolia.indexName" is required"`); }); it('missing apiKey config', () => { const algolia = {indexName: 'indexName', appId: 'BH4D9OD16A'}; expect(() => testValidateThemeConfig({algolia}), - ).toThrowErrorMatchingInlineSnapshot(`"\\"algolia.apiKey\\" is required"`); + ).toThrowErrorMatchingInlineSnapshot(`""algolia.apiKey" is required"`); }); it('missing appId config', () => { @@ -90,7 +84,7 @@ describe('validateThemeConfig', () => { expect(() => testValidateThemeConfig({algolia}), ).toThrowErrorMatchingInlineSnapshot( - `"\\"algolia.appId\\" is required. If you haven't migrated to the new DocSearch infra, please refer to the blog post for instructions: https://docusaurus.io/blog/2021/11/21/algolia-docsearch-migration"`, + `""algolia.appId" is required. If you haven't migrated to the new DocSearch infra, please refer to the blog post for instructions: https://docusaurus.io/blog/2021/11/21/algolia-docsearch-migration"`, ); }); diff --git a/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts b/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts index 72f5cfd83994..2f8949b55fe0 100644 --- a/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts +++ b/packages/docusaurus-theme-translations/src/__tests__/utils.test.ts @@ -17,7 +17,7 @@ describe('extractThemeCodeMessages', () => { Please make sure all theme translations are static! Some warnings were found! - Translate content could not be extracted. It has to be a static string and use optional but static props, like text. + Translate content could not be extracted. It has to be a static string and use optional but static props, like text. File: packages/docusaurus-theme-translations/src/__tests__/__fixtures__/theme/index.js at line 4 Full code: {index} " diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index dc6695380d21..bfa30ac7873e 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -1,103 +1,103 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validation schemas admonitionsSchema: for value=[] 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=[] 1`] = `""value" must be of type object"`; -exports[`validation schemas admonitionsSchema: for value=3 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=3 1`] = `""value" must be of type object"`; -exports[`validation schemas admonitionsSchema: for value=null 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=null 1`] = `""value" must be of type object"`; -exports[`validation schemas admonitionsSchema: for value=true 1`] = `"\\"value\\" must be of type object"`; +exports[`validation schemas admonitionsSchema: for value=true 1`] = `""value" must be of type object"`; -exports[`validation schemas pathnameSchema: for value="foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validation schemas pathnameSchema: for value="foo" 1`] = `""value" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validation schemas pathnameSchema: for value="https://github.com/foo" 1`] = `"\\"value\\" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; +exports[`validation schemas pathnameSchema: for value="https://github.com/foo" 1`] = `""value" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; -exports[`validation schemas pluginIdSchema: for value="/docs" 1`] = `"Illegal plugin ID value \\"/docs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="/docs" 1`] = `"Illegal plugin ID value "/docs": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas pluginIdSchema: for value="do cs" 1`] = `"Illegal plugin ID value \\"do cs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="do cs" 1`] = `"Illegal plugin ID value "do cs": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas pluginIdSchema: for value="do/cs" 1`] = `"Illegal plugin ID value \\"do/cs\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="do/cs" 1`] = `"Illegal plugin ID value "do/cs": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas pluginIdSchema: for value="docs/" 1`] = `"Illegal plugin ID value \\"docs/\\": it should only contain alphanumerics, underscores, and dashes."`; +exports[`validation schemas pluginIdSchema: for value="docs/" 1`] = `"Illegal plugin ID value "docs/": it should only contain alphanumerics, underscores, and dashes."`; -exports[`validation schemas pluginIdSchema: for value=[] 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=[] 1`] = `""value" must be a string"`; -exports[`validation schemas pluginIdSchema: for value=3 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=3 1`] = `""value" must be a string"`; -exports[`validation schemas pluginIdSchema: for value=null 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=null 1`] = `""value" must be a string"`; -exports[`validation schemas pluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`; +exports[`validation schemas pluginIdSchema: for value=true 1`] = `""value" must be a string"`; exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; -exports[`validation schemas rehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=3 1`] = `""value" must be an array"`; -exports[`validation schemas rehypePluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=false 1`] = `""value" must be an array"`; -exports[`validation schemas rehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas rehypePluginsSchema: for value=null 1`] = `""value" must be an array"`; exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = ` -"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: -- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or -- A simple module, like \`require(\\"remark-math\\")\`" +""[0]" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), { strict: false }]\`, or +- A simple module, like \`require("remark-math")\`" `; -exports[`validation schemas remarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=3 1`] = `""value" must be an array"`; -exports[`validation schemas remarkPluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=false 1`] = `""value" must be an array"`; -exports[`validation schemas remarkPluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; +exports[`validation schemas remarkPluginsSchema: for value=null 1`] = `""value" must be an array"`; -exports[`validation schemas uRISchema: for value="spaces are invalid in a URL" 1`] = `"\\"value\\" does not look like a valid url (value='')"`; +exports[`validation schemas uRISchema: for value="spaces are invalid in a URL" 1`] = `""value" does not look like a valid url (value='')"`; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts index 25ed7b2f2793..771ff94c855c 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationUtils.test.ts @@ -43,7 +43,7 @@ describe('normalizePluginOptions', () => { const options = {foo: 1}; expect(() => normalizePluginOptions(Joi.object({foo: Joi.string()}), options), - ).toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" must be a string"`); + ).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`); }); it('warns', () => { @@ -91,7 +91,7 @@ describe('normalizeThemeConfig', () => { const themeConfig = {foo: 1, bar: 1}; expect(() => normalizeThemeConfig(Joi.object({foo: Joi.string()}), themeConfig), - ).toThrowErrorMatchingInlineSnapshot(`"\\"foo\\" must be a string"`); + ).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`); }); it('warns', () => { @@ -136,7 +136,7 @@ describe('validateFrontMatter', () => { }; expect(() => validateFrontMatter(frontMatter, schema), - ).toThrowErrorMatchingInlineSnapshot(`"\\"test\\" must be a string"`); + ).toThrowErrorMatchingInlineSnapshot(`""test" must be a string"`); expect(consoleError).toHaveBeenCalledWith( expect.stringContaining('The following front matter'), ); diff --git a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts index 251a1f6dbe2c..4d809a45c791 100644 --- a/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/dataFileUtils.test.ts @@ -202,7 +202,7 @@ describe('getFolderContainingFile', () => { 'dataFileUtils.test.ts', ), ).rejects.toThrowErrorMatchingInlineSnapshot(` - "File \\"dataFileUtils.test.ts\\" does not exist in any of these folders: + "File "dataFileUtils.test.ts" does not exist in any of these folders: - /foo - /bar - /baz" diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index 49a2844b4721..6db16ef20f31 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -131,7 +131,7 @@ describe('reportMessage', () => { // @ts-expect-error: for test reportMessage('hey', 'foo'), ).toThrowErrorMatchingInlineSnapshot( - `"Unexpected \\"reportingSeverity\\" value: foo."`, + `"Unexpected "reportingSeverity" value: foo."`, ); expect(consoleLog).toBeCalledTimes(1); expect(consoleLog).toBeCalledWith( diff --git a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx index e836cfc855b2..989bdbc7b3ac 100644 --- a/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/BrowserOnly.test.tsx @@ -40,7 +40,7 @@ describe('', () => { ) .toJSON(), ).toThrowErrorMatchingInlineSnapshot(` - "Docusaurus error: The children of must be a \\"render function\\", e.g. {() => {window.location.href}}. + "Docusaurus error: The children of must be a "render function", e.g. {() => {window.location.href}}. Current type: React element" `); }); @@ -55,7 +55,7 @@ describe('', () => { , ); }).toThrowErrorMatchingInlineSnapshot(` - "Docusaurus error: The children of must be a \\"render function\\", e.g. {() => {window.location.href}}. + "Docusaurus error: The children of must be a "render function", e.g. {() => {window.location.href}}. Current type: string" `); }); diff --git a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx index 3e5d370c4e0c..c2ec645c2887 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx @@ -69,7 +69,7 @@ describe('useAllPluginInstancesData', () => { ), }).result.current, ).toThrowErrorMatchingInlineSnapshot( - `"Docusaurus plugin global data not found for \\"bar\\" plugin."`, + `"Docusaurus plugin global data not found for "bar" plugin."`, ); }); }); @@ -116,7 +116,7 @@ describe('usePluginData', () => { ), }).result.current, ).toThrowErrorMatchingInlineSnapshot( - `"Docusaurus plugin global data not found for \\"foo\\" plugin with id \\"baz\\"."`, + `"Docusaurus plugin global data not found for "foo" plugin with id "baz"."`, ); }); }); diff --git a/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts b/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts index d5f17399e9bc..7dd867a08270 100644 --- a/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts +++ b/packages/docusaurus/src/commands/swizzle/__tests__/config.test.ts @@ -66,7 +66,7 @@ describe('normalizeSwizzleConfig', () => { expect(() => normalizeSwizzleConfig(config), ).toThrowErrorMatchingInlineSnapshot( - `"Swizzle config does not match expected schema: \\"components\\" is required"`, + `"Swizzle config does not match expected schema: "components" is required"`, ); }); @@ -87,7 +87,7 @@ describe('normalizeSwizzleConfig', () => { expect(() => normalizeSwizzleConfig(config), ).toThrowErrorMatchingInlineSnapshot( - `"Swizzle config does not match expected schema: \\"components.MyComponent.actions.bad\\" is not allowed"`, + `"Swizzle config does not match expected schema: "components.MyComponent.actions.bad" is not allowed"`, ); }); @@ -107,7 +107,7 @@ describe('normalizeSwizzleConfig', () => { expect(() => normalizeSwizzleConfig(config), ).toThrowErrorMatchingInlineSnapshot( - `"Swizzle config does not match expected schema: \\"components.MyComponent.actions.eject\\" must be one of [safe, unsafe, forbidden]"`, + `"Swizzle config does not match expected schema: "components.MyComponent.actions.eject" must be one of [safe, unsafe, forbidden]"`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap index 0d5185c5a678..b8a9733d0214 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -5,9 +5,9 @@ exports[`normalizeConfig should throw error if plugins is not a string and it's Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], @@ -21,9 +21,9 @@ exports[`normalizeConfig should throw error if plugins is not an array of [strin Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], @@ -37,9 +37,9 @@ exports[`normalizeConfig should throw error if plugins is not an array of [strin Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], @@ -53,9 +53,9 @@ exports[`normalizeConfig should throw error if plugins is not an array of [strin Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], @@ -65,7 +65,7 @@ Example valid plugin config: `; exports[`normalizeConfig should throw error if plugins is not array for the input of: {} 1`] = ` -"\\"plugins\\" must be an array +""plugins" must be an array " `; @@ -74,9 +74,9 @@ exports[`normalizeConfig should throw error if themes is not a string and it's n Example valid theme config: { themes: [ - [\\"@docusaurus/theme-classic\\",options], - \\"./myTheme\\", - [\\"./myTheme\\",{someOption: 42}], + ["@docusaurus/theme-classic",options], + "./myTheme", + ["./myTheme",{someOption: 42}], function myTheme() { }, [function myTheme() { },options] ], @@ -90,9 +90,9 @@ exports[`normalizeConfig should throw error if themes is not an array of [string Example valid theme config: { themes: [ - [\\"@docusaurus/theme-classic\\",options], - \\"./myTheme\\", - [\\"./myTheme\\",{someOption: 42}], + ["@docusaurus/theme-classic",options], + "./myTheme", + ["./myTheme",{someOption: 42}], function myTheme() { }, [function myTheme() { },options] ], @@ -106,9 +106,9 @@ exports[`normalizeConfig should throw error if themes is not an array of [string Example valid theme config: { themes: [ - [\\"@docusaurus/theme-classic\\",options], - \\"./myTheme\\", - [\\"./myTheme\\",{someOption: 42}], + ["@docusaurus/theme-classic",options], + "./myTheme", + ["./myTheme",{someOption: 42}], function myTheme() { }, [function myTheme() { },options] ], @@ -122,9 +122,9 @@ exports[`normalizeConfig should throw error if themes is not an array of [string Example valid theme config: { themes: [ - [\\"@docusaurus/theme-classic\\",options], - \\"./myTheme\\", - [\\"./myTheme\\",{someOption: 42}], + ["@docusaurus/theme-classic",options], + "./myTheme", + ["./myTheme",{someOption: 42}], function myTheme() { }, [function myTheme() { },options] ], @@ -134,30 +134,30 @@ Example valid theme config: `; exports[`normalizeConfig should throw error if themes is not array for the input of: {} 1`] = ` -"\\"themes\\" must be an array +""themes" must be an array " `; exports[`normalizeConfig throws error for baseUrl without trailing \`/\` 1`] = ` -"\\"baseUrl\\" must be a string with a trailing slash. +""baseUrl" must be a string with a trailing slash. " `; exports[`normalizeConfig throws error for required fields 1`] = ` -"\\"baseUrl\\" is required -\\"title\\" is required -\\"url\\" is required -\\"themes\\" must be an array -\\"presets\\" must be an array -\\"scripts\\" must be an array -\\"stylesheets\\" must be an array -These field(s) (\\"invalidField\\",) are not recognized in docusaurus.config.js. -If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. +""baseUrl" is required +"title" is required +"url" is required +"themes" must be an array +"presets" must be an array +"scripts" must be an array +"stylesheets" must be an array +These field(s) ("invalidField",) are not recognized in docusaurus.config.js. +If you still want these fields to be in your configuration, put them in the "customFields" field. See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `; exports[`normalizeConfig throws error for unknown field 1`] = ` -"These field(s) (\\"invalid\\",) are not recognized in docusaurus.config.js. -If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. +"These field(s) ("invalid",) are not recognized in docusaurus.config.js. +If you still want these fields to be in your configuration, put them in the "customFields" field. See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap index 9979705a3132..391f3f0530c9 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/routes.test.ts.snap @@ -102,17 +102,17 @@ export default [ path: '/docs/hello', component: ComponentCreator('/docs/hello', 'fcc'), exact: true, - sidebar: \\"main\\" + sidebar: "main" }, { path: 'docs/foo/baz', component: ComponentCreator('docs/foo/baz', 'eb2'), - sidebar: \\"secondary\\", - \\"key:a\\": \\"containing colon\\", - \\"key'b\\": \\"containing quote\\", - \\"key\\\\\\"c\\": \\"containing double quote\\", - \\"key,d\\": \\"containing comma\\", - 字段: \\"containing unicode\\" + sidebar: "secondary", + "key:a": "containing colon", + "key'b": "containing quote", + "key\\"c": "containing double quote", + "key,d": "containing comma", + 字段: "containing unicode" } ] }, diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts index 12b4be64152f..4965d60f5a05 100644 --- a/packages/docusaurus/src/server/__tests__/config.test.ts +++ b/packages/docusaurus/src/server/__tests__/config.test.ts @@ -53,7 +53,7 @@ describe('loadSiteConfig', () => { customConfigFilePath: 'incomplete.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot(` - "\\"url\\" is required + ""url" is required " `); }); @@ -65,8 +65,8 @@ describe('loadSiteConfig', () => { customConfigFilePath: 'wrong.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot(` - "These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js. - If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. + "These field(s) ("useLessField",) are not recognized in docusaurus.config.js. + If you still want these fields to be in your configuration, put them in the "customFields" field. See https://docusaurus.io/docs/api/docusaurus-config/#customfields" `); }); @@ -78,7 +78,7 @@ describe('loadSiteConfig', () => { customConfigFilePath: 'nonExistent.config.js', }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Config file at \\"/packages/docusaurus/src/server/__tests__/__fixtures__/config/nonExistent.config.js\\" not found."`, + `"Config file at "/packages/docusaurus/src/server/__tests__/__fixtures__/config/nonExistent.config.js" not found."`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 1f8838efa7fc..3a564f9ce3f3 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -227,7 +227,7 @@ describe('normalizeConfig', () => { themes: {}, }); }).toThrowErrorMatchingInlineSnapshot(` - "\\"themes\\" must be an array + ""themes" must be an array " `); }); @@ -238,7 +238,7 @@ describe('normalizeConfig', () => { presets: {}, }); }).toThrowErrorMatchingInlineSnapshot(` - "\\"presets\\" must be an array + ""presets" must be an array " `); }); @@ -249,9 +249,9 @@ describe('normalizeConfig', () => { presets: [() => {}], }); }).toThrowErrorMatchingInlineSnapshot(` - "\\"presets[0]\\" does not look like a valid preset config. A preset config entry should be one of: - - A tuple of [presetName, options], like \`[\\"classic\\", { blog: false }]\`, or - - A simple string, like \`\\"classic\\"\` + ""presets[0]" does not look like a valid preset config. A preset config entry should be one of: + - A tuple of [presetName, options], like \`["classic", { blog: false }]\`, or + - A simple string, like \`"classic"\` " `); }); @@ -270,7 +270,7 @@ describe('normalizeConfig', () => { scripts: ['https://some.com', {}], }); }).toThrowErrorMatchingInlineSnapshot(` - "\\"scripts[1]\\" is invalid. A script must be a plain string (the src), or an object with at least a \\"src\\" property. + ""scripts[1]" is invalid. A script must be a plain string (the src), or an object with at least a "src" property. " `); }); @@ -281,7 +281,7 @@ describe('normalizeConfig', () => { stylesheets: ['https://somescript.com', {type: 'text/css'}], }); }).toThrowErrorMatchingInlineSnapshot(` - "\\"stylesheets[1]\\" is invalid. A stylesheet must be a plain string (the href), or an object with at least a \\"href\\" property. + ""stylesheets[1]" is invalid. A stylesheet must be a plain string (the href), or an object with at least a "href" property. " `); }); @@ -318,7 +318,7 @@ describe('config warnings', () => { expect(warning).toBeDefined(); expect(warning.details).toHaveLength(1); expect(warning.details[0].message).toMatchInlineSnapshot( - `"Docusaurus config validation warning. Field \\"url\\": the url is not supposed to contain a sub-path like '/someSubpath', please use the baseUrl field for sub-paths"`, + `"Docusaurus config validation warning. Field "url": the url is not supposed to contain a sub-path like '/someSubpath', please use the baseUrl field for sub-paths"`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/htmlTags.test.ts b/packages/docusaurus/src/server/__tests__/htmlTags.test.ts index 6f7172df2aab..d701d23f1b57 100644 --- a/packages/docusaurus/src/server/__tests__/htmlTags.test.ts +++ b/packages/docusaurus/src/server/__tests__/htmlTags.test.ts @@ -99,9 +99,9 @@ describe('loadHtmlTags', () => { const htmlTags = loadHtmlTags([pluginHeadTags]); expect(htmlTags).toMatchInlineSnapshot(` { - "headTags": " - - ", + "headTags": " + + ", "postBodyTags": "", "preBodyTags": "", } @@ -114,7 +114,7 @@ describe('loadHtmlTags', () => { { "headTags": "", "postBodyTags": "", - "preBodyTags": "", + "preBodyTags": "", } `); }); @@ -139,12 +139,12 @@ describe('loadHtmlTags', () => { ]); expect(htmlTags).toMatchInlineSnapshot(` { - "headTags": " - - ", + "headTags": " + + ", "postBodyTags": "
    Test content
    ", - "preBodyTags": "", + "preBodyTags": "", } `); }); @@ -158,9 +158,9 @@ describe('loadHtmlTags', () => { ]); expect(htmlTags).toMatchInlineSnapshot(` { - "headTags": " - - ", + "headTags": " + + ", "postBodyTags": "
    Test content
    ", "preBodyTags": "", @@ -184,7 +184,7 @@ describe('loadHtmlTags', () => { }, ]), ).toThrowErrorMatchingInlineSnapshot( - `"Error loading {\\"tagName\\":\\"endiliey\\",\\"attributes\\":{\\"this\\":\\"is invalid\\"}}, \\"endiliey\\" is not a valid HTML tag."`, + `"Error loading {"tagName":"endiliey","attributes":{"this":"is invalid"}}, "endiliey" is not a valid HTML tag."`, ); }); @@ -202,7 +202,7 @@ describe('loadHtmlTags', () => { }, ]), ).toThrowErrorMatchingInlineSnapshot( - `"{\\"tagName\\":true} is not a valid HTML tag object. \\"tagName\\" must be defined as a string."`, + `"{"tagName":true} is not a valid HTML tag object. "tagName" must be defined as a string."`, ); }); @@ -218,7 +218,7 @@ describe('loadHtmlTags', () => { }, ]), ).toThrowErrorMatchingInlineSnapshot( - `"\\"2\\" is not a valid HTML tag object."`, + `""2" is not a valid HTML tag object."`, ); }); }); diff --git a/packages/docusaurus/src/server/__tests__/routes.test.ts b/packages/docusaurus/src/server/__tests__/routes.test.ts index b18f0ccca679..a2f22058da4b 100644 --- a/packages/docusaurus/src/server/__tests__/routes.test.ts +++ b/packages/docusaurus/src/server/__tests__/routes.test.ts @@ -183,9 +183,9 @@ describe('loadRoutes', () => { expect(() => loadRoutes([routeConfigWithoutPath], '/', 'ignore')) .toThrowErrorMatchingInlineSnapshot(` - "Invalid route config: path must be a string and component is required. - {\\"component\\":\\"hello/world.js\\"}" - `); + "Invalid route config: path must be a string and component is required. + {"component":"hello/world.js"}" + `); const routeConfigWithoutComponent = { path: '/hello/world', @@ -193,9 +193,9 @@ describe('loadRoutes', () => { expect(() => loadRoutes([routeConfigWithoutComponent], '/', 'ignore')) .toThrowErrorMatchingInlineSnapshot(` - "Invalid route config: path must be a string and component is required. - {\\"path\\":\\"/hello/world\\"}" - `); + "Invalid route config: path must be a string and component is required. + {"path":"/hello/world"}" + `); }); it('loads route config with empty (but valid) path string', () => { diff --git a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts index 12c62dcd54cd..d33e301382be 100644 --- a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts +++ b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts @@ -55,11 +55,10 @@ describe('loadSiteMetadata', () => { siteDir: path.join(__dirname, '__fixtures__/siteMetadata'), }), ).resolves.toMatchSnapshot(); - // cSpell:ignore mdocusaurus expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(` - "[ERROR] Invalid docusaurus-plugin-content-docs version 1.0.0. - All official @docusaurus/* packages should have the exact same version as @docusaurus/core (). - Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?" + "[ERROR] Invalid docusaurus-plugin-content-docs version 1.0.0. + All official @docusaurus/* packages should have the exact same version as @docusaurus/core (). + Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?" `); }); }); diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap index 3c982b11453f..b900cdd18224 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/init.test.ts.snap @@ -5,9 +5,9 @@ exports[`initPlugins throws user-friendly error message for plugins with bad val Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], @@ -17,9 +17,9 @@ Example valid plugin config: Example valid plugin config: { plugins: [ - [\\"@docusaurus/plugin-content-docs\\",options], - \\"./myPlugin\\", - [\\"./myPlugin\\",{someOption: 42}], + ["@docusaurus/plugin-content-docs",options], + "./myPlugin", + ["./myPlugin",{someOption: 42}], function myPlugin() { }, [function myPlugin() { },options] ], diff --git a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/pluginIds.test.ts.snap b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/pluginIds.test.ts.snap index 4952facb6eaf..c8b4f56954da 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/pluginIds.test.ts.snap +++ b/packages/docusaurus/src/server/plugins/__tests__/__snapshots__/pluginIds.test.ts.snap @@ -1,20 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ensureUniquePluginInstanceIds reject multi instance plugins with same id 1`] = ` -"Plugin \\"plugin-docs\\" is used 2 times with ID \\"sameId\\". +"Plugin "plugin-docs" is used 2 times with ID "sameId". To use the same plugin multiple times on a Docusaurus site, you need to assign a unique ID to each plugin instance." `; exports[`ensureUniquePluginInstanceIds reject multi instance plugins with some without id 1`] = ` -"Plugin \\"plugin-docs\\" is used 2 times with ID \\"default\\". +"Plugin "plugin-docs" is used 2 times with ID "default". To use the same plugin multiple times on a Docusaurus site, you need to assign a unique ID to each plugin instance. -The plugin ID is \\"default\\" by default. It's possible that the preset you are using already includes a plugin instance, in which case you either want to disable the plugin in the preset (to use a single instance), or assign another ID to your extra plugin instance (to use multiple instances)." +The plugin ID is "default" by default. It's possible that the preset you are using already includes a plugin instance, in which case you either want to disable the plugin in the preset (to use a single instance), or assign another ID to your extra plugin instance (to use multiple instances)." `; exports[`ensureUniquePluginInstanceIds reject multi instance plugins without id 1`] = ` -"Plugin \\"plugin-docs\\" is used 2 times with ID \\"default\\". +"Plugin "plugin-docs" is used 2 times with ID "default". To use the same plugin multiple times on a Docusaurus site, you need to assign a unique ID to each plugin instance. -The plugin ID is \\"default\\" by default. It's possible that the preset you are using already includes a plugin instance, in which case you either want to disable the plugin in the preset (to use a single instance), or assign another ID to your extra plugin instance (to use multiple instances)." +The plugin ID is "default" by default. It's possible that the preset you are using already includes a plugin instance, in which case you either want to disable the plugin in the preset (to use a single instance), or assign another ID to your extra plugin instance (to use multiple instances)." `; diff --git a/packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts b/packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts index 239811e3427b..c149e117d8d5 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/moduleShorthand.test.ts @@ -72,7 +72,7 @@ describe('resolveModuleName', () => { expect(() => resolveModuleName('@docusaurus/plugin-content-doc', require, 'plugin'), ).toThrowErrorMatchingInlineSnapshot(` - "Docusaurus was unable to resolve the \\"@docusaurus/plugin-content-doc\\" plugin. Make sure one of the following packages are installed: + "Docusaurus was unable to resolve the "@docusaurus/plugin-content-doc" plugin. Make sure one of the following packages are installed: - @docusaurus/plugin-content-doc - @docusaurus/docusaurus-plugin-plugin-content-doc" `); @@ -81,7 +81,7 @@ describe('resolveModuleName', () => { it('throws good error message for shorthand', () => { expect(() => resolveModuleName('content-doc', require, 'plugin')) .toThrowErrorMatchingInlineSnapshot(` - "Docusaurus was unable to resolve the \\"content-doc\\" plugin. Make sure one of the following packages are installed: + "Docusaurus was unable to resolve the "content-doc" plugin. Make sure one of the following packages are installed: - content-doc - @docusaurus/plugin-content-doc - docusaurus-plugin-content-doc" diff --git a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts index b4dda430760b..89240e3ea05e 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translations.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translations.test.ts @@ -259,10 +259,11 @@ describe('writeCodeTranslations', () => { { key1: {message: 'key1 message'}, }, + {}, ), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"bad\\" must be of type object"`, + `""bad" must be of type object"`, ); }); }); @@ -403,7 +404,7 @@ describe('writePluginTranslations', () => { options: {}, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Translation file path at \\"my/translation/file.json\\" does not need to end with \\".json\\", we add the extension automatically."`, + `"Translation file path at "my/translation/file.json" does not need to end with ".json", we add the extension automatically."`, ); }); }); @@ -522,29 +523,27 @@ describe('readCodeTranslationFileContent', () => { await expect(() => testReadTranslation('HEY'), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, + `""value" must be of type object"`, ); await expect(() => testReadTranslation(42), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"value\\" must be of type object"`, + `""value" must be of type object"`, ); await expect(() => testReadTranslation({key: {description: 'no message'}}), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"key.message\\" is required"`, - ); + ).rejects.toThrowErrorMatchingInlineSnapshot(`""key.message" is required"`); await expect(() => testReadTranslation({key: {message: 42}}), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"key.message\\" must be a string"`, + `""key.message" must be a string"`, ); await expect(() => testReadTranslation({ key: {message: 'Message', description: 42}, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `"\\"key.description\\" must be a string"`, + `""key.description" must be a string"`, ); }); }); diff --git a/packages/docusaurus/src/webpack/__tests__/utils.test.ts b/packages/docusaurus/src/webpack/__tests__/utils.test.ts index 1a388ed4e4f8..afcc1477f782 100644 --- a/packages/docusaurus/src/webpack/__tests__/utils.test.ts +++ b/packages/docusaurus/src/webpack/__tests__/utils.test.ts @@ -335,7 +335,7 @@ describe('getHttpsConfig', () => { ); process.env.SSL_KEY_FILE = path.join(__dirname, '__fixtures__/host.key'); await expect(getHttpsConfig()).rejects.toThrowErrorMatchingInlineSnapshot( - `"You specified SSL_CRT_FILE in your env, but the file \\"/packages/docusaurus/src/webpack/__tests__/__fixtures__/nonexistent.crt\\" can't be found."`, + `"You specified SSL_CRT_FILE in your env, but the file "/packages/docusaurus/src/webpack/__tests__/__fixtures__/nonexistent.crt" can't be found."`, ); }); From 171927342fca8dafe77093bf5dbc8e81df9055f2 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Fri, 8 Apr 2022 17:08:22 +0800 Subject: [PATCH 135/405] feat(core): fail-safe global data fetching (#7083) --- .../src/index.d.ts | 8 ++++--- .../src/client/docsClientUtils.ts | 4 ++-- .../src/client/index.ts | 23 +++++++++++-------- .../src/plugin-content-docs.d.ts | 7 +++--- packages/docusaurus-types/src/index.d.ts | 8 +++++++ .../exports/__tests__/useGlobalData.test.tsx | 4 ++-- .../src/client/exports/useGlobalData.ts | 12 ++++++---- website/docs/docusaurus-core.md | 11 +++++++-- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 9d98309ef69c..dc196b86f210 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -315,16 +315,18 @@ declare module '@docusaurus/renderRoutes' { } declare module '@docusaurus/useGlobalData' { - import type {GlobalData} from '@docusaurus/types'; + import type {GlobalData, UseDataOptions} from '@docusaurus/types'; export function useAllPluginInstancesData( pluginName: string, - ): GlobalData[string]; + options?: UseDataOptions, + ): GlobalData[string] | undefined; export function usePluginData( pluginName: string, pluginId?: string, - ): GlobalData[string][string]; + options?: UseDataOptions, + ): GlobalData[string][string] | undefined; export default function useGlobalData(): GlobalData; } diff --git a/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts b/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts index 1a07cd180735..a6e3359fc52f 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/docsClientUtils.ts @@ -11,11 +11,11 @@ import type { GlobalPluginData, GlobalVersion, GlobalDoc, - GetActivePluginOptions, ActivePlugin, ActiveDocContext, DocVersionSuggestions, } from '@docusaurus/plugin-content-docs/client'; +import type {UseDataOptions} from '@docusaurus/types'; // This code is not part of the api surface, not in ./theme on purpose @@ -25,7 +25,7 @@ import type { export function getActivePlugin( allPluginData: {[pluginId: string]: GlobalPluginData}, pathname: string, - options: GetActivePluginOptions = {}, + options: UseDataOptions = {}, ): ActivePlugin | undefined { const activeEntry = Object.entries(allPluginData) // Route sorting: '/android/foo' should match '/android' instead of '/' diff --git a/packages/docusaurus-plugin-content-docs/src/client/index.ts b/packages/docusaurus-plugin-content-docs/src/client/index.ts index 803456fbbe7d..4923a069d0a6 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/index.ts @@ -6,7 +6,10 @@ */ import {useLocation} from '@docusaurus/router'; -import useGlobalData, {usePluginData} from '@docusaurus/useGlobalData'; +import { + useAllPluginInstancesData, + usePluginData, +} from '@docusaurus/useGlobalData'; import { getActivePlugin, @@ -21,25 +24,27 @@ import type { ActivePlugin, ActiveDocContext, DocVersionSuggestions, - GetActivePluginOptions, } from '@docusaurus/plugin-content-docs/client'; +import type {UseDataOptions} from '@docusaurus/types'; // Important to use a constant object to avoid React useEffect executions etc. // see https://github.com/facebook/docusaurus/issues/5089 const StableEmptyObject = {}; -// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks -// are still used by the theme. We need a fail-safe fallback when the docs -// plugin is not in use +// In blog-only mode, docs hooks are still used by the theme. We need a fail- +// safe fallback when the docs plugin is not in use export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} => - useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject; + useAllPluginInstancesData('docusaurus-plugin-content-docs') ?? + StableEmptyObject; export const useDocsData = (pluginId: string | undefined): GlobalPluginData => - usePluginData('docusaurus-plugin-content-docs', pluginId) as GlobalPluginData; + usePluginData('docusaurus-plugin-content-docs', pluginId, { + failfast: true, + }) as GlobalPluginData; // TODO this feature should be provided by docusaurus core export const useActivePlugin = ( - options: GetActivePluginOptions = {}, + options: UseDataOptions = {}, ): ActivePlugin | undefined => { const data = useAllDocsData(); const {pathname} = useLocation(); @@ -47,7 +52,7 @@ export const useActivePlugin = ( }; export const useActivePluginAndVersion = ( - options: GetActivePluginOptions = {}, + options: UseDataOptions = {}, ): | undefined | {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined} => { diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 77d4b7b894c0..7bc5a2419430 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -612,6 +612,8 @@ declare module '@theme/DocPage/Layout/Main' { // TODO until TS supports exports field... hope it's in 4.6 declare module '@docusaurus/plugin-content-docs/client' { + import type {UseDataOptions} from '@docusaurus/types'; + export type ActivePlugin = { pluginId: string; pluginData: GlobalPluginData; @@ -655,15 +657,14 @@ declare module '@docusaurus/plugin-content-docs/client' { // suggest the same doc, in latest version (if exist) latestDocSuggestion?: GlobalDoc; }; - export type GetActivePluginOptions = {failfast?: boolean}; // use fail-fast option if you know for sure one plugin instance is active export const useAllDocsData: () => {[pluginId: string]: GlobalPluginData}; export const useDocsData: (pluginId?: string) => GlobalPluginData; export const useActivePlugin: ( - options?: GetActivePluginOptions, + options?: UseDataOptions, ) => ActivePlugin | undefined; export const useActivePluginAndVersion: ( - options?: GetActivePluginOptions, + options?: UseDataOptions, ) => | {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined} | undefined; diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index e20bd74ee6a5..9c19ac7edcc6 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -619,3 +619,11 @@ export type TagModule = TagsListItem & { /** The tags list page's permalink. */ allTagsPath: string; }; + +export type UseDataOptions = { + /** + * Throw an error, or simply return undefined if the data cannot be found. Use + * `true` if you are sure the data must exist. + */ + failfast?: boolean; +}; diff --git a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx index c2ec645c2887..b688427aa9a5 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx @@ -59,7 +59,7 @@ describe('useAllPluginInstancesData', () => { it('throws when plugin data not found', () => { expect( () => - renderHook(() => useAllPluginInstancesData('bar'), { + renderHook(() => useAllPluginInstancesData('bar', {failfast: true}), { wrapper: ({children}) => ( { it('throws when plugin instance data not found', () => { expect( () => - renderHook(() => usePluginData('foo', 'baz'), { + renderHook(() => usePluginData('foo', 'baz', {failfast: true}), { wrapper: ({children}) => ( { Access global data created by a specific plugin. Given a plugin name, it returns the data of all the plugins instances of that name, by plugin id. ```ts -useAllPluginInstancesData(pluginName: string) +function useAllPluginInstancesData( + pluginName: string, + options?: {failfast?: boolean}, +); ``` Usage example: From 3e110054d72fa2b33bad4175bdc8739e51008f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 8 Apr 2022 12:41:00 +0200 Subject: [PATCH 136/405] fix(theme-classic): fix docs sidebar layout shifts when expanding categories (#7134) --- .../src/theme/DocSidebar/Desktop/Content/styles.module.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css index 1ee104b73adb..8d8c7e88cbe6 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/Desktop/Content/styles.module.css @@ -10,6 +10,12 @@ flex-grow: 1; padding: 0.5rem; } + @supports (scrollbar-gutter: stable) { + .menu { + padding: 0.5rem 0 0.5rem 0.5rem; + scrollbar-gutter: stable; + } + } .menuWithAnnouncementBar { margin-bottom: var(--docusaurus-announcement-bar-height); From 7941a46be3085e2555a22e21a2ec8d55c81a1086 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Fri, 8 Apr 2022 22:34:34 +0800 Subject: [PATCH 137/405] feat: allow setting calendar for i18n date formatting (#6430) * feat: allow setting calendar for i18n date formatting * fix TS * add test --- .../src/__tests__/feed.test.ts | 6 ++++- .../src/__tests__/index.test.ts | 2 +- .../src/blogUtils.ts | 13 +++++++++-- .../src/docs.ts | 6 ++--- packages/docusaurus-types/src/index.d.ts | 1 + .../src/server/__tests__/i18n.test.ts | 22 ++++++++++++++++++- .../docusaurus/src/server/configValidation.ts | 1 + packages/docusaurus/src/server/i18n.ts | 2 ++ website/docs/api/docusaurus.config.js.md | 13 +++++++---- 9 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index facf967523db..f7d31a7dbbb0 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -19,7 +19,11 @@ const DefaultI18N: I18n = { currentLocale: 'en', locales: ['en'], defaultLocale: 'en', - localeConfigs: {}, + localeConfigs: { + en: { + calendar: 'gregory', + }, + }, }; function getBlogContentPaths(siteDir: string): BlogContentPaths { diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 2a197366835e..79ec1bb2b010 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -41,7 +41,7 @@ function getI18n(locale: string): I18n { currentLocale: locale, locales: [locale], defaultLocale: locale, - localeConfigs: {}, + localeConfigs: {[locale]: {calendar: 'gregory'}}, }; } diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 8138d1ab8b00..6b839cee9d42 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -151,13 +151,18 @@ export function parseBlogFileName( return {date: undefined, text, slug}; } -function formatBlogPostDate(locale: string, date: Date): string { +function formatBlogPostDate( + locale: string, + date: Date, + calendar: string, +): string { try { return new Intl.DateTimeFormat(locale, { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC', + calendar, }).format(date); } catch (err) { logger.error`Can't format blog post date "${String(date)}"`; @@ -253,7 +258,11 @@ async function processBlogSourceFile( } const date = await getDate(); - const formattedDate = formatBlogPostDate(i18n.currentLocale, date); + const formattedDate = formatBlogPostDate( + i18n.currentLocale, + date, + i18n.localeConfigs[i18n.currentLocale]!.calendar, + ); const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text; const description = frontMatter.description ?? excerpt ?? ''; diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index ee247ec0a97a..c5057800f3c9 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -254,9 +254,9 @@ function doProcessDocMetadata({ lastUpdatedBy: lastUpdate.lastUpdatedBy, lastUpdatedAt: lastUpdate.lastUpdatedAt, formattedLastUpdatedAt: lastUpdate.lastUpdatedAt - ? new Intl.DateTimeFormat(i18n.currentLocale).format( - lastUpdate.lastUpdatedAt * 1000, - ) + ? new Intl.DateTimeFormat(i18n.currentLocale, { + calendar: i18n.localeConfigs[i18n.currentLocale]!.calendar, + }).format(lastUpdate.lastUpdatedAt * 1000) : undefined, sidebarPosition, frontMatter, diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 9c19ac7edcc6..348a3ded439e 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -45,6 +45,7 @@ export type I18nLocaleConfig = { label: string; htmlLang: string; direction: string; + calendar: string; }; export type I18nConfig = { diff --git a/packages/docusaurus/src/server/__tests__/i18n.test.ts b/packages/docusaurus/src/server/__tests__/i18n.test.ts index 258adfbe7c65..5142d0972fbb 100644 --- a/packages/docusaurus/src/server/__tests__/i18n.test.ts +++ b/packages/docusaurus/src/server/__tests__/i18n.test.ts @@ -32,48 +32,63 @@ describe('defaultLocaleConfig', () => { label: 'Français', direction: 'ltr', htmlLang: 'fr', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('fr-FR')).toEqual({ label: 'Français (France)', direction: 'ltr', htmlLang: 'fr-FR', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('en')).toEqual({ label: 'English', direction: 'ltr', htmlLang: 'en', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('en-US')).toEqual({ label: 'American English', direction: 'ltr', htmlLang: 'en-US', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('zh')).toEqual({ label: '中文', direction: 'ltr', htmlLang: 'zh', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('zh-CN')).toEqual({ label: '中文(中国)', direction: 'ltr', htmlLang: 'zh-CN', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('en-US')).toEqual({ label: 'American English', direction: 'ltr', htmlLang: 'en-US', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('fa')).toEqual({ // cSpell:ignore فارسی label: 'فارسی', direction: 'rtl', htmlLang: 'fa', + calendar: 'gregory', }); expect(getDefaultLocaleConfig('fa-IR')).toEqual({ // cSpell:ignore ایران فارسیا label: 'فارسی (ایران)', direction: 'rtl', htmlLang: 'fa-IR', + calendar: 'gregory', + }); + expect(getDefaultLocaleConfig('en-US-u-ca-buddhist')).toEqual({ + label: 'American English', + direction: 'ltr', + htmlLang: 'en-US-u-ca-buddhist', + calendar: 'buddhist', }); }); }); @@ -144,7 +159,12 @@ describe('loadI18n', () => { locales: ['en', 'fr', 'de'], currentLocale: 'de', localeConfigs: { - fr: {label: 'Français', direction: 'ltr', htmlLang: 'fr'}, + fr: { + label: 'Français', + direction: 'ltr', + htmlLang: 'fr', + calendar: 'gregory', + }, en: getDefaultLocaleConfig('en'), de: getDefaultLocaleConfig('de'), }, diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 74f3836b0e9f..007c3d1d5b34 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -131,6 +131,7 @@ const LocaleConfigSchema = Joi.object({ label: Joi.string(), htmlLang: Joi.string(), direction: Joi.string().equal('ltr', 'rtl').default('ltr'), + calendar: Joi.string(), }); const I18N_CONFIG_SCHEMA = Joi.object({ diff --git a/packages/docusaurus/src/server/i18n.ts b/packages/docusaurus/src/server/i18n.ts index b2d5dfe570cc..57f639c14098 100644 --- a/packages/docusaurus/src/server/i18n.ts +++ b/packages/docusaurus/src/server/i18n.ts @@ -24,6 +24,8 @@ export function getDefaultLocaleConfig(locale: string): I18nLocaleConfig { label: getDefaultLocaleLabel(locale), direction: getLangDir(locale), htmlLang: locale, + // If the locale name includes -u-ca-xxx the calendar will be defined + calendar: new Intl.Locale(locale).calendar ?? 'gregory', }; } diff --git a/website/docs/api/docusaurus.config.js.md b/website/docs/api/docusaurus.config.js.md index 5a52885277b7..932dd352ea4f 100644 --- a/website/docs/api/docusaurus.config.js.md +++ b/website/docs/api/docusaurus.config.js.md @@ -124,6 +124,8 @@ The i18n configuration object to [localize your site](../i18n/i18n-introduction. Example: + + ```js title="docusaurus.config.js" module.exports = { i18n: { @@ -134,11 +136,13 @@ module.exports = { label: 'English', direction: 'ltr', htmlLang: 'en-US', + calendar: 'gregory', }, - fr: { - label: 'Français', - direction: 'ltr', - htmlLang: 'fr-FR', + fa: { + label: 'فارسی', + direction: 'rtl', + htmlLang: 'fa-IR', + calendar: 'persian', }, }, }, @@ -148,6 +152,7 @@ module.exports = { - `label`: the label to use for this locale - `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Arabic, Hebrew, etc.) - `htmlLang`: BCP 47 language tag to use in `` and in `` +- `calendar`: the [calendar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar) used to calculate the date era. Note that it doesn't control the actual string displayed: `MM/DD/YYYY` and `DD/MM/YYYY` are both `gregory`. To choose the format (`DD/MM/YYYY` or `MM/DD/YYYY`), set your locale name to `en-GB` or `en-US` (`en` means `en-US`). ### `noIndex` {#noindex} From d5cfa5b7cf85817766082061a7d6044747e55f26 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Sat, 9 Apr 2022 03:27:22 +0300 Subject: [PATCH 138/405] refactor(theme-classic): fix a few margin inconsistencies (#7129) * refactor(theme-classic): minor fixes and improvements * Fixes after review * Reset spacing for all children inside browser window --- .../docusaurus-theme-classic/src/theme-classic.d.ts | 1 + .../src/theme/BlogSidebar/Desktop/styles.module.css | 1 + .../src/theme/DocCardList/index.tsx | 10 ++++------ .../src/theme/DocCategoryGeneratedIndexPage/index.tsx | 2 +- .../DocCategoryGeneratedIndexPage/styles.module.css | 4 ++++ .../src/theme/DocItem/styles.module.css | 6 ++++++ .../NavbarItem/LocaleDropdownNavbarItem/index.tsx | 2 +- .../src/theme/TabItem/index.tsx | 8 +++++++- .../src/theme/TabItem/styles.module.css | 10 ++++++++++ .../docusaurus-theme-classic/src/theme/Tabs/index.tsx | 6 +++--- .../src/theme/Tabs/styles.module.css | 4 ++++ .../src/components/Details/styles.module.css | 4 ++++ .../markdown-features/markdown-features-tabs.mdx | 1 - 13 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/TabItem/styles.module.css diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 7c0deb7dc60a..08475210a920 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -176,6 +176,7 @@ declare module '@theme/DocCardList' { export interface Props { readonly items: PropSidebarItem[]; + readonly className?: string; } export default function DocCardList(props: Props): JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css index 3ca0d4b8d5e7..cf147cd4e369 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/styles.module.css @@ -29,6 +29,7 @@ .sidebarItemLink { color: var(--ifm-font-color-base); + display: block; } .sidebarItemLink:hover { diff --git a/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx index 052e88292523..3cd1425daf2b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocCardList/index.tsx @@ -6,10 +6,12 @@ */ import React from 'react'; +import clsx from 'clsx'; import DocCard from '@theme/DocCard'; import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; import {findFirstCategoryLink} from '@docusaurus/theme-common'; +import type {Props} from '@theme/DocCardList'; // Filter categories that don't have a link. function filterItems(items: PropSidebarItem[]): PropSidebarItem[] { @@ -21,13 +23,9 @@ function filterItems(items: PropSidebarItem[]): PropSidebarItem[] { }); } -export default function DocCardList({ - items, -}: { - items: PropSidebarItem[]; -}): JSX.Element { +export default function DocCardList({items, className}: Props): JSX.Element { return ( -
    +
    {filterItems(items).map((item, index) => (
    diff --git a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx index 179839ac09cc..8f58116ead34 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage/index.tsx @@ -61,7 +61,7 @@ function DocCategoryGeneratedIndexPageContent({ )}
    - +