refactor: import jest as global; unify import style of some modules (#6898)

* refactor: import jest as global

* fix react
This commit is contained in:
Joshua Chen 2022-03-11 19:04:27 +08:00 committed by GitHub
parent e97dc0d37e
commit c9ee6e467c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 177 additions and 139 deletions

View file

@ -166,7 +166,12 @@ module.exports = {
// selector: // selector:
// @ 'ExportDefaultDeclaration > Identifier, ExportNamedDeclaration[source=null] > ExportSpecifier', // @ 'ExportDefaultDeclaration > Identifier, ExportNamedDeclaration[source=null] > ExportSpecifier',
// message: 'Export in one statement' // 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-template-curly-in-string': WARNING,
'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}], 'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}],
@ -312,5 +317,11 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': OFF, '@typescript-eslint/explicit-module-boundary-types': OFF,
}, },
}, },
{
files: ['*.test.ts', '*.test.tsx'],
rules: {
'import/no-extraneous-dependencies': OFF,
},
},
], ],
}; };

View file

@ -4,7 +4,6 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/* eslint-disable import/no-extraneous-dependencies */
import {Globby} from '@docusaurus/utils'; import {Globby} from '@docusaurus/utils';
import fs from 'fs-extra'; import fs from 'fs-extra';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import logger from '../index'; import logger from '../index';
describe('formatters', () => { describe('formatters', () => {

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import remark from 'remark'; import remark from 'remark';
import mdx from 'remark-mdx'; import mdx from 'remark-mdx';

View file

@ -5,22 +5,20 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {join} from 'path'; import path from 'path';
import remark from 'remark'; import remark from 'remark';
import mdx from 'remark-mdx'; import mdx from 'remark-mdx';
import vfile from 'to-vfile'; import vfile from 'to-vfile';
import plugin from '..'; import plugin from '..';
const processFixture = async (name) => { const processFixture = async (name: string) => {
const path = join(__dirname, '__fixtures__', name); const file = await vfile.read(path.join(__dirname, '__fixtures__', name));
const file = await vfile.read(path);
const result = await remark().use(mdx).use(plugin).process(file); const result = await remark().use(mdx).use(plugin).process(file);
return result.toString(); return result.toString();
}; };
const processFixtureAST = async (name) => { const processFixtureAST = async (name: string) => {
const path = join(__dirname, '__fixtures__', name); const file = await vfile.read(path.join(__dirname, '__fixtures__', name));
const file = await vfile.read(path);
return remark().use(mdx).use(plugin).parse(file); return remark().use(mdx).use(plugin).parse(file);
}; };

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {migrateDocusaurusProject} from '../index'; import {migrateDocusaurusProject} from '../index';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import {createBlogFeedFiles} from '../feed'; import {createBlogFeedFiles} from '../feed';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import pluginContentBlog from '../index'; import pluginContentBlog from '../index';
import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types'; import type {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import {linkify, type LinkifyParams, getSourceToPermalink} from '../blogUtils'; import {linkify, type LinkifyParams, getSourceToPermalink} from '../blogUtils';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import {cliDocsVersionCommand} from '../cli'; import {cliDocsVersionCommand} from '../cli';
import type { import type {

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import {loadContext} from '@docusaurus/core/src/server/index'; import {loadContext} from '@docusaurus/core/src/server/index';
import { import {

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import {isMatch} from 'picomatch'; import {isMatch} from 'picomatch';
import commander from 'commander'; import commander from 'commander';
@ -29,7 +30,7 @@ import type {
} from '../sidebars/types'; } from '../sidebars/types';
import {toSidebarsProp} from '../props'; import {toSidebarsProp} from '../props';
import {validate} from 'webpack'; import webpack from 'webpack';
import {DefaultSidebarItemsGenerator} from '../sidebars/generator'; import {DefaultSidebarItemsGenerator} from '../sidebars/generator';
import {DisabledSidebars} from '../sidebars'; import {DisabledSidebars} from '../sidebars';
@ -311,7 +312,7 @@ describe('simple website', () => {
undefined, undefined,
content, content,
); );
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import shell from 'shelljs'; import shell from 'shelljs';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import { import {
getVersionsFilePath, getVersionsFilePath,

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import {linkify} from '../linkify'; import {linkify} from '../linkify';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {DefaultSidebarItemsGenerator} from '../generator'; import {DefaultSidebarItemsGenerator} from '../generator';
import type {SidebarItemsGenerator} from '../types'; import type {SidebarItemsGenerator} from '../types';
import {DefaultNumberPrefixParser} from '../../numberPrefix'; import {DefaultNumberPrefixParser} from '../../numberPrefix';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {processSidebars} from '../processor'; import {processSidebars} from '../processor';
import type { import type {
SidebarItem, SidebarItem,

View file

@ -6,8 +6,8 @@
*/ */
import React, { import React, {
type ComponentProps,
isValidElement, isValidElement,
type ComponentProps,
type ReactElement, type ReactElement,
} from 'react'; } from 'react';
import Head from '@docusaurus/Head'; import Head from '@docusaurus/Head';
@ -52,7 +52,7 @@ const MDXComponents: MDXComponentsObject = {
const shouldBeInline = React.Children.toArray(props.children).every( const shouldBeInline = React.Children.toArray(props.children).every(
(el) => (el) =>
(typeof el === 'string' && !el.includes('\n')) || (typeof el === 'string' && !el.includes('\n')) ||
(React.isValidElement(el) && inlineElements.includes(el.props.mdxType)), (isValidElement(el) && inlineElements.includes(el.props.mdxType)),
); );
return shouldBeInline ? <code {...props} /> : <CodeBlock {...props} />; return shouldBeInline ? <code {...props} /> : <CodeBlock {...props} />;

View file

@ -8,7 +8,6 @@
import React, { import React, {
useState, useState,
cloneElement, cloneElement,
Children,
isValidElement, isValidElement,
type ReactElement, type ReactElement,
} from 'react'; } from 'react';
@ -40,7 +39,7 @@ function TabsComponent(props: Props): JSX.Element {
groupId, groupId,
className, className,
} = props; } = props;
const children = Children.map(props.children, (child) => { const children = React.Children.map(props.children, (child) => {
if (isValidElement(child) && isTabItem(child)) { if (isValidElement(child) && isTabItem(child)) {
return child; return child;
} }

View file

@ -11,11 +11,11 @@ import React, {
useEffect, useEffect,
useRef, useRef,
useCallback, useCallback,
useLayoutEffect,
type RefObject, type RefObject,
type Dispatch, type Dispatch,
type SetStateAction, type SetStateAction,
type ReactNode, type ReactNode,
useLayoutEffect,
} from 'react'; } from 'react';
const DefaultAnimationEasing = 'ease-in-out'; const DefaultAnimationEasing = 'ease-in-out';

View file

@ -6,10 +6,10 @@
*/ */
import React, { import React, {
type ComponentProps,
type ReactElement,
useRef, useRef,
useState, useState,
type ComponentProps,
type ReactElement,
} from 'react'; } from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser'; import useIsBrowser from '@docusaurus/useIsBrowser';
import clsx from 'clsx'; import clsx from 'clsx';

View file

@ -10,9 +10,8 @@ import React, {
useEffect, useEffect,
useCallback, useCallback,
useMemo, useMemo,
type ReactNode,
useContext, useContext,
createContext, type ReactNode,
} from 'react'; } from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser'; import useIsBrowser from '@docusaurus/useIsBrowser';
import {createStorageSlot} from './storageUtils'; import {createStorageSlot} from './storageUtils';
@ -96,7 +95,9 @@ const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
); );
}; };
const AnnouncementBarContext = createContext<AnnouncementBarAPI | null>(null); const AnnouncementBarContext = React.createContext<AnnouncementBarAPI | null>(
null,
);
export function AnnouncementBarProvider({ export function AnnouncementBarProvider({
children, children,

View file

@ -11,6 +11,7 @@ import React, {
useEffect, useEffect,
useContext, useContext,
useMemo, useMemo,
useRef,
type ReactNode, type ReactNode,
} from 'react'; } from 'react';
import {ReactContextError} from './reactUtils'; import {ReactContextError} from './reactUtils';
@ -96,7 +97,7 @@ function useColorModeContextValue(): ColorModeContextValue {
// be reset to dark when exiting print mode, disregarding user settings. When // 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 // the listener fires only because of a print/screen switch, we don't change
// color mode. See https://github.com/facebook/docusaurus/pull/6490 // color mode. See https://github.com/facebook/docusaurus/pull/6490
const previousMediaIsPrint = React.useRef(false); const previousMediaIsPrint = useRef(false);
useEffect(() => { useEffect(() => {
if (disableSwitch && !respectPrefersColorScheme) { if (disableSwitch && !respectPrefersColorScheme) {

View file

@ -6,12 +6,11 @@
*/ */
import React, { import React, {
createContext,
type ReactNode,
useContext, useContext,
useEffect, useEffect,
useMemo, useMemo,
useState, useState,
type ReactNode,
} from 'react'; } from 'react';
import {useThemeConfig, type DocsVersionPersistence} from '../useThemeConfig'; import {useThemeConfig, type DocsVersionPersistence} from '../useThemeConfig';
import {isDocsPluginEnabled} from '../docsUtils'; import {isDocsPluginEnabled} from '../docsUtils';
@ -131,7 +130,9 @@ function useContextValue() {
type DocsPreferredVersionContextValue = ReturnType<typeof useContextValue>; type DocsPreferredVersionContextValue = ReturnType<typeof useContextValue>;
const Context = createContext<DocsPreferredVersionContextValue | null>(null); const Context = React.createContext<DocsPreferredVersionContextValue | null>(
null,
);
export function DocsPreferredVersionContextProvider({ export function DocsPreferredVersionContextProvider({
children, children,

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * 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 { import {
useActivePlugin, useActivePlugin,
useAllDocsData, useAllDocsData,
@ -29,7 +29,7 @@ export const isDocsPluginEnabled: boolean = !!useAllDocsData;
// Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx // Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx
const EmptyContextValue: unique symbol = Symbol('EmptyContext'); const EmptyContextValue: unique symbol = Symbol('EmptyContext');
const DocsVersionContext = createContext< const DocsVersionContext = React.createContext<
PropVersionMetadata | typeof EmptyContextValue PropVersionMetadata | typeof EmptyContextValue
>(EmptyContextValue); >(EmptyContextValue);
@ -69,7 +69,7 @@ export function useDocById(id: string | undefined): PropVersionDoc | undefined {
return doc; return doc;
} }
const DocsSidebarContext = createContext< const DocsSidebarContext = React.createContext<
PropSidebar | null | typeof EmptyContextValue PropSidebar | null | typeof EmptyContextValue
>(EmptyContextValue); >(EmptyContextValue);

View file

@ -7,12 +7,11 @@
import React, { import React, {
useState, useState,
type ReactNode,
useContext, useContext,
createContext,
useEffect, useEffect,
type ComponentType,
useMemo, useMemo,
type ReactNode,
type ComponentType,
} from 'react'; } from 'react';
import {ReactContextError} from './reactUtils'; import {ReactContextError} from './reactUtils';
@ -46,7 +45,7 @@ function useContextValue() {
type ContextValue = ReturnType<typeof useContextValue>; type ContextValue = ReturnType<typeof useContextValue>;
const Context = createContext<ContextValue | null>(null); const Context = React.createContext<ContextValue | null>(null);
export function MobileSecondaryMenuProvider({ export function MobileSecondaryMenuProvider({
children, children,

View file

@ -6,14 +6,13 @@
*/ */
import React, { import React, {
createContext,
type ReactNode,
useCallback, useCallback,
useContext, useContext,
useEffect, useEffect,
useLayoutEffect, useLayoutEffect,
useMemo, useMemo,
useRef, useRef,
type ReactNode,
} from 'react'; } from 'react';
import {useDynamicCallback, ReactContextError} from './reactUtils'; import {useDynamicCallback, ReactContextError} from './reactUtils';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
@ -57,7 +56,7 @@ function useScrollControllerContextValue(): ScrollController {
); );
} }
const ScrollMonitorContext = createContext<ScrollController | undefined>( const ScrollMonitorContext = React.createContext<ScrollController | undefined>(
undefined, undefined,
); );

View file

@ -9,7 +9,6 @@ import React, {
useState, useState,
useCallback, useCallback,
useEffect, useEffect,
createContext,
useMemo, useMemo,
useContext, useContext,
type ReactNode, type ReactNode,
@ -24,7 +23,7 @@ type TabGroupChoiceContextValue = {
readonly setTabGroupChoices: (groupId: string, newChoice: string) => void; readonly setTabGroupChoices: (groupId: string, newChoice: string) => void;
}; };
const TabGroupChoiceContext = createContext< const TabGroupChoiceContext = React.createContext<
TabGroupChoiceContextValue | undefined TabGroupChoiceContextValue | undefined
>(undefined); >(undefined);

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {extractThemeCodeMessages} from '../update'; import {extractThemeCodeMessages} from '../update';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import Joi from '../Joi'; import Joi from '../Joi';
import {JoiFrontMatter} from '../JoiFrontMatter'; import {JoiFrontMatter} from '../JoiFrontMatter';
import {validateFrontMatter} from '../validationUtils'; import {validateFrontMatter} from '../validationUtils';
@ -21,7 +22,9 @@ describe('validateFrontMatter', () => {
}); });
test('should reject bad values', () => { 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}>({ const schema = Joi.object<{test: string}>({
test: Joi.string(), test: Joi.string(),
}); });

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {genChunkName, readOutputHTMLFile, generate} from '../emitUtils'; import {genChunkName, readOutputHTMLFile, generate} from '../emitUtils';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import { import {
removeSuffix, removeSuffix,
removePrefix, removePrefix,

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * 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 = { type LinksCollector = {
collectLink: (link: string) => void; collectLink: (link: string) => void;
@ -26,7 +26,7 @@ export const createStatefulLinksCollector = (): StatefulLinksCollector => {
}; };
}; };
const Context = createContext<LinksCollector>({ const Context = React.createContext<LinksCollector>({
collectLink: () => { collectLink: () => {
// noop by default for client // noop by default for client
// we only use the broken links checker server-side // we only use the broken links checker server-side

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import normalizeLocation from '../normalizeLocation'; import normalizeLocation from '../normalizeLocation';
describe('normalizeLocation', () => { describe('normalizeLocation', () => {

View file

@ -6,7 +6,7 @@
*/ */
import React from 'react'; import React from 'react';
import {hydrate, render} from 'react-dom'; import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom'; import {BrowserRouter} from 'react-router-dom';
import {HelmetProvider} from 'react-helmet-async'; import {HelmetProvider} from 'react-helmet-async';
@ -30,7 +30,8 @@ if (ExecutionEnvironment.canUseDOM) {
// first-load experience. // first-load experience.
// For development, there is no existing markup so we had to render it. // For development, there is no existing markup so we had to render it.
// We also preload async component to avoid first-load loading screen. // 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(() => { preload(routes, window.location.pathname).then(() => {
renderMethod( renderMethod(
<HelmetProvider> <HelmetProvider>

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * 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 { import type {
InterpolateProps, InterpolateProps,
InterpolateValues, InterpolateValues,
@ -49,7 +49,7 @@ export function interpolate<Str extends string, Value extends ReactNode>(
const value = values?.[key]; const value = values?.[key];
if (typeof value !== 'undefined') { if (typeof value !== 'undefined') {
const element = React.isValidElement(value) const element = isValidElement(value)
? value ? value
: // For non-React elements: basic primitive->string conversion : // For non-React elements: basic primitive->string conversion
String(value); String(value);

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import React from 'react'; import React from 'react';
import renderer from 'react-test-renderer'; import renderer from 'react-test-renderer';
import BrowserOnly from '../BrowserOnly'; import BrowserOnly from '../BrowserOnly';

View file

@ -5,12 +5,13 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl'; import useBaseUrl, {useBaseUrlUtils} from '../useBaseUrl';
import useDocusaurusContext from '../useDocusaurusContext'; import useDocusaurusContext from '../useDocusaurusContext';
jest.mock('../useDocusaurusContext', () => jest.fn(), {virtual: true}); jest.mock('../useDocusaurusContext');
const mockedContext = <jest.Mock>useDocusaurusContext; const mockedContext = useDocusaurusContext as jest.Mock;
const forcePrepend = {forcePrependBaseUrl: true}; const forcePrepend = {forcePrependBaseUrl: true};

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import {ThemePath, createTempSiteDir, Components} from './testUtils'; import {ThemePath, createTempSiteDir, Components} from './testUtils';

View file

@ -62,7 +62,7 @@ declare module '@slorber/static-site-generator-webpack-plugin' {
} }
declare module 'webpack/lib/HotModuleReplacementPlugin' { declare module 'webpack/lib/HotModuleReplacementPlugin' {
import {HotModuleReplacementPlugin} from 'webpack'; import type {HotModuleReplacementPlugin} from 'webpack';
export default HotModuleReplacementPlugin; export default HotModuleReplacementPlugin;
} }

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import _ from 'lodash'; import _ from 'lodash';
import {handleBrokenLinks} from '../brokenLinks'; import {handleBrokenLinks} from '../brokenLinks';
@ -157,7 +158,7 @@ describe('handleBrokenLinks', () => {
test('no-op for ignore', async () => { test('no-op for ignore', async () => {
// In any case, _.mapValues will always be called, unless handleBrokenLinks // In any case, _.mapValues will always be called, unless handleBrokenLinks
// has already bailed // has already bailed
const lodashMock = jest.spyOn(_, 'mapValues').mockImplementation(); const lodashMock = jest.spyOn(_, 'mapValues');
await handleBrokenLinks({ await handleBrokenLinks({
allCollectedLinks, allCollectedLinks,
onBrokenLinks: 'ignore', onBrokenLinks: 'ignore',

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {handleDuplicateRoutes} from '../duplicateRoutes'; import {handleDuplicateRoutes} from '../duplicateRoutes';
import type {RouteConfig} from '@docusaurus/types'; import type {RouteConfig} from '@docusaurus/types';

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import {loadI18n, localizePath, getDefaultLocaleConfig} from '../i18n'; import {loadI18n, localizePath, getDefaultLocaleConfig} from '../i18n';
import {DEFAULT_I18N_CONFIG} from '../configValidation'; import {DEFAULT_I18N_CONFIG} from '../configValidation';
import path from 'path'; import path from 'path';
@ -79,7 +80,7 @@ describe('defaultLocaleConfig', () => {
}); });
describe('loadI18n', () => { describe('loadI18n', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
beforeEach(() => { beforeEach(() => {
consoleSpy.mockClear(); consoleSpy.mockClear();
}); });

View file

@ -20,6 +20,7 @@ export function sortAliases(aliases: ThemeAliases): ThemeAliases {
const entries = _.sortBy(Object.entries(aliases), ([alias]) => alias); const entries = _.sortBy(Object.entries(aliases), ([alias]) => alias);
// @theme/NavbarItem should be after @theme/NavbarItem/LocaleDropdown // @theme/NavbarItem should be after @theme/NavbarItem/LocaleDropdown
entries.sort(([alias1], [alias2]) => entries.sort(([alias1], [alias2]) =>
// eslint-disable-next-line no-nested-ternary
alias1.includes(`${alias2}/`) ? -1 : alias2.includes(`${alias1}/`) ? 1 : 0, alias1.includes(`${alias2}/`) ? -1 : alias2.includes(`${alias1}/`) ? 1 : 0,
); );
return Object.fromEntries(entries); return Object.fromEntries(entries);

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import { import {
ensureTranslationFileContent, ensureTranslationFileContent,
writeTranslationFileContent, writeTranslationFileContent,
@ -560,7 +561,7 @@ describe('getPluginsDefaultCodeTranslationMessages', () => {
}); });
describe('applyDefaultCodeTranslations', () => { describe('applyDefaultCodeTranslations', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
beforeEach(() => { beforeEach(() => {
consoleSpy.mockClear(); consoleSpy.mockClear();
}); });

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import fs from 'fs-extra'; import fs from 'fs-extra';
import tmp from 'tmp-promise'; import tmp from 'tmp-promise';
import { import {

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {jest} from '@jest/globals';
import path from 'path'; import path from 'path';
import { import {

View file

@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree. * 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 createClientConfig from '../client';
import loadSetup from '../../server/__tests__/testUtils'; import loadSetup from '../../server/__tests__/testUtils';
@ -15,7 +16,7 @@ describe('webpack dev config', () => {
console.log = jest.fn(); console.log = jest.fn();
const props = await loadSetup('simple'); const props = await loadSetup('simple');
const config = await createClientConfig(props); const config = await createClientConfig(props);
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });
@ -23,7 +24,7 @@ describe('webpack dev config', () => {
console.log = jest.fn(); console.log = jest.fn();
const props = await loadSetup('custom'); const props = await loadSetup('custom');
const config = await createClientConfig(props); const config = await createClientConfig(props);
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });
}); });

View file

@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree. * 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 createServerConfig from '../server';
import loadSetup from '../../server/__tests__/testUtils'; import loadSetup from '../../server/__tests__/testUtils';
@ -15,7 +16,7 @@ describe('webpack production config', () => {
console.log = jest.fn(); console.log = jest.fn();
const props = await loadSetup('simple'); const props = await loadSetup('simple');
const config = await createServerConfig({props}); const config = await createServerConfig({props});
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });
@ -23,7 +24,7 @@ describe('webpack production config', () => {
console.log = jest.fn(); console.log = jest.fn();
const props = await loadSetup('custom'); const props = await loadSetup('custom');
const config = await createServerConfig({props}); const config = await createServerConfig({props});
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });
}); });

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * 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 path from 'path';
import { import {
@ -86,7 +86,7 @@ describe('extending generated webpack config', () => {
filename: 'new.bundle.js', filename: 'new.bundle.js',
}, },
}); });
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });
@ -116,7 +116,7 @@ describe('extending generated webpack config', () => {
filename: 'new.bundle.js', filename: 'new.bundle.js',
}, },
}); });
const errors = validate(config); const errors = webpack.validate(config);
expect(errors).toBeUndefined(); expect(errors).toBeUndefined();
}); });

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * 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'; const pluginName = 'chunk-asset-plugin';
@ -48,7 +48,7 @@ export default class ChunkAssetPlugin {
chunkNameToId, chunkNameToId,
)}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`, )}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`,
); );
return Template.asString(buf); return webpack.Template.asString(buf);
}); });
}); });
} }

View file

@ -13,7 +13,9 @@ describe('lqip library', () => {
const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg'); const invalidPath = path.join(__dirname, '__fixtures__', 'docusaurus.svg');
it('should reject unknown or unsupported file format', async () => { 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 () => { it('should generate a valid base64', async () => {

View file

@ -11,36 +11,35 @@ import type {Palette} from 'node-vibrant/lib/color';
import {toPalette, toBase64} from '../utils'; import {toPalette, toBase64} from '../utils';
describe('lqip-loader', () => { describe('toBase64', () => {
describe('toBase64', () => { test('should return a properly formatted Base64 image string', () => {
test('should return a properly formatted Base64 image string', () => { const mockedMimeType = 'image/jpeg';
const expected = 'data:image/jpeg;base64,aGVsbG8gd29ybGQ='; const mockedBase64Data = Buffer.from('hello world');
const mockedMimeType = 'image/jpeg'; expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual(
const mockedBase64Data = Buffer.from('hello world'); 'data:image/jpeg;base64,aGVsbG8gd29ybGQ=',
expect(toBase64(mockedMimeType, mockedBase64Data)).toEqual(expected); );
}); });
}); });
describe('toPalette', () => { describe('toPalette', () => {
let correctTestSwatch: Palette = {}; let correctTestSwatch: Palette = {};
let testSwatchWithNull: Palette & {Vibrant?: null} = {}; let testSwatchWithNull: Palette & {Vibrant?: null} = {};
beforeAll(() => { beforeAll(() => {
const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg'); const imgPath = path.join(__dirname, '__fixtures__/endi.jpg');
const vibrant = new Vibrant(imgPath, {}); const vibrant = new Vibrant(imgPath, {});
return vibrant.getPalette().then((palette) => { return vibrant.getPalette().then((palette) => {
correctTestSwatch = {...palette}; correctTestSwatch = {...palette};
testSwatchWithNull = {...palette, Vibrant: null}; testSwatchWithNull = {...palette, Vibrant: null};
}); });
}); });
it('should return 6 hex colours sorted by popularity', () => { it('should return 6 hex colours sorted by popularity', () => {
expect(toPalette(correctTestSwatch)).toHaveLength(6); expect(toPalette(correctTestSwatch)).toHaveLength(6);
}); });
it('should return 5 hex colours with no errors if a palette was incomplete', () => { it('should return 5 hex colours with no errors if a palette was incomplete', () => {
expect(toPalette(testSwatchWithNull)).toHaveLength(5); expect(toPalette(testSwatchWithNull)).toHaveLength(5);
});
}); });
}); });

View file

@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree. * 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 Layout from '@theme/Layout';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
export default function LinkTest(): JSX.Element { export default function LinkTest(): JSX.Element {
const anchorRef = React.useRef<HTMLAnchorElement>(null); const anchorRef = useRef<HTMLAnchorElement>(null);
return ( return (
<Layout> <Layout>
<main className="container margin-vert--xl"> <main className="container margin-vert--xl">

View file

@ -102,7 +102,7 @@ import MyComponentSource from '!!raw-loader!@site/src/pages/examples/\_myCompone
```jsx live ```jsx live
function Demo() { function Demo() {
React.useEffect(() => console.log('mount'), []); useEffect(() => console.log('mount'), []);
return null; return null;
} }
``` ```

View file

@ -6,14 +6,12 @@
*/ */
import React, { import React, {
Children,
type ComponentProps, type ComponentProps,
type ReactElement, type ReactElement,
type ReactNode, type ReactNode,
isValidElement, isValidElement,
useRef, useRef,
useEffect, useEffect,
forwardRef,
} from 'react'; } from 'react';
import {useHistory} from '@docusaurus/router'; import {useHistory} from '@docusaurus/router';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -27,41 +25,41 @@ interface Props {
function getText(node: ReactElement): string { function getText(node: ReactElement): string {
let curNode: ReactNode = node; let curNode: ReactNode = node;
while (isValidElement(curNode)) { while (isValidElement(curNode)) {
[curNode] = Children.toArray(curNode.props.children); [curNode] = React.Children.toArray(curNode.props.children);
} }
return curNode as string; return curNode as string;
} }
const APITableRow = forwardRef( function APITableRow(
( {
{ name,
name, children,
children, }: {name: string | undefined; children: ReactElement<ComponentProps<'tr'>>},
}: {name: string | undefined; children: ReactElement<ComponentProps<'tr'>>}, ref: React.ForwardedRef<HTMLTableRowElement>,
ref: React.ForwardedRef<HTMLTableRowElement>, ) {
) => { const entryName = getText(children);
const entryName = getText(children); const id = name ? `${name}-${entryName}` : entryName;
const id = name ? `${name}-${entryName}` : entryName; const anchor = `#${id}`;
const anchor = `#${id}`; const history = useHistory();
const history = useHistory(); return (
return ( <tr
<tr id={id}
id={id} tabIndex={0}
tabIndex={0} ref={history.location.hash === anchor ? ref : undefined}
ref={history.location.hash === anchor ? ref : undefined} onClick={() => {
onClick={() => { history.push(anchor);
}}
onKeyDown={(e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
history.push(anchor); history.push(anchor);
}} }
onKeyDown={(e: React.KeyboardEvent) => { }}>
if (e.key === 'Enter') { {children.props.children}
history.push(anchor); </tr>
} );
}}> }
{children.props.children}
</tr> const APITableRowComp = React.forwardRef(APITableRow);
);
},
);
/* /*
* Note: this is not a quite robust component since it makes a lot of * 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. * should be generally correct in the MDX context.
*/ */
export default function APITable({children, name}: Props): JSX.Element { export default function APITable({children, name}: Props): JSX.Element {
const [thead, tbody] = Children.toArray( const [thead, tbody] = React.Children.toArray(
children.props.children, children.props.children,
) as ReactElement[]; ) as ReactElement[];
const highlightedRow = useRef<HTMLTableRowElement>(null); const highlightedRow = useRef<HTMLTableRowElement>(null);
useEffect(() => { useEffect(() => {
highlightedRow.current?.focus(); highlightedRow.current?.focus();
}, [highlightedRow]); }, [highlightedRow]);
const rows = Children.map( const rows = React.Children.map(
tbody.props.children, tbody.props.children,
(row: ReactElement<ComponentProps<'tr'>>) => ( (row: ReactElement<ComponentProps<'tr'>>) => (
<APITableRow name={name} ref={highlightedRow}> <APITableRowComp name={name} ref={highlightedRow}>
{row} {row}
</APITableRow> </APITableRowComp>
), ),
); );

View file

@ -6,12 +6,10 @@
*/ */
import {TagList, sortedUsers, type User} from '../users'; import {TagList, sortedUsers, type User} from '../users';
// eslint-disable-next-line import/no-extraneous-dependencies
import {Joi} from '@docusaurus/utils-validation'; import {Joi} from '@docusaurus/utils-validation';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
// eslint-disable-next-line import/no-extraneous-dependencies
import imageSize from 'image-size'; import imageSize from 'image-size';
declare global { declare global {

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React, {memo} from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import Image from '@theme/IdealImage'; import Image from '@theme/IdealImage';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
@ -95,4 +95,4 @@ function ShowcaseCard({user}: {user: User}) {
); );
} }
export default memo(ShowcaseCard); export default React.memo(ShowcaseCard);

View file

@ -6,12 +6,12 @@
*/ */
import React, { import React, {
type ComponentProps,
type ReactNode,
type ReactElement,
useCallback, useCallback,
useState, useState,
useEffect, useEffect,
type ComponentProps,
type ReactNode,
type ReactElement,
} from 'react'; } from 'react';
import {useHistory, useLocation} from '@docusaurus/router'; import {useHistory, useLocation} from '@docusaurus/router';
import {toggleListItem} from '@site/src/utils/jsUtils'; import {toggleListItem} from '@site/src/utils/jsUtils';