Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: fix more type-aware linting errors #7479

Merged
merged 1 commit into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)'],
Expand Down Expand Up @@ -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.`,
Expand Down
7 changes: 4 additions & 3 deletions admin/scripts/generateExamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<import("../../packages/create-docusaurus/templates/classic/package.json") & { scripts: { [name: string]: string }; description: string }>} */ (
fs.readJSON(`examples/${template}/package.json`)
);

// Attach the dev script which would be used in code sandbox by default
templatePackageJson.scripts.dev = 'docusaurus start';
Expand Down
4 changes: 3 additions & 1 deletion packages/create-docusaurus/bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/create-docusaurus/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async function askForPackageManagerChoice(): Promise<PackageManager> {
logger.info`Falling back to name=${defaultPackageManager}`;
},
},
)) as {packageManager: PackageManager}
)) as {packageManager?: PackageManager}
).packageManager ?? defaultPackageManager
);
}
Expand Down
6 changes: 4 additions & 2 deletions packages/docusaurus-migrate/bin/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 :(');
Expand All @@ -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]')
Expand Down
13 changes: 12 additions & 1 deletion packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<GlobalData[string][string]>;

export function usePluginData(
pluginName: string,
pluginId?: string,
options?: UseDataOptions,
): GlobalData[string][string] | undefined;
): GlobalData[string][string];

export default function useGlobalData(): GlobalData;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
10 changes: 3 additions & 7 deletions packages/docusaurus-plugin-content-docs/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getVersionDocsDirPath,
getVersionSidebarsPath,
getDocsDirPathLocalized,
readVersionsFile,
} from './versions/files';
import {validateVersionName} from './versions/validation';
import {loadSidebarsFileUnsafe} from './sidebars';
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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`,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string[] | null> {
Expand Down
5 changes: 3 additions & 2 deletions packages/docusaurus-theme-classic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
3 changes: 1 addition & 2 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 & {
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ComponentProps<'summary'>> | undefined =
items.find((item) => item?.props?.mdxType === 'summary');
const summary = items.find(
(item): item is ReactElement<ComponentProps<'summary'>> =>
React.isValidElement(item) && item.props?.mdxType === 'summary',
);
const children = <>{items.filter((item) => item !== summary)}</>;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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 (
<Head {...(props as ComponentProps<typeof Head>)}>{unwrappedChildren}</Head>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export default function MDXPre(props: Props): JSX.Element {
<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.children.props?.originalType === 'code'
? props.children.props
: {...props})}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Types>) => {
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<Types>;
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 <NavbarItemComponent {...(props as never)} />;
}
6 changes: 3 additions & 3 deletions packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Tabs> has a defaultValue "${defaultValue}" but none of its children has the corresponding value. Available values are: ${values
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function Details({
}
}}>
{/* eslint-disable-next-line @docusaurus/no-untranslated-text */}
{summary || <summary>Details</summary>}
{summary ?? <summary>Details</summary>}

<Collapsible
lazy={false} // Content might matter for SEO in this case
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export function useTOCHighlight(config: TOCHighlightConfig | undefined): void {
function updateLinkActiveClass(link: HTMLAnchorElement, active: boolean) {
if (active) {
if (lastActiveLinkRef.current && lastActiveLinkRef.current !== link) {
lastActiveLinkRef.current?.classList.remove(linkActiveClassName);
lastActiveLinkRef.current.classList.remove(linkActiveClassName);
}
link.classList.add(linkActiveClassName);
lastActiveLinkRef.current = link;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function parseCodeBlockTitle(metastring?: string): string {
}

export function containsLineNumbers(metastring?: string): boolean {
return metastring?.includes('showLineNumbers') || false;
return Boolean(metastring?.includes('showLineNumbers'));
}

/**
Expand Down Expand Up @@ -209,7 +209,9 @@ export function parseLines(
lineNumber += 1;
continue;
}
const directive = match.slice(1).find((item) => 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]) {
Expand Down
Loading