refactor: enable a few TS flags (#6852)

* refactor: enable a few TS flags

* refactor

* revert to working version

* fix

* better

* change
This commit is contained in:
Joshua Chen 2022-03-06 13:09:10 +08:00 committed by GitHub
parent 9f925a42bf
commit 4db0c620de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 210 additions and 174 deletions

View file

@ -21,8 +21,8 @@ function interpolate(
): string {
let res = '';
values.forEach((value, idx) => {
const flag = msgs[idx].match(/[a-z]+=$/);
res += msgs[idx].replace(/[a-z]+=$/, '');
const flag = msgs[idx]!.match(/[a-z]+=$/);
res += msgs[idx]!.replace(/[a-z]+=$/, '');
const format = (() => {
if (!flag) {
return (a: string | number) => a;

View file

@ -94,7 +94,7 @@ export default function plugin(options: PluginOptions = {}): Transformer {
const targetIndex = getOrCreateExistingTargetIndex(children, name);
if (headings && headings.length) {
children[targetIndex].value = `export const ${name} = ${stringifyObject(
children[targetIndex]!.value = `export const ${name} = ${stringifyObject(
headings,
)};`;
}

View file

@ -37,8 +37,8 @@ export default function extractMetadata(content: string): Data {
// New line characters => to handle all operating systems.
const lines = (both.header ?? '').split(/\r?\n/);
for (let i = 0; i < lines.length - 1; i += 1) {
const keyValue = lines[i].split(':');
lines.slice(0, -1).forEach((line) => {
const keyValue = line.split(':') as [string, ...string[]];
const key = keyValue[0].trim();
let value = keyValue.slice(1).join(':').trim();
try {
@ -47,7 +47,7 @@ export default function extractMetadata(content: string): Data {
// Ignore the error as it means it's not a JSON value.
}
metadata[key] = value;
}
});
return {metadata, rawContent: both.content};
}

View file

@ -535,7 +535,7 @@ async function migrateVersionedSidebar(
// Order matters: if a sidebar file doesn't exist, we have to use the
// previous version's
for (let i = 0; i < versions.length; i += 1) {
const version = versions[i];
const version = versions[i]!;
let sidebarEntries: SidebarEntries;
const sidebarPath = path.join(
siteDir,
@ -545,7 +545,7 @@ async function migrateVersionedSidebar(
try {
sidebarEntries = JSON.parse(await fs.readFile(sidebarPath, 'utf-8'));
} catch {
sidebars.push({version, entries: sidebars[i - 1].entries});
sidebars.push({version, entries: sidebars[i - 1]!.entries});
return;
}
const newSidebar = Object.entries(sidebarEntries).reduce(

View file

@ -33,6 +33,9 @@ const property = (key: string, value: ArrowFunctionExpression) =>
const processCallExpression = (node: ASTPath<VariableDeclarator>) => {
const args = (node?.value?.init as CallExpression)?.arguments[0];
if (!args) {
return;
}
if (args.type === 'Literal') {
if (
typeof args.value === 'string' &&
@ -71,6 +74,9 @@ const processMemberExpression = (node: ASTPath<VariableDeclarator>) => {
return;
}
const args = object.arguments[0];
if (!args) {
return;
}
if (args.type === 'Literal') {
if (args.value === '../../core/CompLibrary.js') {
const newDeclarator = jscodeshift.variableDeclarator(
@ -117,7 +123,7 @@ export default function transformer(file: string): string {
}
});
if (r[r.length - 1]) {
jscodeshift(r[r.length - 1].parent).insertAfter(
jscodeshift(r[r.length - 1]!.parent).insertAfter(
jscodeshift.importDeclaration(
[jscodeshift.importDefaultSpecifier(jscodeshift.identifier('Layout'))],
jscodeshift.literal('@theme/Layout'),

View file

@ -139,10 +139,10 @@ export function parseBlogFileName(
if (dateFilenameMatch) {
const {folder, text, date: dateString} = dateFilenameMatch.groups!;
// Always treat dates as UTC by adding the `Z`
const date = new Date(`${dateString}Z`);
const slugDate = dateString.replace(/-/g, '/');
const slug = `/${slugDate}/${folder}${text}`;
return {date, text, slug};
const date = new Date(`${dateString!}Z`);
const slugDate = dateString!.replace(/-/g, '/');
const slug = `/${slugDate}/${folder!}${text!}`;
return {date, text: text!, slug};
}
const text = blogSourceRelative.replace(/(?:\/index)?\.mdx?$/, '');
const slug = `/${text}`;

View file

@ -307,7 +307,7 @@ export default async function pluginContentBlog(
({
content: {
__import: true,
path: blogItemsToMetadata[postID].source,
path: blogItemsToMetadata[postID]!.source,
query: {
truncated: true,
},
@ -359,7 +359,7 @@ export default async function pluginContentBlog(
modules: {
sidebar: aliasedSource(sidebarProp),
items: items.map((postID) => {
const blogPostMetadata = blogItemsToMetadata[postID];
const blogPostMetadata = blogItemsToMetadata[postID]!;
return {
content: {
__import: true,

View file

@ -19,8 +19,9 @@ function translateListPage(
items,
metadata: {
...metadata,
blogTitle: translations.title.message,
blogDescription: translations.description.message,
blogTitle: translations.title?.message ?? page.metadata.blogTitle,
blogDescription:
translations.description?.message ?? page.metadata.blogDescription,
},
};
});
@ -52,10 +53,14 @@ export function translateContent(
content: BlogContent,
translationFiles: TranslationFiles,
): BlogContent {
const [{content: optionsTranslations}] = translationFiles;
if (translationFiles.length === 0) {
return content;
}
const {content: optionsTranslations} = translationFiles[0]!;
return {
...content,
blogSidebarTitle: optionsTranslations['sidebar.title'].message,
blogSidebarTitle:
optionsTranslations['sidebar.title']?.message ?? content.blogSidebarTitle,
blogListPaginated: translateListPage(
content.blogListPaginated,
optionsTranslations,

View file

@ -363,7 +363,7 @@ export function getMainDocId({
doc.unversionedId === firstDocIdOfFirstSidebar,
)!;
}
return docs[0];
return docs[0]!;
}
return getMainDoc().unversionedId;

View file

@ -49,7 +49,7 @@ async function readCategoriesMetadata(contentPath: string) {
const categoryToFile = _.groupBy(categoryFiles, path.dirname);
return combinePromises(
_.mapValues(categoryToFile, async (files, folder) => {
const [filePath] = files;
const filePath = files[0]!;
if (files.length > 1) {
logger.warn`There are more than one category metadata files for path=${folder}: ${files.join(
', ',

View file

@ -201,12 +201,12 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
if (!sidebarName) {
return emptySidebarNavigation();
}
if (!sidebarNameToNavigationItems[sidebarName]) {
const navigationItems = sidebarNameToNavigationItems[sidebarName];
if (!navigationItems) {
throw new Error(
`Doc with ID ${docId} wants to display sidebar ${sidebarName} but a sidebar with this name doesn't exist`,
);
}
const navigationItems = sidebarNameToNavigationItems[sidebarName];
const currentItemIndex = navigationItems.findIndex((item) => {
if (item.type === 'doc') {
return item.id === docId;
@ -263,7 +263,7 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
if (!sidebarName) {
return emptySidebarNavigation();
}
const navigationItems = sidebarNameToNavigationItems[sidebarName];
const navigationItems = sidebarNameToNavigationItems[sidebarName]!;
const currentItemIndex = navigationItems.findIndex(
isCurrentCategoryGeneratedIndexItem,
);
@ -341,7 +341,7 @@ Available document ids are:
getCategoryGeneratedIndexList,
getCategoryGeneratedIndexNavigation,
checkSidebarsDocIds,
getFirstLink: (id) => getFirstLink(sidebars[id]),
getFirstLink: (id) => getFirstLink(sidebars[id]!),
};
}

View file

@ -274,10 +274,14 @@ function translateVersion(
translationFiles: Record<string, TranslationFile>,
): LoadedVersion {
const versionTranslations =
translationFiles[getVersionFileName(version.versionName)].content;
translationFiles[getVersionFileName(version.versionName)]?.content;
if (!versionTranslations) {
return version;
}
return {
...version,
versionLabel: versionTranslations['version.label']?.message,
versionLabel:
versionTranslations['version.label']?.message ?? version.versionLabel,
sidebars: translateSidebars(version, versionTranslations),
// docs: translateDocs(version.docs, versionTranslations),
};

View file

@ -464,11 +464,11 @@ Please set the docs "sidebarPath" field in your config file to:
// "last version" is not a very good concept nor api surface
function getDefaultLastVersionName(versionNames: string[]) {
if (versionNames.length === 1) {
return versionNames[0];
return versionNames[0]!;
}
return versionNames.filter(
(versionName) => versionName !== CURRENT_VERSION_NAME,
)[0];
)[0]!;
}
function checkVersionsOptions(

View file

@ -71,7 +71,7 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
if (isParent(node)) {
let index = 0;
while (index < node.children.length) {
const child = node.children[index];
const child = node.children[index]!;
if (matchNode(child)) {
const result = transformNode(child, sync);
node.children.splice(index, 1, ...result);

View file

@ -107,7 +107,7 @@ export default function docusaurusThemeClassic(
prism: {additionalLanguages = []} = {},
} = themeConfig;
const {customCss} = options || {};
const {direction} = localeConfigs[currentLocale];
const {direction} = localeConfigs[currentLocale]!;
return {
name: 'docusaurus-theme-classic',

View file

@ -133,7 +133,7 @@ export default function BackToTopButton(): JSX.Element {
ThemeClassNames.common.backToTopButton,
styles.backToTopButton,
{
[styles.backToTopButtonShow]: show,
[styles.backToTopButtonShow!]: show,
},
)}
type="button"

View file

@ -114,7 +114,7 @@ export default function BlogPostItem(props: Props): JSX.Element {
{(tagsExists || truncated) && (
<footer
className={clsx('row docusaurus-mt-lg', {
[styles.blogPostDetailsFull]: isBlogPostPage,
[styles.blogPostDetailsFull!]: isBlogPostPage,
})}>
{tagsExists && (
<div className={clsx('col', {'col--9': truncatedPost})}>

View file

@ -128,8 +128,8 @@ export default function CodeBlock({
style={style}>
<code className={styles.codeBlockLines}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '\n') {
line[0].content = '';
if (line.length === 1 && line[0]!.content === '\n') {
line[0]!.content = '';
}
const lineProps = getLineProps({line, key: i});

View file

@ -32,9 +32,9 @@ function ColorModeToggle({
return (
<div
className={clsx(styles.toggle, className, {
[styles.toggleChecked]: checked,
[styles.toggleFocused]: focused,
[styles.toggleDisabled]: !isBrowser,
[styles.toggleChecked!]: checked,
[styles.toggleFocused!]: focused,
[styles.toggleDisabled!]: !isBrowser,
})}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div

View file

@ -54,7 +54,7 @@ export default function DocItem(props: Props): JSX.Element {
<div className="row">
<div
className={clsx('col', {
[styles.docItemCol]: !hideTableOfContents,
[styles.docItemCol!]: !hideTableOfContents,
})}>
<DocVersionBanner />
<div className={styles.docItemContainer}>

View file

@ -74,12 +74,12 @@ function DocPageContent({
ThemeClassNames.docs.docSidebarContainer,
styles.docSidebarContainer,
{
[styles.docSidebarContainerHidden]: hiddenSidebarContainer,
[styles.docSidebarContainerHidden!]: hiddenSidebarContainer,
},
)}
onTransitionEnd={(e) => {
if (
!e.currentTarget.classList.contains(styles.docSidebarContainer)
!e.currentTarget.classList.contains(styles.docSidebarContainer!)
) {
return;
}
@ -126,7 +126,7 @@ function DocPageContent({
)}
<main
className={clsx(styles.docMainContainer, {
[styles.docMainContainerEnhanced]:
[styles.docMainContainerEnhanced!]:
hiddenSidebarContainer || !sidebar,
})}>
<div
@ -134,7 +134,7 @@ function DocPageContent({
'container padding-top--md padding-bottom--lg',
styles.docItemWrapper,
{
[styles.docItemWrapperEnhanced]: hiddenSidebarContainer,
[styles.docItemWrapperEnhanced!]: hiddenSidebarContainer,
},
)}>
<MDXProvider components={MDXComponents}>{children}</MDXProvider>
@ -172,7 +172,7 @@ export default function DocPage(props: Props): JSX.Element {
<html className={versionMetadata.className} />
</Head>
<DocsVersionProvider version={versionMetadata}>
<DocsSidebarProvider sidebar={sidebar}>
<DocsSidebarProvider sidebar={sidebar ?? null}>
<DocPageContent
currentDocRoute={currentDocRoute}
versionMetadata={versionMetadata}

View file

@ -73,13 +73,13 @@ function DocSidebarDesktop({path, sidebar, onCollapse, isHidden}: Props) {
return (
<div
className={clsx(styles.sidebar, {
[styles.sidebarWithHideableNavbar]: hideOnScroll,
[styles.sidebarHidden]: isHidden,
[styles.sidebarWithHideableNavbar!]: hideOnScroll,
[styles.sidebarHidden!]: isHidden,
})}>
{hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
<nav
className={clsx('menu thin-scrollbar', styles.menu, {
[styles.menuWithAnnouncementBar]: showAnnouncementBar,
[styles.menuWithAnnouncementBar!]: showAnnouncementBar,
})}>
<ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
<DocSidebarItems items={sidebar} activePath={path} level={1} />

View file

@ -131,7 +131,7 @@ function SimpleLinks({links}: {links: SimpleFooter['links']}) {
function isMultiColumnFooterLinks(
links: MultiColumnFooter['links'] | SimpleFooter['links'],
): links is MultiColumnFooter['links'] {
return 'title' in links[0];
return 'title' in links[0]!;
}
function Footer(): JSX.Element | null {

View file

@ -26,8 +26,8 @@ function AnchorHeading({as: As, id, ...props}: Props) {
<As
{...props}
className={clsx('anchor', {
[styles.anchorWithHideOnScrollNavbar]: hideOnScroll,
[styles.anchorWithStickyNavbar]: !hideOnScroll,
[styles.anchorWithHideOnScrollNavbar!]: hideOnScroll,
[styles.anchorWithStickyNavbar!]: !hideOnScroll,
})}
id={id}>
{props.children}

View file

@ -92,7 +92,7 @@ export default function LayoutHead(props: Props): JSX.Element {
const {title, description, image, keywords, searchMetadata} = props;
const faviconUrl = useBaseUrl(favicon);
const pageTitle = useTitleFormatter(title);
const {htmlLang, direction: htmlDir} = localeConfigs[currentLocale];
const {htmlLang, direction: htmlDir} = localeConfigs[currentLocale]!;
return (
<>

View file

@ -241,8 +241,8 @@ export default function Navbar(): JSX.Element {
'navbar--dark': style === 'dark',
'navbar--primary': style === 'primary',
'navbar-sidebar--show': mobileSidebar.shown,
[styles.navbarHideable]: hideOnScroll,
[styles.navbarHidden]: hideOnScroll && !isNavbarVisible,
[styles.navbarHideable!]: hideOnScroll,
[styles.navbarHidden!]: hideOnScroll && !isNavbarVisible,
})}>
<div className="navbar__inner">
<div className="navbar__items">

View file

@ -28,7 +28,7 @@ export default function LocaleDropdownNavbarItem({
const alternatePageUtils = useAlternatePageUtils();
function getLocaleLabel(locale: string) {
return localeConfigs[locale].label;
return localeConfigs[locale]!.label;
}
const localeItems = locales.map((locale): LinkLikeNavbarItemProps => {

View file

@ -28,7 +28,7 @@ export default function TOCCollapsible({
className={clsx(
styles.tocCollapsible,
{
[styles.tocCollapsibleExpanded]: !collapsed,
[styles.tocCollapsibleExpanded!]: !collapsed,
},
className,
)}>

View file

@ -108,7 +108,7 @@ function TabsComponent(props: Props): JSX.Element {
) => {
const newTab = event.currentTarget;
const newTabIndex = tabRefs.indexOf(newTab);
const newTabValue = values[newTabIndex].value;
const newTabValue = values[newTabIndex]!.value;
if (newTabValue !== selectedValue) {
blockElementScrollPositionUntilNextRender(newTab);
@ -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:
@ -181,7 +181,7 @@ function TabsComponent(props: Props): JSX.Element {
cloneElement(
children.filter(
(tabItem) => tabItem.props.value === selectedValue,
)[0],
)[0]!,
{className: 'margin-vert--md'},
)
) : (

View file

@ -19,8 +19,8 @@ export default function Tag(props: Props): JSX.Element {
<Link
href={permalink}
className={clsx(styles.tag, {
[styles.tagRegular]: !count,
[styles.tagWithCount]: count,
[styles.tagRegular!]: !count,
[styles.tagWithCount!]: count,
})}>
{name}
{count && <span>{count}</span>}

View file

@ -50,8 +50,11 @@ function getNavbarTranslationFile(navbar: Navbar): TranslationFileContent {
}
function translateNavbar(
navbar: Navbar,
navbarTranslations: TranslationFileContent,
navbarTranslations: TranslationFileContent | undefined,
): Navbar {
if (!navbarTranslations) {
return navbar;
}
return {
...navbar,
title: navbarTranslations.title?.message ?? navbar.title,
@ -76,7 +79,7 @@ function translateNavbar(
function isMultiColumnFooterLinks(
links: MultiColumnFooter['links'] | SimpleFooter['links'],
): links is MultiColumnFooter['links'] {
return links.length > 0 && 'title' in links[0];
return links.length > 0 && 'title' in links[0]!;
}
function getFooterTranslationFile(footer: Footer): TranslationFileContent {
@ -121,8 +124,11 @@ function getFooterTranslationFile(footer: Footer): TranslationFileContent {
}
function translateFooter(
footer: Footer,
footerTranslations: TranslationFileContent,
footerTranslations: TranslationFileContent | undefined,
): Footer {
if (!footerTranslations) {
return footer;
}
const links = isMultiColumnFooterLinks(footer.links)
? footer.links.map((link) => ({
...link,
@ -187,10 +193,10 @@ export function translateThemeConfig({
...themeConfig,
navbar: translateNavbar(
themeConfig.navbar,
translationFilesMap.navbar.content,
translationFilesMap.navbar?.content,
),
footer: themeConfig.footer
? translateFooter(themeConfig.footer, translationFilesMap.footer.content)
? translateFooter(themeConfig.footer, translationFilesMap.footer?.content)
: undefined,
};
}

View file

@ -4,7 +4,7 @@
"lib": ["DOM", "ES2019"],
"module": "esnext",
"noEmit": true,
"jsx": "react",
"jsx": "react-native",
"baseUrl": "src"
},
"include": ["src/"]

View file

@ -58,7 +58,7 @@ export default function Details({
data-collapsed={collapsed}
className={clsx(
styles.details,
{[styles.isBrowser]: isBrowser},
{[styles.isBrowser!]: isBrowser},
props.className,
)}
onMouseDown={(e) => {

View file

@ -115,7 +115,7 @@ export function parseLines(
// Highlighted lines specified in props: don't parse the content
if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)!
.groups!.range;
.groups!.range!;
const highlightLines = rangeParser(highlightLinesRange)
.filter((n) => n > 0)
.map((n) => n - 1);
@ -131,7 +131,7 @@ export function parseLines(
let highlightRange = '';
// loop through lines
for (let lineNumber = 0; lineNumber < lines.length; ) {
const line = lines[lineNumber];
const line = lines[lineNumber]!;
const match = line.match(directiveRegex);
if (match !== null) {
const directive = match.slice(1).find((item) => item !== undefined);

View file

@ -71,7 +71,7 @@ function readStorageState({
pluginId,
versionPersistence,
);
const pluginData = allDocsData[pluginId];
const pluginData = allDocsData[pluginId]!;
const versionExists = pluginData.versions.some(
(version) => version.name === preferredVersionNameUnsafe,
);

View file

@ -25,7 +25,7 @@ export function useDocsPreferredVersion(
const docsData = useDocsData(pluginId);
const [state, api] = useDocsPreferredVersionContext();
const {preferredVersionName} = state[pluginId];
const {preferredVersionName} = state[pluginId]!;
const preferredVersion = preferredVersionName
? docsData.versions.find((version) => version.name === preferredVersionName)
@ -49,8 +49,8 @@ export function useDocsPreferredVersionByPluginId(): Record<
const [state] = useDocsPreferredVersionContext();
function getPluginIdPreferredVersion(pluginId: string) {
const docsData = allDocsData[pluginId];
const {preferredVersionName} = state[pluginId];
const docsData = allDocsData[pluginId]!;
const {preferredVersionName} = state[pluginId]!;
return preferredVersionName
? docsData.versions.find(

View file

@ -19,7 +19,7 @@ type TagsListItem = Readonly<{name: string; permalink: string; count: number}>;
export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>;
function getTagLetter(tag: string): string {
return tag[0].toUpperCase();
return tag[0]!.toUpperCase();
}
export function listTagsByLetters(
@ -29,8 +29,8 @@ export function listTagsByLetters(
const groups: Record<string, TagsListItem[]> = {};
Object.values(tags).forEach((tag) => {
const letter = getTagLetter(tag.name);
groups[letter] = groups[letter] ?? [];
groups[letter].push(tag);
groups[letter] ??= [];
groups[letter]!.push(tag);
});
return (

View file

@ -44,7 +44,7 @@ function treeifyTOC(flatTOC: readonly TOCItem[]): TOCTreeNode[] {
headings.forEach((heading) => {
const {parentIndex, ...rest} = heading;
if (parentIndex >= 0) {
headings[parentIndex].children.push(rest);
headings[parentIndex]!.children.push(rest);
} else {
rootNodes.push(rest);
}

View file

@ -34,7 +34,9 @@ export function useContextualSearchFilters(): useContextualSearchFiltersReturns
const preferredVersion = docsPreferredVersionByPluginId[pluginId];
const latestVersion = allDocsData[pluginId].versions.find((v) => v.isLast)!;
const latestVersion = allDocsData[pluginId]!.versions.find(
(v) => v.isLast,
)!;
const version = activeVersion ?? preferredVersion ?? latestVersion;

View file

@ -99,7 +99,7 @@ function selectPluralMessage(
const parts = pluralMessages.split(separator);
if (parts.length === 1) {
return parts[0];
return parts[0]!;
}
if (parts.length > localePluralForms.pluralForms.length) {
console.error(
@ -110,7 +110,7 @@ function selectPluralMessage(
const pluralFormIndex = localePluralForms.pluralForms.indexOf(pluralForm);
// In case of not enough plural form messages, we take the last one (other)
// instead of returning undefined
return parts[Math.min(pluralFormIndex, parts.length - 1)];
return parts[Math.min(pluralFormIndex, parts.length - 1)]!;
}
export function usePluralForm(): {

View file

@ -83,7 +83,7 @@ function getActiveAnchor(
}
// no anchor under viewport top? (ie we are at the bottom of the page)
// => highlight the last anchor found
return anchors[anchors.length - 1];
return anchors[anchors.length - 1] ?? null;
}
function getLinkAnchorValue(link: HTMLAnchorElement): string {

View file

@ -58,7 +58,7 @@ function useDocsSearchVersionsHelpers() {
Object.entries(allDocsData).reduce(
(acc, [pluginId, pluginData]) => ({
...acc,
[pluginId]: pluginData.versions[0].name,
[pluginId]: pluginData.versions[0]!.name,
}),
{},
),
@ -277,7 +277,7 @@ export default function SearchPage(): JSX.Element {
const {
isIntersecting,
boundingClientRect: {y: currentY},
} = entries[0];
} = entries[0]!;
if (isIntersecting && prevY.current > currentY) {
searchResultStateDispatcher({type: 'advance'});

View file

@ -41,7 +41,7 @@ export default function applyTrailingSlash(
}
// The trailing slash should be handled before the ?search#hash !
const [pathname] = path.split(/[#?]/);
const [pathname] = path.split(/[#?]/) as [string, ...string[]];
// Never transform '/' to ''
// Never remove the baseUrl trailing slash!

View file

@ -6,11 +6,11 @@
*/
export const NODE_MAJOR_VERSION = parseInt(
process.versions.node.split('.')[0],
process.versions.node.split('.')[0]!,
10,
);
export const NODE_MINOR_VERSION = parseInt(
process.versions.node.split('.')[1],
process.versions.node.split('.')[1]!,
10,
);

View file

@ -48,12 +48,13 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
let lastCodeFence = '';
const lines = fileString.split('\n').map((line) => {
if (line.trim().startsWith('```')) {
const codeFence = line.trim().match(/^`+/)![0]!;
if (!fencedBlock) {
fencedBlock = true;
[lastCodeFence] = line.trim().match(/^`+/)!;
lastCodeFence = codeFence;
// If we are in a ````-fenced block, all ``` would be plain text instead
// of fences
} else if (line.trim().match(/^`+/)![0].length >= lastCodeFence.length) {
} else if (codeFence.length >= lastCodeFence.length) {
fencedBlock = false;
}
}
@ -71,7 +72,7 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
let mdMatch = mdRegex.exec(modifiedLine);
while (mdMatch !== null) {
// Replace it to correct html link.
const mdLink = mdMatch.groups!.filename;
const mdLink = mdMatch.groups!.filename!;
const sourcesToTry = [
path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)),

View file

@ -18,8 +18,8 @@ export function parseMarkdownHeadingId(heading: string): {
const matches = customHeadingIdRegex.exec(heading);
if (matches) {
return {
text: matches.groups!.text,
id: matches.groups!.id,
text: matches.groups!.text!,
id: matches.groups!.id!,
};
}
return {text: heading, id: undefined};
@ -51,14 +51,13 @@ export function createExcerpt(fileString: string): string | undefined {
// Skip code block line.
if (fileLine.trim().startsWith('```')) {
const codeFence = fileLine.trim().match(/^`+/)![0]!;
if (!inCode) {
inCode = true;
[lastCodeFence] = fileLine.trim().match(/^`+/)!;
lastCodeFence = codeFence;
// If we are in a ````-fenced block, all ``` would be plain text instead
// of fences
} else if (
fileLine.trim().match(/^`+/)![0].length >= lastCodeFence.length
) {
} else if (codeFence.length >= lastCodeFence.length) {
inCode = false;
}
continue;

View file

@ -80,13 +80,13 @@ export function groupTaggedItems<Item>(
// TODO: it's not really clear what should be the behavior if 2 items have
// the same tag but the permalink is different for each
// For now, the first tag found wins
result[tag.permalink] = result[tag.permalink] ?? {
result[tag.permalink] ??= {
tag,
items: [],
};
// Add item to group
result[tag.permalink].items.push(item);
result[tag.permalink]!.items.push(item);
}
items.forEach((item) => {

View file

@ -15,10 +15,17 @@ export function normalizeUrl(rawUrls: string[]): string {
let hasStartingSlash = false;
let hasEndingSlash = false;
const isNonEmptyArray = (arr: string[]): arr is [string, ...string[]] =>
arr.length > 0;
if (!isNonEmptyArray(urls)) {
return '';
}
// If the first part is a plain protocol, we combine it with the next part.
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
const first = urls.shift();
if (first!.startsWith('file:') && urls[0].startsWith('/')) {
const first = urls.shift()!;
if (first.startsWith('file:') && urls[0].startsWith('/')) {
// Force a double slash here, else we lose the information that the next
// segment is an absolute path
urls[0] = `${first}//${urls[0]}`;

View file

@ -38,7 +38,7 @@ function clearConsole(): void {
function getProcessIdOnPort(port: number): string {
return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
.toString()
.split('\n')[0]
.split('\n')[0]!
.trim();
}

View file

@ -45,7 +45,7 @@ class PendingNavigation extends React.Component<Props, State> {
// Intercept location update and still show current route until next route
// is done loading.
shouldComponentUpdate(nextProps: Props, nextState: State) {
override shouldComponentUpdate(nextProps: Props, nextState: State) {
const routeDidChange = nextProps.location !== this.props.location;
const {routes, delay} = this.props;
@ -116,7 +116,7 @@ class PendingNavigation extends React.Component<Props, State> {
nprogress.done();
}
render() {
override render() {
const {children, location} = this.props;
return (
<Route location={normalizeLocation(location)} render={() => children} />

View file

@ -27,7 +27,7 @@ export default function ComponentCreator(
}
const chunkNamesKey = `${path}-${hash}`;
const chunkNames = routesChunkNames[chunkNamesKey];
const chunkNames = routesChunkNames[chunkNamesKey]!;
const optsModules: string[] = [];
const optsWebpack: string[] = [];
const optsLoader: OptsLoader = {};
@ -47,8 +47,8 @@ export default function ComponentCreator(
]
*/
const flatChunkNames = flat(chunkNames);
Object.keys(flatChunkNames).forEach((key) => {
const chunkRegistry = registry[flatChunkNames[key]];
Object.entries(flatChunkNames).forEach(([key, chunkName]) => {
const chunkRegistry = registry[chunkName];
if (chunkRegistry) {
// eslint-disable-next-line prefer-destructuring
optsLoader[key] = chunkRegistry[0];
@ -68,16 +68,16 @@ export default function ComponentCreator(
Object.keys(loaded).forEach((key) => {
let val = loadedModules;
const keyPath = key.split('.');
for (let i = 0; i < keyPath.length - 1; i += 1) {
val = val[keyPath[i]];
}
val[keyPath[keyPath.length - 1]] = loaded[key].default;
keyPath.slice(0, -1).forEach((k) => {
val = val[k];
});
val[keyPath[keyPath.length - 1]!] = loaded[key].default;
const nonDefaultKeys = Object.keys(loaded[key]).filter(
(k) => k !== 'default',
);
if (nonDefaultKeys && nonDefaultKeys.length) {
nonDefaultKeys.forEach((nonDefaultKey) => {
val[keyPath[keyPath.length - 1]][nonDefaultKey] =
val[keyPath[keyPath.length - 1]!][nonDefaultKey] =
loaded[key][nonDefaultKey];
});
}

View file

@ -21,14 +21,14 @@ export default class ErrorBoundary extends React.Component<Props, State> {
this.state = {error: null};
}
componentDidCatch(error: Error): void {
override componentDidCatch(error: Error): void {
// Catch errors in any components below and re-render with error message
if (ExecutionEnvironment.canUseDOM) {
this.setState({error});
}
}
render(): ReactNode {
override render(): ReactNode {
const {children} = this.props;
const {error} = this.state;

View file

@ -25,7 +25,7 @@ function getLocalizedMessage({
);
}
return codeTranslations[(id ?? message)!] ?? message ?? id;
return codeTranslations[(id ?? message)!] ?? message ?? id!;
}
// Imperative translation API is useful for some edge-cases:

View file

@ -15,8 +15,7 @@ export default function flat(target: RouteChunksTree): Record<string, string> {
const output: Record<string, string> = {};
function step(object: RouteChunksTree, prefix?: string | number) {
Object.keys(object).forEach((key: string | number) => {
const value = object[key];
Object.entries(object).forEach(([key, value]) => {
const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
if (isTree(value)) {

View file

@ -37,9 +37,9 @@ function linkPrefetchStrategy(url: string) {
link.onerror = reject;
const parentElement =
document.getElementsByTagName('head')[0] ||
document.getElementsByName('script')[0].parentNode;
parentElement.appendChild(link);
document.getElementsByTagName('head')[0] ??
document.getElementsByName('script')[0]?.parentNode;
parentElement?.appendChild(link);
});
}

View file

@ -75,7 +75,7 @@ async function doRender(locals: Locals & {path: string}) {
ssrTemplate,
noIndex,
} = locals;
const location = routesLocation[locals.path];
const location = routesLocation[locals.path]!;
await preload(routes, location);
const modules = new Set<string>();
const context = {};

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import type {ReactNode} from 'react';
import React, {type ReactNode} from 'react';
// Wrapper at the very top of the app, that is applied constantly
// and does not depend on current route (unlike the layout)
@ -14,6 +14,6 @@ import type {ReactNode} from 'react';
// and these providers won't reset state when we navigate
//
// See https://github.com/facebook/docusaurus/issues/3919
export default function Root({children}: {children: ReactNode}): ReactNode {
return children;
export default function Root({children}: {children: ReactNode}): JSX.Element {
return <>{children}</>;
}

View file

@ -79,7 +79,7 @@ export default async function build(
// We need the default locale to always be the 1st in the list. If we build it
// last, it would "erase" the localized sites built in sub-folders
const orderedLocales: string[] = [
const orderedLocales: [string, ...string[]] = [
i18n.defaultLocale,
...i18n.locales.filter((locale) => locale !== i18n.defaultLocale),
];
@ -89,7 +89,7 @@ export default async function build(
orderedLocales.indexOf(locale) === orderedLocales.length - 1;
return tryToBuildLocale({locale, isLastLocale});
});
return results[0];
return results[0]!;
}
async function buildLocale({

View file

@ -30,7 +30,7 @@ export async function initSwizzleContext(
return {
plugins: plugins.map((plugin, pluginIndex) => ({
plugin: pluginsNormalized[pluginIndex],
plugin: pluginsNormalized[pluginIndex]!,
instance: plugin,
})),
};

View file

@ -35,7 +35,7 @@ type BrokenLink = {
// matchRoutes does not support qs/anchors, so we remove it!
function onlyPathname(link: string) {
return link.split('#')[0].split('?')[0];
return link.split('#')[0]!.split('?')[0]!;
}
function getPageBrokenLinks({

View file

@ -359,13 +359,13 @@ export default ${JSON.stringify(siteConfig, null, 2)};`,
generatedFilesDir,
'registry.js',
`export default {
${Object.keys(registry)
.sort()
${Object.entries(registry)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(
(key) =>
` '${key}': [${registry[key].loader}, '${escapePath(
registry[key].modulePath,
)}', require.resolveWeak('${escapePath(registry[key].modulePath)}')],`,
([key, chunk]) =>
` '${key}': [${chunk.loader}, '${escapePath(
chunk.modulePath,
)}', require.resolveWeak('${escapePath(chunk.modulePath)}')],`,
)
.join('\n')}};\n`,
);

View file

@ -126,7 +126,7 @@ export async function loadPlugins({
.mapValues((nameItems) =>
_.chain(nameItems)
.groupBy((item) => item.options.id ?? DEFAULT_PLUGIN_ID)
.mapValues((idItems) => idItems[0].content)
.mapValues((idItems) => idItems[0]!.content)
.value(),
)
.value();
@ -177,7 +177,7 @@ export async function loadPlugins({
data,
) => {
globalData[plugin.name] = globalData[plugin.name] ?? {};
globalData[plugin.name][pluginId] = data;
globalData[plugin.name]![pluginId] = data;
};
const actions: PluginContentLoadedActions = {

View file

@ -249,8 +249,8 @@ function genRouteChunkNames(
}
const newValue: ChunkNames = {};
Object.keys(value).forEach((key) => {
newValue[key] = genRouteChunkNames(registry, value[key], key, name);
Object.entries(value).forEach(([key, v]) => {
newValue[key] = genRouteChunkNames(registry, v, key, name);
});
return newValue;
}

View file

@ -20,7 +20,7 @@ export async function loadThemeAliases(
for (const themePath of themePaths) {
const themeAliases = await themeAlias(themePath, true);
Object.keys(themeAliases).forEach((aliasKey) => {
Object.entries(themeAliases).forEach(([aliasKey, alias]) => {
// If this alias shadows a previous one, use @theme-init to preserve the
// initial one. @theme-init is only applied once: to the initial theme
// that provided this component
@ -28,10 +28,10 @@ export async function loadThemeAliases(
const componentName = aliasKey.substring(aliasKey.indexOf('/') + 1);
const initAlias = `@theme-init/${componentName}`;
if (!(initAlias in aliases)) {
aliases[initAlias] = aliases[aliasKey];
aliases[initAlias] = aliases[aliasKey]!;
}
}
aliases[aliasKey] = themeAliases[aliasKey];
aliases[aliasKey] = alias;
});
}

View file

@ -340,7 +340,7 @@ ${sourceWarningPart(path.node)}`,
const args = path.get('arguments');
if (args.length === 1 || args.length === 2) {
const firstArgPath = args[0];
const firstArgPath = args[0]!;
// translate("x" + "y"); => translate("xy");
const firstArgEvaluated = firstArgPath.evaluate();

View file

@ -25,11 +25,12 @@ export default class ChunkAssetPlugin {
compiler.hooks.thisCompilation.tap(pluginName, ({mainTemplate}) => {
mainTemplate.hooks.requireExtensions.tap(pluginName, (source, chunk) => {
const chunkIdToName = chunk.getChunkMaps(false).name;
const chunkNameToId = Object.create(null);
Object.keys(chunkIdToName).forEach((chunkId) => {
const chunkName = chunkIdToName[chunkId];
chunkNameToId[chunkName] = chunkId;
});
const chunkNameToId = Object.fromEntries(
Object.entries(chunkIdToName).map(([chunkId, chunkName]) => [
chunkName,
chunkId,
]),
);
const buf = [source];
buf.push('// function to get chunk asset');
buf.push(

View file

@ -14,7 +14,7 @@ function showError(arr: string[]) {
}
export default class LogPlugin extends WebpackBar {
apply(compiler: Compiler): void {
override apply(compiler: Compiler): void {
super.apply(compiler);
// TODO can't this be done in compile(configs) alongside the warnings???

View file

@ -5,7 +5,6 @@
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"outDir": "lib",
"jsx": "react",
"allowJs": true
},
"include": ["src"],

View file

@ -39,7 +39,7 @@ export default async function lqipLoader(
if (contentIsUrlExport) {
source = content.match(
/^(?:export default|module.exports =) (?<source>.*)/,
)!.groups!.source;
)!.groups!.source!;
} else {
if (!contentIsFileExport) {
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
@ -48,7 +48,7 @@ export default async function lqipLoader(
}
source = content.match(
/^(?:export default|module.exports =) (?<source>.*);/,
)!.groups!.source;
)!.groups!.source!;
}
const outputPromises: [Promise<string> | null, Promise<string[]> | null] = [

View file

@ -25,14 +25,15 @@ const SUPPORTED_MIMES: Record<string, string> = {
export async function base64(file: string): Promise<string> {
let extension = path.extname(file);
extension = extension.split('.').pop()!;
const mime = SUPPORTED_MIMES[extension];
if (!SUPPORTED_MIMES[extension]) {
if (!mime) {
throw new Error(ERROR_EXT);
}
try {
const data = await sharp(file).resize(10).toBuffer();
return toBase64(SUPPORTED_MIMES[extension], data);
return toBase64(mime, data);
} catch (err) {
logger.error`Generation of base64 failed for image path=${file}.`;
throw err;

View file

@ -1,42 +1,48 @@
{
"compilerOptions": {
/* Emit */
"target": "ES2020",
"module": "commonjs",
"lib": ["ESNext", "DOM"],
"declaration": true,
"declarationMap": false,
"jsx": "react",
"importHelpers": true,
"noEmitHelpers": true,
/* Strict Type-Checking Options */
"strict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
/* Additional Checks */
"noUnusedLocals": false, // ensured by eslint, should not block compilation
"noImplicitReturns": true,
"allowUnreachableCode": false,
// Too hard to turn on
"exactOptionalPropertyTypes": false,
"noFallthroughCasesInSwitch": true,
/* Disabled on purpose (handled by ESLint, should not block compilation) */
"noImplicitOverride": true,
"noImplicitReturns": true,
// `process.env` is usually accessed as property
"noPropertyAccessFromIndexSignature": false,
"noUncheckedIndexedAccess": true,
/* strict family */
"strict": true,
"alwaysStrict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"useUnknownInCatchVariables": true,
/* Handled by ESLint */
"noUnusedLocals": false,
"noUnusedParameters": false,
"importsNotUsedAsValues": "remove",
/* Module Resolution Options */
/* Module Resolution */
"moduleResolution": "node",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
/* Advanced Options */
"resolveJsonModule": true,
"skipLibCheck": true, // @types/webpack and webpack/types.d.ts are not the same thing
/* Use tslib */
"importHelpers": true,
"noEmitHelpers": true
"skipLibCheck": true // @types/webpack and webpack/types.d.ts are not the same thing
},
"exclude": ["node_modules", "**/__tests__/**/*", "**/lib/**/*"]
}