From 624735bd92a82724e4fc18239d42e160726af506 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 24 May 2022 19:19:24 +0800 Subject: [PATCH] refactor: fix more type-aware linting errors (#7479) --- .eslintrc.js | 4 +- admin/scripts/generateExamples.js | 7 +- packages/create-docusaurus/bin/index.js | 4 +- packages/create-docusaurus/src/index.ts | 2 +- packages/docusaurus-migrate/bin/index.mjs | 6 +- .../src/index.d.ts | 13 ++- .../src/__tests__/feed.test.ts | 4 +- .../docusaurus-plugin-content-docs/src/cli.ts | 10 +- .../src/versions/files.ts | 2 +- .../docusaurus-theme-classic/src/index.ts | 5 +- .../src/theme-classic.d.ts | 3 +- .../src/theme/MDXComponents/Details.tsx | 8 +- .../src/theme/MDXComponents/Head.tsx | 8 +- .../src/theme/MDXComponents/Pre.tsx | 4 +- .../src/theme/Navbar/Content/index.tsx | 3 +- .../MobileSidebar/PrimaryMenu/index.tsx | 3 +- .../DocsVersionDropdownNavbarItem.tsx | 4 +- .../theme/NavbarItem/DropdownNavbarItem.tsx | 3 +- .../src/theme/NavbarItem/index.tsx | 27 ++--- .../src/theme/Tabs/index.tsx | 6 +- .../src/components/Details/index.tsx | 2 +- .../src/hooks/useTOCHighlight.ts | 2 +- .../src/utils/codeBlockUtils.ts | 6 +- .../src/utils/useThemeConfig.ts | 6 +- .../src/theme/Playground/index.tsx | 2 +- .../src/theme/SearchBar/index.tsx | 2 +- .../locales/__tests__/locales.test.ts | 6 +- .../src/index.ts | 2 +- .../src/__tests__/pathUtils.test.ts | 30 +++-- packages/docusaurus/bin/beforeCli.mjs | 4 +- .../src/client/ClientLifecyclesDispatcher.tsx | 2 +- .../src/client/__tests__/flat.test.ts | 2 +- packages/docusaurus/src/client/docusaurus.ts | 2 +- .../docusaurus/src/client/exports/Link.tsx | 5 +- .../exports/__tests__/useGlobalData.test.tsx | 13 --- .../src/client/exports/isInternalUrl.ts | 2 +- .../src/client/exports/useGlobalData.ts | 3 - packages/docusaurus/src/client/flat.ts | 2 +- packages/docusaurus/src/client/prefetch.ts | 4 +- .../docusaurus/src/client/serverEntry.tsx | 4 +- .../configValidation.test.ts.snap | 16 +-- .../docusaurus/src/server/configValidation.ts | 8 +- packages/docusaurus/src/server/htmlTags.ts | 2 +- .../__tests__/__snapshots__/init.test.ts.snap | 4 +- .../src/server/plugins/__tests__/init.test.ts | 2 +- .../translations/translationsExtractor.ts | 6 +- packages/docusaurus/src/webpack/utils.ts | 2 +- packages/lqip-loader/src/index.ts | 7 +- .../src/__tests__/index.test.ts | 110 +++++++++--------- tsconfig.json | 1 + website/src/pages/versions.tsx | 2 +- 51 files changed, 195 insertions(+), 192 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4dc985f0d9f9..051366201728 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -83,7 +83,7 @@ module.exports = { 'no-restricted-exports': OFF, 'no-restricted-properties': [ ERROR, - ...[ + .../** @type {[string, string][]} */ ([ // TODO: TS doesn't make Boolean a narrowing function yet, // so filter(Boolean) is problematic type-wise // ['compact', 'Array#filter(Boolean)'], @@ -114,7 +114,7 @@ module.exports = { ['take', 'Array#slice(0, n)'], ['takeRight', 'Array#slice(-n)'], ['tail', 'Array#slice(1)'], - ].map(([property, alternative]) => ({ + ]).map(([property, alternative]) => ({ object: '_', property, message: `Use ${alternative} instead.`, diff --git a/admin/scripts/generateExamples.js b/admin/scripts/generateExamples.js index de99e750490b..59020d821d09 100644 --- a/admin/scripts/generateExamples.js +++ b/admin/scripts/generateExamples.js @@ -44,9 +44,10 @@ async function generateTemplateExample(template) { `npm init docusaurus@latest examples/${template} ${command}`, ); - const templatePackageJson = await fs.readJSON( - `examples/${template}/package.json`, - ); + const templatePackageJson = + await /** @type {Promise} */ ( + fs.readJSON(`examples/${template}/package.json`) + ); // Attach the dev script which would be used in code sandbox by default templatePackageJson.scripts.dev = 'docusaurus start'; diff --git a/packages/create-docusaurus/bin/index.js b/packages/create-docusaurus/bin/index.js index 328495345270..35e135ebc65c 100755 --- a/packages/create-docusaurus/bin/index.js +++ b/packages/create-docusaurus/bin/index.js @@ -14,7 +14,9 @@ import logger from '@docusaurus/logger'; import semver from 'semver'; import {program} from 'commander'; -const packageJson = createRequire(import.meta.url)('../package.json'); +const packageJson = /** @type {import("../package.json")} */ ( + createRequire(import.meta.url)('../package.json') +); const requiredVersion = packageJson.engines.node; if (!semver.satisfies(process.version, requiredVersion)) { diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 6523b9291766..27d53f50fd59 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -78,7 +78,7 @@ async function askForPackageManagerChoice(): Promise { logger.info`Falling back to name=${defaultPackageManager}`; }, }, - )) as {packageManager: PackageManager} + )) as {packageManager?: PackageManager} ).packageManager ?? defaultPackageManager ); } diff --git a/packages/docusaurus-migrate/bin/index.mjs b/packages/docusaurus-migrate/bin/index.mjs index 769c5e9e3c08..0ace2050c1ca 100755 --- a/packages/docusaurus-migrate/bin/index.mjs +++ b/packages/docusaurus-migrate/bin/index.mjs @@ -15,7 +15,9 @@ import semver from 'semver'; import cli from 'commander'; const moduleRequire = createRequire(import.meta.url); -const requiredVersion = moduleRequire('../package.json').engines.node; +const requiredVersion = /** @type {import("../package.json")} */ ( + moduleRequire('../package.json') +).engines.node; if (!semver.satisfies(process.version, requiredVersion)) { logger.error('Minimum Node.js version not met :('); @@ -25,7 +27,7 @@ if (!semver.satisfies(process.version, requiredVersion)) { // See https://github.com/facebook/docusaurus/pull/6860 const {migrateDocusaurusProject, migrateMDToMDX} = - moduleRequire('../lib/index.js'); + /** @type {import("../lib/index.js")} */ (moduleRequire('../lib/index.js')); cli .command('migrate [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 cd6bf0d1c910..3a900c907d77 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -323,16 +323,27 @@ declare module '@docusaurus/renderRoutes' { declare module '@docusaurus/useGlobalData' { import type {GlobalData, UseDataOptions} from '@docusaurus/types'; + export function useAllPluginInstancesData( + pluginName: string, + options: {failfast: true}, + ): GlobalData[string]; + export function useAllPluginInstancesData( pluginName: string, options?: UseDataOptions, ): GlobalData[string] | undefined; + export function usePluginData( + pluginName: string, + pluginId: string | undefined, + options: {failfast: true}, + ): NonNullable; + export function usePluginData( pluginName: string, pluginId?: string, options?: UseDataOptions, - ): GlobalData[string][string] | undefined; + ): GlobalData[string][string]; export default function useGlobalData(): GlobalData; } 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 7b7981985443..2e5d96872dfe 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -133,7 +133,9 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { } as PluginOptions, ); - expect(fsMock.mock.calls.map((call) => call[1])).toMatchSnapshot(); + expect( + fsMock.mock.calls.map((call) => call[1] as string), + ).toMatchSnapshot(); fsMock.mockClear(); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index 7156d4c6e49a..65e4984affa0 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -14,6 +14,7 @@ import { getVersionDocsDirPath, getVersionSidebarsPath, getDocsDirPathLocalized, + readVersionsFile, } from './versions/files'; import {validateVersionName} from './versions/validation'; import {loadSidebarsFileUnsafe} from './sidebars'; @@ -69,12 +70,7 @@ export async function cliDocsVersionCommand( throw err; } - // Load existing versions. - let versions: string[] = []; - const versionsJSONFile = getVersionsFilePath(siteDir, pluginId); - if (await fs.pathExists(versionsJSONFile)) { - versions = await fs.readJSON(versionsJSONFile); - } + const versions = (await readVersionsFile(siteDir, pluginId)) ?? []; // Check if version already exists. if (versions.includes(version)) { @@ -137,7 +133,7 @@ export async function cliDocsVersionCommand( // Update versions.json file. versions.unshift(version); await fs.outputFile( - versionsJSONFile, + getVersionsFilePath(siteDir, pluginId), `${JSON.stringify(versions, null, 2)}\n`, ); diff --git a/packages/docusaurus-plugin-content-docs/src/versions/files.ts b/packages/docusaurus-plugin-content-docs/src/versions/files.ts index f9ef69c82944..04c97efaebaa 100644 --- a/packages/docusaurus-plugin-content-docs/src/versions/files.ts +++ b/packages/docusaurus-plugin-content-docs/src/versions/files.ts @@ -89,7 +89,7 @@ export function getVersionsFilePath(siteDir: string, pluginId: string): string { * @throws Throws if validation fails, i.e. `versions.json` doesn't contain an * array of valid version names. */ -async function readVersionsFile( +export async function readVersionsFile( siteDir: string, pluginId: string, ): Promise { diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index c87fef7f4b7e..b52f14d98b57 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -19,8 +19,9 @@ import type webpack from 'webpack'; const requireFromDocusaurusCore = createRequire( require.resolve('@docusaurus/core/package.json'), ); -const ContextReplacementPlugin: typeof webpack.ContextReplacementPlugin = - requireFromDocusaurusCore('webpack/lib/ContextReplacementPlugin'); +const ContextReplacementPlugin = requireFromDocusaurusCore( + 'webpack/lib/ContextReplacementPlugin', +) as typeof webpack.ContextReplacementPlugin; // Need to be inlined to prevent dark mode FOUC // Make sure the key is the same as the one in `/theme/hooks/useTheme.js` diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 4aa679bd4946..bc9b9c9bbaf3 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -816,7 +816,6 @@ declare module '@theme/NavbarItem/NavbarNavLink' { declare module '@theme/NavbarItem/DropdownNavbarItem' { import type {Props as NavbarNavLinkProps} from '@theme/NavbarItem/NavbarNavLink'; - import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; export type DesktopOrMobileNavBarItemProps = NavbarNavLinkProps & { @@ -976,7 +975,7 @@ declare module '@theme/NavbarItem' { } & SearchNavbarItemProps) ); - export type Types = Props['type']; + export type NavbarItemType = Props['type']; export default function NavbarItem(props: Props): JSX.Element; } diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx index 8ae874a7a23e..c99fdc2a6adb 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Details.tsx @@ -10,11 +10,13 @@ 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[]; + const items = React.Children.toArray(props.children); // Split summary item from the rest to pass it as a separate prop to the // Details theme component - const summary: ReactElement> | undefined = - items.find((item) => item?.props?.mdxType === 'summary'); + const summary = items.find( + (item): item is ReactElement> => + React.isValidElement(item) && item.props?.mdxType === 'summary', + ); const children = <>{items.filter((item) => item !== summary)}; return ( diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx index c21608e69e36..bf8867f409ba 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Head.tsx @@ -11,8 +11,10 @@ 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) { +function unwrapMDXElement( + element: ReactElement<{mdxType?: string; originalType?: string} | undefined>, +) { + if (element.props?.mdxType && element.props.originalType) { const {mdxType, originalType, ...newProps} = element.props; return React.createElement(element.props.originalType, newProps); } @@ -21,7 +23,7 @@ function unwrapMDXElement(element: ReactElement) { export default function MDXHead(props: Props): JSX.Element { const unwrappedChildren = React.Children.map(props.children, (child) => - unwrapMDXElement(child as ReactElement), + React.isValidElement(child) ? unwrapMDXElement(child) : child, ); return ( )}>{unwrappedChildren} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx index bfaf413fd04b..75e64c997171 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXComponents/Pre.tsx @@ -14,8 +14,8 @@ export default function MDXPre(props: Props): JSX.Element { ); diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/Content/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/Content/index.tsx index 89503a675dcb..cf087e6cefd5 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/Content/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/Content/index.tsx @@ -11,13 +11,12 @@ import { useNavbarMobileSidebar, useThemeConfig, } from '@docusaurus/theme-common'; -import NavbarItem from '@theme/NavbarItem'; +import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem'; import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle'; import SearchBar from '@theme/SearchBar'; import NavbarMobileSidebarToggle from '@theme/Navbar/MobileSidebar/Toggle'; import NavbarLogo from '@theme/Navbar/Logo'; import NavbarSearch from '@theme/Navbar/Search'; -import type {Props as NavbarItemConfig} from '@theme/NavbarItem'; import styles from './styles.module.css'; 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 index d8fa6524a6f0..3fec36ad617d 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx @@ -7,8 +7,7 @@ import React from 'react'; import {useNavbarMobileSidebar, useThemeConfig} from '@docusaurus/theme-common'; -import NavbarItem from '@theme/NavbarItem'; -import type {Props as NavbarItemConfig} from '@theme/NavbarItem'; +import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem'; function useNavbarItems() { // TODO temporary casting until ThemeConfig type is improved diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx index b351eeeef1a8..47903ce0aa35 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx @@ -38,13 +38,13 @@ export default function DocsVersionDropdownNavbarItem({ // 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] ?? + activeDocContext.alternateDocVersions[version.name] ?? getVersionMainDoc(version); return { isNavLink: true, label: version.label, to: versionDoc.path, - isActive: () => version === activeDocContext?.activeVersion, + isActive: () => version === activeDocContext.activeVersion, onClick: () => savePreferredVersionName(version.name), }; }); diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx index ca5e03d92f12..45c61dac60e7 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx @@ -15,12 +15,11 @@ import { useLocalPathname, } from '@docusaurus/theme-common'; import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink'; -import NavbarItem from '@theme/NavbarItem'; +import NavbarItem, {type LinkLikeNavbarItemProps} from '@theme/NavbarItem'; import type { DesktopOrMobileNavBarItemProps, Props, } from '@theme/NavbarItem/DropdownNavbarItem'; -import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; const dropdownLinkActiveClass = 'dropdown__link--active'; diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx index ca3253143a16..0096e2bdb1e3 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx @@ -7,31 +7,22 @@ import React from 'react'; import ComponentTypes from '@theme/NavbarItem/ComponentTypes'; -import {type Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem'; -import type {Types, Props} from '@theme/NavbarItem'; +import type {NavbarItemType, Props} from '@theme/NavbarItem'; -const getNavbarItemComponent = (type: NonNullable) => { - const component = ComponentTypes[type]; - if (!component) { - throw new Error(`No NavbarItem component found for type "${type}".`); - } - return component; -}; - -function getComponentType(type: Types, isDropdown: boolean) { +function normalizeComponentType(type: NavbarItemType, props: object) { // Backward compatibility: navbar item with no type set // but containing dropdown items should use the type "dropdown" if (!type || type === 'default') { - return isDropdown ? 'dropdown' : 'default'; + return 'items' in props ? 'dropdown' : 'default'; } - return type as NonNullable; + return type; } export default function NavbarItem({type, ...props}: Props): JSX.Element { - const componentType = getComponentType( - type, - (props as DropdownNavbarItemProps).items !== undefined, - ); - const NavbarItemComponent = getNavbarItemComponent(componentType); + const componentType = normalizeComponentType(type, props); + const NavbarItemComponent = ComponentTypes[componentType]; + if (!NavbarItemComponent) { + throw new Error(`No NavbarItem component found for type "${type}".`); + } return ; } diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx index e81a01d3fc5b..8d055ce06e6f 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx @@ -75,7 +75,7 @@ function TabsComponent(props: Props): JSX.Element { ? defaultValueProp : defaultValueProp ?? children.find((child) => child.props.default)?.props.value ?? - children[0]?.props.value; + children[0]!.props.value; if (defaultValue !== null && !values.some((a) => a.value === defaultValue)) { throw new Error( `Docusaurus error: The has a defaultValue "${defaultValue}" but none of its children has the corresponding value. Available values are: ${values @@ -126,12 +126,12 @@ function TabsComponent(props: Props): JSX.Element { switch (event.key) { case 'ArrowRight': { const nextTab = tabRefs.indexOf(event.currentTarget) + 1; - focusElement = tabRefs[nextTab] || tabRefs[0]!; + focusElement = tabRefs[nextTab] ?? tabRefs[0]!; break; } case 'ArrowLeft': { const prevTab = tabRefs.indexOf(event.currentTarget) - 1; - focusElement = tabRefs[prevTab] || tabRefs[tabRefs.length - 1]!; + focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!; break; } default: diff --git a/packages/docusaurus-theme-common/src/components/Details/index.tsx b/packages/docusaurus-theme-common/src/components/Details/index.tsx index 41c34097aa86..19952166bc59 100644 --- a/packages/docusaurus-theme-common/src/components/Details/index.tsx +++ b/packages/docusaurus-theme-common/src/components/Details/index.tsx @@ -92,7 +92,7 @@ export function Details({ } }}> {/* eslint-disable-next-line @docusaurus/no-untranslated-text */} - {summary || Details} + {summary ?? Details} item !== undefined)!; + const directive = match + .slice(1) + .find((item: string | undefined) => item !== undefined)!; if (lineToClassName[directive]) { blocks[lineToClassName[directive]!]!.range += `${lineNumber},`; } else if (blockStartToClassName[directive]) { diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index 111468e5ea88..b160bf307c84 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -85,10 +85,10 @@ export type FooterBase = { }; export type MultiColumnFooter = FooterBase & { - links: Array<{ + links: { title: string | null; items: FooterLinkItem[]; - }>; + }[]; }; export type SimpleFooter = FooterBase & { @@ -123,7 +123,7 @@ export type ThemeConfig = { prism: PrismConfig; footer?: Footer; image?: string; - metadata: Array<{[key: string]: string}>; + metadata: {[key: string]: string}[]; tableOfContents: TableOfContents; }; diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx index 64a6cc354517..ef5c0f0f4ff9 100644 --- a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx +++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx @@ -98,7 +98,7 @@ export default function Playground({ {/* @ts-expect-error: type incompatibility with refs */} `${code};`)} + transformCode={transformCode ?? ((code) => `${code};`)} theme={prismTheme} {...props}> {playgroundPosition === 'top' ? ( diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.tsx b/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.tsx index 217555ad316d..bd36e353aa6a 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.tsx +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.tsx @@ -75,7 +75,7 @@ type FacetFilters = Required< function mergeFacetFilters(f1: FacetFilters, f2: FacetFilters): FacetFilters { const normalize = ( f: FacetFilters, - ): readonly string[] | ReadonlyArray => + ): readonly string[] | readonly (string | readonly string[])[] => typeof f === 'string' ? [f] : f; return [...normalize(f1), ...normalize(f2)] as FacetFilters; } diff --git a/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts index 3b7a611cbcd6..446a1ea9d090 100644 --- a/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts +++ b/packages/docusaurus-theme-translations/locales/__tests__/locales.test.ts @@ -22,8 +22,10 @@ describe('theme translations', () => { .then((files) => Promise.all( files.map( - (baseMessagesFile): Promise<{[key: string]: string}> => - fs.readJSON(path.join(baseMessagesDirPath, baseMessagesFile)), + (baseMessagesFile) => + fs.readJSON( + path.join(baseMessagesDirPath, baseMessagesFile), + ) as Promise<{[key: string]: string}>, ), ), ) diff --git a/packages/docusaurus-theme-translations/src/index.ts b/packages/docusaurus-theme-translations/src/index.ts index 8b9afb841d90..4c2538044409 100644 --- a/packages/docusaurus-theme-translations/src/index.ts +++ b/packages/docusaurus-theme-translations/src/index.ts @@ -51,7 +51,7 @@ export async function readDefaultCodeTranslationMessages({ const filePath = path.resolve(dirPath, localeToTry, `${name}.json`); if (await fs.pathExists(filePath)) { - return fs.readJSON(filePath); + return fs.readJSON(filePath) as Promise; } } diff --git a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts index eb6cc8d13f07..6059d2946d08 100644 --- a/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/pathUtils.test.ts @@ -37,21 +37,24 @@ describe('isNameTooLong', () => { }; const oldProcessPlatform = process.platform; Object.defineProperty(process, 'platform', {value: 'darwin'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(isNameTooLong(file)).toBe( - typeof asserts[file] === 'boolean' ? asserts[file] : asserts[file].apfs, + typeof expected === 'boolean' ? expected : expected.apfs, ); }); Object.defineProperty(process, 'platform', {value: 'win32'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(isNameTooLong(file)).toBe( - typeof asserts[file] === 'boolean' ? asserts[file] : asserts[file].apfs, + typeof expected === 'boolean' ? expected : expected.apfs, ); }); Object.defineProperty(process, 'platform', {value: 'android'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(isNameTooLong(file)).toBe( - typeof asserts[file] === 'boolean' ? asserts[file] : asserts[file].xfs, + typeof expected === 'boolean' ? expected : expected.xfs, ); }); Object.defineProperty(process, 'platform', {value: oldProcessPlatform}); @@ -79,21 +82,24 @@ describe('shortName', () => { }; const oldProcessPlatform = process.platform; Object.defineProperty(process, 'platform', {value: 'darwin'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(shortName(file)).toBe( - typeof asserts[file] === 'string' ? asserts[file] : asserts[file].apfs, + typeof expected === 'string' ? expected : expected.apfs, ); }); Object.defineProperty(process, 'platform', {value: 'win32'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(shortName(file)).toBe( - typeof asserts[file] === 'string' ? asserts[file] : asserts[file].apfs, + typeof expected === 'string' ? expected : expected.apfs, ); }); Object.defineProperty(process, 'platform', {value: 'android'}); - Object.keys(asserts).forEach((file) => { + (Object.keys(asserts) as (keyof typeof asserts)[]).forEach((file) => { + const expected = asserts[file]; expect(shortName(file)).toBe( - typeof asserts[file] === 'string' ? asserts[file] : asserts[file].xfs, + typeof expected === 'string' ? expected : expected.xfs, ); }); Object.defineProperty(process, 'platform', {value: oldProcessPlatform}); diff --git a/packages/docusaurus/bin/beforeCli.mjs b/packages/docusaurus/bin/beforeCli.mjs index fa4cecdbc77c..238939f2a0b8 100644 --- a/packages/docusaurus/bin/beforeCli.mjs +++ b/packages/docusaurus/bin/beforeCli.mjs @@ -16,7 +16,9 @@ import updateNotifier from 'update-notifier'; import boxen from 'boxen'; import {DOCUSAURUS_VERSION} from '@docusaurus/utils'; -const packageJson = createRequire(import.meta.url)('../package.json'); +const packageJson = /** @type {import("../package.json")} */ ( + createRequire(import.meta.url)('../package.json') +); /** @type {Record} */ let sitePkg; try { diff --git a/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx b/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx index caf75a1647bf..e9cb7f8d5f5a 100644 --- a/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx +++ b/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx @@ -15,7 +15,7 @@ export function dispatchLifecycleAction( ...args: Parameters> ): () => void { const callbacks = clientModules.map((clientModule) => { - const lifecycleFunction = (clientModule?.default?.[lifecycleAction] ?? + const lifecycleFunction = (clientModule.default?.[lifecycleAction] ?? clientModule[lifecycleAction]) as | (( ...a: Parameters> diff --git a/packages/docusaurus/src/client/__tests__/flat.test.ts b/packages/docusaurus/src/client/__tests__/flat.test.ts index f931108938bb..54c252393dd1 100644 --- a/packages/docusaurus/src/client/__tests__/flat.test.ts +++ b/packages/docusaurus/src/client/__tests__/flat.test.ts @@ -41,7 +41,7 @@ describe('flat', () => { null: null, undefined, }; - Object.keys(primitives).forEach((key) => { + (Object.keys(primitives) as (keyof typeof primitives)[]).forEach((key) => { const value = primitives[key]; expect( flat({ diff --git a/packages/docusaurus/src/client/docusaurus.ts b/packages/docusaurus/src/client/docusaurus.ts index 987f931ede0a..da1236cacede 100644 --- a/packages/docusaurus/src/client/docusaurus.ts +++ b/packages/docusaurus/src/client/docusaurus.ts @@ -70,7 +70,7 @@ const docusaurus = { // In some cases, webpack might decide to optimize further, leading to // the chunk assets being merged to another chunk. In this case, we can // safely filter it out and don't need to load it. - if (chunkAsset && !/undefined/.test(chunkAsset)) { + if (chunkAsset && !chunkAsset.includes('undefined')) { return prefetchHelper(chunkAsset); } return Promise.resolve(); diff --git a/packages/docusaurus/src/client/exports/Link.tsx b/packages/docusaurus/src/client/exports/Link.tsx index 78a3f91a6b7b..614c608c3faf 100644 --- a/packages/docusaurus/src/client/exports/Link.tsx +++ b/packages/docusaurus/src/client/exports/Link.tsx @@ -47,10 +47,7 @@ function Link( const linksCollector = useLinksCollector(); const innerRef = useRef(null); - useImperativeHandle( - forwardedRef, - () => innerRef.current as HTMLAnchorElement, - ); + useImperativeHandle(forwardedRef, () => innerRef.current!); // IMPORTANT: using to or href should not change anything // For example, MDX links will ALWAYS give us the href props diff --git a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx index b688427aa9a5..1f52a15b4070 100644 --- a/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx +++ b/packages/docusaurus/src/client/exports/__tests__/useGlobalData.test.tsx @@ -26,19 +26,6 @@ describe('useGlobalData', () => { }).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', () => { diff --git a/packages/docusaurus/src/client/exports/isInternalUrl.ts b/packages/docusaurus/src/client/exports/isInternalUrl.ts index f3158e6e9859..489aff74bc0d 100644 --- a/packages/docusaurus/src/client/exports/isInternalUrl.ts +++ b/packages/docusaurus/src/client/exports/isInternalUrl.ts @@ -6,7 +6,7 @@ */ export function hasProtocol(url: string): boolean { - return /^(?:\w*:|\/\/)/.test(url) === true; + return /^(?:\w*:|\/\/)/.test(url); } export default function isInternalUrl(url?: string): boolean { diff --git a/packages/docusaurus/src/client/exports/useGlobalData.ts b/packages/docusaurus/src/client/exports/useGlobalData.ts index 004d99e38a16..7036878568bd 100644 --- a/packages/docusaurus/src/client/exports/useGlobalData.ts +++ b/packages/docusaurus/src/client/exports/useGlobalData.ts @@ -11,9 +11,6 @@ import type {GlobalData, UseDataOptions} from '@docusaurus/types'; export default function useGlobalData(): GlobalData { const {globalData} = useDocusaurusContext(); - if (!globalData) { - throw new Error('Docusaurus global data not found.'); - } return globalData; } diff --git a/packages/docusaurus/src/client/flat.ts b/packages/docusaurus/src/client/flat.ts index 8413842b8b76..3ef06a2d38e6 100644 --- a/packages/docusaurus/src/client/flat.ts +++ b/packages/docusaurus/src/client/flat.ts @@ -10,7 +10,7 @@ import type {ChunkNames} from '@docusaurus/types'; type Chunk = ChunkNames[string]; type Tree = Exclude; -const isTree = (x: Chunk): x is Tree => +const isTree = (x: unknown): x is Tree => typeof x === 'object' && !!x && Object.keys(x).length > 0; /** diff --git a/packages/docusaurus/src/client/prefetch.ts b/packages/docusaurus/src/client/prefetch.ts index a7a58008a753..4b84c7e884a0 100644 --- a/packages/docusaurus/src/client/prefetch.ts +++ b/packages/docusaurus/src/client/prefetch.ts @@ -8,8 +8,8 @@ function supports(feature: string) { try { const fakeLink = document.createElement('link'); - return fakeLink.relList?.supports?.(feature); - } catch (err) { + return fakeLink.relList.supports(feature); + } catch { return false; } } diff --git a/packages/docusaurus/src/client/serverEntry.tsx b/packages/docusaurus/src/client/serverEntry.tsx index 9918e4220adb..528a0a96e3a8 100644 --- a/packages/docusaurus/src/client/serverEntry.tsx +++ b/packages/docusaurus/src/client/serverEntry.tsx @@ -115,9 +115,9 @@ async function doRender(locals: Locals & {path: string}) { // Using readJSON seems to fail for users of some plugins, possibly because of // the eval sandbox having a different `Buffer` instance (native one instead // of polyfilled one) - const manifest: Manifest = await fs + const manifest = (await fs .readFile(manifestPath, 'utf-8') - .then(JSON.parse); + .then(JSON.parse)) as Manifest; // Get all required assets for this particular page based on client // manifest information. 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 b8a9733d0214..5aceb9625550 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP 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]. +" => Bad Docusaurus plugin value plugins[0]. Example valid plugin config: { plugins: [ @@ -17,7 +17,7 @@ Example valid plugin config: `; exports[`normalizeConfig should throw error if plugins is not an array of [string, object][] #1 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus plugin value as path [plugins,0]. +" => Bad Docusaurus plugin value plugins[0]. Example valid plugin config: { plugins: [ @@ -33,7 +33,7 @@ Example valid plugin config: `; exports[`normalizeConfig should throw error if plugins is not an array of [string, object][] #2 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus plugin value as path [plugins,0]. +" => Bad Docusaurus plugin value plugins[0]. Example valid plugin config: { plugins: [ @@ -49,7 +49,7 @@ Example valid plugin config: `; exports[`normalizeConfig should throw error if plugins is not an array of [string, object][] #3 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus plugin value as path [plugins,0]. +" => Bad Docusaurus plugin value plugins[0]. Example valid plugin config: { plugins: [ @@ -70,7 +70,7 @@ exports[`normalizeConfig should throw error if plugins is not array for the inpu `; 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]. +" => Bad Docusaurus theme value themes[0]. Example valid theme config: { themes: [ @@ -86,7 +86,7 @@ Example valid theme config: `; exports[`normalizeConfig should throw error if themes is not an array of [string, object][] #1 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus theme value as path [themes,0]. +" => Bad Docusaurus theme value themes[0]. Example valid theme config: { themes: [ @@ -102,7 +102,7 @@ Example valid theme config: `; exports[`normalizeConfig should throw error if themes is not an array of [string, object][] #2 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus theme value as path [themes,0]. +" => Bad Docusaurus theme value themes[0]. Example valid theme config: { themes: [ @@ -118,7 +118,7 @@ Example valid theme config: `; exports[`normalizeConfig should throw error if themes is not an array of [string, object][] #3 for the input of: [[Array]] 1`] = ` -" => Bad Docusaurus theme value as path [themes,0]. +" => Bad Docusaurus theme value themes[0]. Example valid theme config: { themes: [ diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 2820e4b44dc3..f5ef6a3cc9a4 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -100,7 +100,9 @@ function createPluginSchema(theme: boolean) { error.message = ` => Bad Docusaurus ${ theme ? 'theme' : 'plugin' - } value as path [${error.path}]. + } value ${error.path.reduce((acc, cur) => + typeof cur === 'string' ? `${acc}.${cur}` : `${acc}[${cur}]`, + )}. ${validConfigExample} `; }); @@ -247,7 +249,9 @@ export function validateConfig(config: unknown): DocusaurusConfig { if (error) { const unknownFields = error.details.reduce((formattedError, err) => { if (err.type === 'object.unknown') { - return `${formattedError}"${err.path}",`; + return `${formattedError}"${err.path.reduce((acc, cur) => + typeof cur === 'string' ? `${acc}.${cur}` : `${acc}[${cur}]`, + )}",`; } return formattedError; }, ''); diff --git a/packages/docusaurus/src/server/htmlTags.ts b/packages/docusaurus/src/server/htmlTags.ts index 81cce416352a..e61f94680404 100644 --- a/packages/docusaurus/src/server/htmlTags.ts +++ b/packages/docusaurus/src/server/htmlTags.ts @@ -83,5 +83,5 @@ export function loadHtmlTags( .trim(), ), ), - ); + ) as Pick; } 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 b900cdd18224..048fb326e44f 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,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`initPlugins throws user-friendly error message for plugins with bad values 1`] = ` -" => Bad Docusaurus plugin value as path [plugins,0]. +" => Bad Docusaurus plugin value plugins[0]. Example valid plugin config: { plugins: [ @@ -13,7 +13,7 @@ Example valid plugin config: ], }; - => Bad Docusaurus plugin value as path [plugins,1]. + => Bad Docusaurus plugin value plugins[1]. Example valid plugin config: { plugins: [ diff --git a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts index adcd9147dcb6..30fe4cb603a9 100644 --- a/packages/docusaurus/src/server/plugins/__tests__/init.test.ts +++ b/packages/docusaurus/src/server/plugins/__tests__/init.test.ts @@ -21,7 +21,7 @@ describe('initPlugins', () => { it('parses plugins correctly and loads them in correct order', async () => { const {context, plugins} = await loadSite(); - expect(context.siteConfig.plugins?.length).toBe(4); + expect(context.siteConfig.plugins).toHaveLength(4); expect(plugins).toHaveLength(8); expect(plugins[0].name).toBe('preset-plugin1'); diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index 83be6bcd7503..dc3b44a3aef4 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -184,7 +184,7 @@ function extractSourceCodeAstTranslations( sourceCodeFilePath: string, ): SourceCodeFileTranslations { function sourceWarningPart(node: Node) { - return `File: ${sourceCodeFilePath} at line ${node.loc?.start.line} + return `File: ${sourceCodeFilePath} at line ${node.loc?.start.line ?? '?'} Full code: ${generate(node).code}`; } @@ -313,7 +313,9 @@ ${sourceWarningPart(path.node)}`); if (isJSXText || isJSXExpressionContainer) { message = isJSXText ? singleChildren.node.value.trim().replace(/\s+/g, ' ') - : (singleChildren.get('expression') as NodePath).evaluate().value; + : String( + (singleChildren.get('expression') as NodePath).evaluate().value, + ); translations[id ?? message] = { message, diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 8a7d0aef6120..1d045731b64f 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -198,7 +198,7 @@ export function applyConfigurePostCss( configurePostCss: NonNullable, config: Configuration, ): Configuration { - type LocalPostCSSLoader = unknown & { + type LocalPostCSSLoader = object & { options: {postcssOptions: PostCssOptions}; }; diff --git a/packages/lqip-loader/src/index.ts b/packages/lqip-loader/src/index.ts index 5dd78269439c..66d828fffb80 100644 --- a/packages/lqip-loader/src/index.ts +++ b/packages/lqip-loader/src/index.ts @@ -6,7 +6,7 @@ */ import * as lqip from './lqip'; -import type {LoaderContext} from 'webpack'; +import type {LoaderContext, LoaderModule} from 'webpack'; type Options = { base64: boolean; @@ -36,8 +36,9 @@ export default async function lqipLoader( } else { if (!contentIsFileExport) { // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires - const fileLoader = require('file-loader') as typeof import('file-loader'); - content = fileLoader.call(this, contentBuffer); + const fileLoader = require('file-loader') as LoaderModule['default']; + // @ts-expect-error: type is a bit unwieldy... + content = fileLoader!.call(this, contentBuffer) as string; } source = content.match( /^(?:export default|module.exports =) (?.*);/, diff --git a/packages/stylelint-copyright/src/__tests__/index.test.ts b/packages/stylelint-copyright/src/__tests__/index.test.ts index 4d0f865e153d..aa4b5de12e27 100644 --- a/packages/stylelint-copyright/src/__tests__/index.test.ts +++ b/packages/stylelint-copyright/src/__tests__/index.test.ts @@ -43,68 +43,64 @@ function getOutputCss(output: stylelint.LinterResult) { function testStylelintRule(config: stylelint.Config, tests: TestSuite) { describe(`${tests.ruleName}`, () => { const checkTestCaseContent = (testCase: TestCase) => - testCase.description || testCase.code; - - if (tests.accept?.length) { - describe('accept cases', () => { - tests.accept.forEach((testCase) => { - it(`${checkTestCaseContent(testCase)}`, async () => { - const options: stylelint.LinterOptions = { - code: testCase.code, - config, - }; - - const output = await stylelint.lint(options); - expect(output.results[0]!.warnings).toEqual([]); - if (!tests.fix) { - return; - } - const fixedOutput = await stylelint.lint({...options, fix: true}); - const fixedCode = getOutputCss(fixedOutput); - expect(fixedCode).toBe(testCase.code); - }); + testCase.description ?? testCase.code; + + describe('accept cases', () => { + tests.accept.forEach((testCase) => { + it(`${checkTestCaseContent(testCase)}`, async () => { + const options: stylelint.LinterOptions = { + code: testCase.code, + config, + }; + + const output = await stylelint.lint(options); + expect(output.results[0]!.warnings).toEqual([]); + if (!tests.fix) { + return; + } + const fixedOutput = await stylelint.lint({...options, fix: true}); + const fixedCode = getOutputCss(fixedOutput); + expect(fixedCode).toBe(testCase.code); }); }); - } + }); - if (tests.reject?.length) { - describe('reject cases', () => { - tests.reject.forEach((testCase) => { - it(`${checkTestCaseContent(testCase)}`, async () => { - const options = { - code: testCase.code, - config, - }; - - const output = await stylelint.lint(options); - const {warnings} = output.results[0]!; - const warning = warnings[0]!; - expect(warnings.length).toBeGreaterThanOrEqual(1); - expect(testCase).toHaveMessage(); - if (testCase.message != null) { - expect(warning.text).toBe(testCase.message); - } - if (testCase.line != null) { - expect(warning.line).toBe(testCase.line); - } - if (testCase.column != null) { - expect(warning.column).toBe(testCase.column); - } - if (!tests.fix) { - return; - } - if (!testCase.fixed) { - throw new Error( - 'If using { fix: true } in test tests, all reject cases must have { fixed: .. }', - ); - } - const fixedOutput = await stylelint.lint({...options, fix: true}); - const fixedCode = getOutputCss(fixedOutput); - expect(fixedCode).toBe(testCase.fixed); - }); + describe('reject cases', () => { + tests.reject.forEach((testCase) => { + it(`${checkTestCaseContent(testCase)}`, async () => { + const options = { + code: testCase.code, + config, + }; + + const output = await stylelint.lint(options); + const {warnings} = output.results[0]!; + const warning = warnings[0]!; + expect(warnings.length).toBeGreaterThanOrEqual(1); + expect(testCase).toHaveMessage(); + if (testCase.message != null) { + expect(warning.text).toBe(testCase.message); + } + if (testCase.line != null) { + expect(warning.line).toBe(testCase.line); + } + if (testCase.column != null) { + expect(warning.column).toBe(testCase.column); + } + if (!tests.fix) { + return; + } + if (!testCase.fixed) { + throw new Error( + 'If using { fix: true } in test tests, all reject cases must have { fixed: .. }', + ); + } + const fixedOutput = await stylelint.lint({...options, fix: true}); + const fixedCode = getOutputCss(fixedOutput); + expect(fixedCode).toBe(testCase.fixed); }); }); - } + }); expect.extend({ toHaveMessage(testCase: TestCase) { diff --git a/tsconfig.json b/tsconfig.json index 34195b64e138..5a379450a1b0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,6 +51,7 @@ "allowJs": true, "skipLibCheck": true // @types/webpack and webpack/types.d.ts are not the same thing }, + "include": ["./**/*", "./**/.eslintrc.js"], "exclude": [ "node_modules", "coverage/**", diff --git a/website/src/pages/versions.tsx b/website/src/pages/versions.tsx index 4a65419b8837..12d042e92eda 100644 --- a/website/src/pages/versions.tsx +++ b/website/src/pages/versions.tsx @@ -45,7 +45,7 @@ export default function Version(): JSX.Element { const pastVersions = versions.filter( (version) => version !== latestVersion && version.name !== 'current', ); - const repoUrl = `https://github.com/${organizationName}/${projectName}`; + const repoUrl = `https://github.com/${organizationName!}/${projectName!}`; return (