refactor(core): fix types for client code (#6064)

This commit is contained in:
Joshua Chen 2021-12-08 02:58:36 +08:00 committed by GitHub
parent f96a051fbe
commit b4ec7ec011
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 48 additions and 58 deletions

View file

@ -12,6 +12,7 @@
"directory": "packages/docusaurus-module-type-aliases"
},
"dependencies": {
"@docusaurus/types": "2.0.0-beta.9",
"@types/react": "*",
"@types/react-helmet": "*",
"@types/react-router-config": "*",

View file

@ -47,7 +47,9 @@ declare module '@generated/routes' {
}
declare module '@generated/routesChunkNames' {
const routesChunkNames: Record<string, Record<string, string>>;
import type {RouteChunksTree} from '@docusaurus/types';
const routesChunkNames: Record<string, RouteChunksTree>;
export = routesChunkNames;
}

View file

@ -442,3 +442,5 @@ export interface TOCItem {
readonly children: TOCItem[];
readonly level: number;
}
export type RouteChunksTree = {[x: string | number]: string | RouteChunksTree};

View file

@ -72,6 +72,12 @@ function insertBanner() {
`;
}
declare global {
interface Window {
__DOCUSAURUS_INSERT_BASEURL_BANNER: boolean;
}
}
function BaseUrlIssueBannerEnabled() {
const {
siteConfig: {baseUrl},
@ -80,8 +86,7 @@ function BaseUrlIssueBannerEnabled() {
// useLayoutEffect fires before DOMContentLoaded.
// It gives the opportunity to avoid inserting the banner in the first place
useLayoutEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any)[InsertBannerWindowAttribute] = false;
window[InsertBannerWindowAttribute] = false;
}, []);
return (

View file

@ -5,19 +5,16 @@
* LICENSE file in the root directory of this source tree.
*/
// too dynamic
/* eslint-disable @typescript-eslint/no-explicit-any */
import clientModules from '@generated/client-modules';
interface Dispatchers {
onRouteUpdate: (...args: any) => void;
onRouteUpdateDelayed: (...args: any) => void;
onRouteUpdate: (...args: unknown[]) => void;
onRouteUpdateDelayed: (...args: unknown[]) => void;
}
function dispatchLifecycleAction(
lifecycleAction: keyof Dispatchers,
...args: any[]
...args: unknown[]
) {
clientModules.forEach((clientModule) => {
const lifecycleFunction =

View file

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {matchRoutes} from 'react-router-config';
import routesChunkNames from '@generated/routesChunkNames';
import routes from '@generated/routes';
@ -22,18 +23,10 @@ declare global {
}
}
const isSlowConnection = () => {
// If user is on slow or constrained connection.
if (`connection` in navigator) {
if (
(navigator.connection.effectiveType || ``).indexOf(`2g`) !== -1 &&
navigator.connection.saveData
) {
return true;
}
}
return false;
};
const isSlowConnection = () =>
navigator.connection?.effectiveType.includes('2g') &&
navigator.connection?.saveData;
const canPrefetch = (routePath: string) =>
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
@ -41,25 +34,19 @@ const canPrefetch = (routePath: string) =>
const canPreload = (routePath: string) =>
!isSlowConnection() && !loaded[routePath];
const flatten = <T>(arrays: T[][]): T[] =>
Array.prototype.concat.apply([], arrays);
// Remove the last part containing the route hash
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
// output: /blog/2018/12/14/Happy-First-Birthday-Slash
const removeRouteNameHash = (str: string) => str.replace(/(-[^-]+)$/, '');
const getChunkNamesToLoad = (path: string): string[] =>
flatten(
Object.entries(routesChunkNames)
.filter(
([routeNameWithHash]) =>
removeRouteNameHash(routeNameWithHash) === path,
([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path,
)
.map(([, routeChunks]) =>
.flatMap(([, routeChunks]) =>
// flat() is useful for nested chunk names, it's not like array.flat()
Object.values(flat(routeChunks)),
),
);
const docusaurus = {
@ -73,8 +60,8 @@ const docusaurus = {
// Find all webpack chunk names needed.
const matches = matchRoutes(routes, routePath);
const chunkNamesNeeded = flatten(
matches.map((match) => getChunkNamesToLoad(match.route.path as string)),
const chunkNamesNeeded = matches.flatMap((match) =>
getChunkNamesToLoad(match.route.path),
);
// Prefetch all webpack chunk assets file needed.

View file

@ -41,9 +41,9 @@ export function interpolate<Str extends string, Value extends ReactNode>(
const processedText = text.replace(ValueRegexp, (match: string) => {
// remove {{ and }} around the placeholder
const key = match.substr(
const key = match.substring(
1,
match.length - 2,
match.length - 1,
) as ExtractInterpolatePlaceholders<Str>;
const value = values?.[key];

View file

@ -5,24 +5,25 @@
* LICENSE file in the root directory of this source tree.
*/
// Too dynamic
/* eslint-disable @typescript-eslint/no-explicit-any */
function flat(target: unknown): Record<string, any> {
import type {RouteChunksTree} from '@docusaurus/types';
const isTree = (x: string | RouteChunksTree): x is RouteChunksTree =>
typeof x === 'object' && !!x && Object.keys(x).length > 0;
function flat(target: RouteChunksTree): Record<string, string> {
const delimiter = '.';
const output: Record<string, any> = {};
const output: Record<string, string> = {};
function step(object: any, prev?: string) {
Object.keys(object).forEach((key) => {
function step(object: RouteChunksTree, prefix?: string | number) {
Object.keys(object).forEach((key: string | number) => {
const value = object[key];
const type = typeof value;
const isObject = type === 'object' && !!value;
const newKey = prev ? prev + delimiter + key : key;
const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
if (isObject && Object.keys(value).length) {
if (isTree(value)) {
step(value, newKey);
return;
}
} else {
output[newKey] = value;
}
});
}

View file

@ -10,9 +10,5 @@ import {Plugin} from '@docusaurus/types';
export default function loadClientModules(
plugins: Plugin<unknown>[],
): string[] {
return ([] as string[]).concat(
...plugins
.map((plugin) => plugin.getClientModules?.() ?? [])
.filter(Boolean),
);
return plugins.flatMap((plugin) => plugin.getClientModules?.() ?? []);
}

View file

@ -15,8 +15,7 @@ function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject {
if (!isPlainObject(val)) {
throw new Error(`"${val}" is not a valid HTML tag object.`);
}
// @ts-expect-error: If tagName doesn't exist, it will throw.
if (typeof val.tagName !== 'string') {
if (typeof (val as HtmlTagObject).tagName !== 'string') {
throw new Error(
`${JSON.stringify(
val,