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 { ): string {
let res = ''; let res = '';
values.forEach((value, idx) => { values.forEach((value, idx) => {
const flag = msgs[idx].match(/[a-z]+=$/); const flag = msgs[idx]!.match(/[a-z]+=$/);
res += msgs[idx].replace(/[a-z]+=$/, ''); res += msgs[idx]!.replace(/[a-z]+=$/, '');
const format = (() => { const format = (() => {
if (!flag) { if (!flag) {
return (a: string | number) => a; return (a: string | number) => a;

View file

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

View file

@ -37,8 +37,8 @@ export default function extractMetadata(content: string): Data {
// New line characters => to handle all operating systems. // New line characters => to handle all operating systems.
const lines = (both.header ?? '').split(/\r?\n/); const lines = (both.header ?? '').split(/\r?\n/);
for (let i = 0; i < lines.length - 1; i += 1) { lines.slice(0, -1).forEach((line) => {
const keyValue = lines[i].split(':'); const keyValue = line.split(':') as [string, ...string[]];
const key = keyValue[0].trim(); const key = keyValue[0].trim();
let value = keyValue.slice(1).join(':').trim(); let value = keyValue.slice(1).join(':').trim();
try { try {
@ -47,7 +47,7 @@ export default function extractMetadata(content: string): Data {
// Ignore the error as it means it's not a JSON value. // Ignore the error as it means it's not a JSON value.
} }
metadata[key] = value; metadata[key] = value;
} });
return {metadata, rawContent: both.content}; 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 // Order matters: if a sidebar file doesn't exist, we have to use the
// previous version's // previous version's
for (let i = 0; i < versions.length; i += 1) { for (let i = 0; i < versions.length; i += 1) {
const version = versions[i]; const version = versions[i]!;
let sidebarEntries: SidebarEntries; let sidebarEntries: SidebarEntries;
const sidebarPath = path.join( const sidebarPath = path.join(
siteDir, siteDir,
@ -545,7 +545,7 @@ async function migrateVersionedSidebar(
try { try {
sidebarEntries = JSON.parse(await fs.readFile(sidebarPath, 'utf-8')); sidebarEntries = JSON.parse(await fs.readFile(sidebarPath, 'utf-8'));
} catch { } catch {
sidebars.push({version, entries: sidebars[i - 1].entries}); sidebars.push({version, entries: sidebars[i - 1]!.entries});
return; return;
} }
const newSidebar = Object.entries(sidebarEntries).reduce( const newSidebar = Object.entries(sidebarEntries).reduce(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -49,7 +49,7 @@ async function readCategoriesMetadata(contentPath: string) {
const categoryToFile = _.groupBy(categoryFiles, path.dirname); const categoryToFile = _.groupBy(categoryFiles, path.dirname);
return combinePromises( return combinePromises(
_.mapValues(categoryToFile, async (files, folder) => { _.mapValues(categoryToFile, async (files, folder) => {
const [filePath] = files; const filePath = files[0]!;
if (files.length > 1) { if (files.length > 1) {
logger.warn`There are more than one category metadata files for path=${folder}: ${files.join( 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) { if (!sidebarName) {
return emptySidebarNavigation(); return emptySidebarNavigation();
} }
if (!sidebarNameToNavigationItems[sidebarName]) { const navigationItems = sidebarNameToNavigationItems[sidebarName];
if (!navigationItems) {
throw new Error( throw new Error(
`Doc with ID ${docId} wants to display sidebar ${sidebarName} but a sidebar with this name doesn't exist`, `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) => { const currentItemIndex = navigationItems.findIndex((item) => {
if (item.type === 'doc') { if (item.type === 'doc') {
return item.id === docId; return item.id === docId;
@ -263,7 +263,7 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
if (!sidebarName) { if (!sidebarName) {
return emptySidebarNavigation(); return emptySidebarNavigation();
} }
const navigationItems = sidebarNameToNavigationItems[sidebarName]; const navigationItems = sidebarNameToNavigationItems[sidebarName]!;
const currentItemIndex = navigationItems.findIndex( const currentItemIndex = navigationItems.findIndex(
isCurrentCategoryGeneratedIndexItem, isCurrentCategoryGeneratedIndexItem,
); );
@ -341,7 +341,7 @@ Available document ids are:
getCategoryGeneratedIndexList, getCategoryGeneratedIndexList,
getCategoryGeneratedIndexNavigation, getCategoryGeneratedIndexNavigation,
checkSidebarsDocIds, checkSidebarsDocIds,
getFirstLink: (id) => getFirstLink(sidebars[id]), getFirstLink: (id) => getFirstLink(sidebars[id]!),
}; };
} }

View file

@ -274,10 +274,14 @@ function translateVersion(
translationFiles: Record<string, TranslationFile>, translationFiles: Record<string, TranslationFile>,
): LoadedVersion { ): LoadedVersion {
const versionTranslations = const versionTranslations =
translationFiles[getVersionFileName(version.versionName)].content; translationFiles[getVersionFileName(version.versionName)]?.content;
if (!versionTranslations) {
return version;
}
return { return {
...version, ...version,
versionLabel: versionTranslations['version.label']?.message, versionLabel:
versionTranslations['version.label']?.message ?? version.versionLabel,
sidebars: translateSidebars(version, versionTranslations), sidebars: translateSidebars(version, versionTranslations),
// docs: translateDocs(version.docs, 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 // "last version" is not a very good concept nor api surface
function getDefaultLastVersionName(versionNames: string[]) { function getDefaultLastVersionName(versionNames: string[]) {
if (versionNames.length === 1) { if (versionNames.length === 1) {
return versionNames[0]; return versionNames[0]!;
} }
return versionNames.filter( return versionNames.filter(
(versionName) => versionName !== CURRENT_VERSION_NAME, (versionName) => versionName !== CURRENT_VERSION_NAME,
)[0]; )[0]!;
} }
function checkVersionsOptions( function checkVersionsOptions(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -108,7 +108,7 @@ function TabsComponent(props: Props): JSX.Element {
) => { ) => {
const newTab = event.currentTarget; const newTab = event.currentTarget;
const newTabIndex = tabRefs.indexOf(newTab); const newTabIndex = tabRefs.indexOf(newTab);
const newTabValue = values[newTabIndex].value; const newTabValue = values[newTabIndex]!.value;
if (newTabValue !== selectedValue) { if (newTabValue !== selectedValue) {
blockElementScrollPositionUntilNextRender(newTab); blockElementScrollPositionUntilNextRender(newTab);
@ -126,12 +126,12 @@ function TabsComponent(props: Props): JSX.Element {
switch (event.key) { switch (event.key) {
case 'ArrowRight': { case 'ArrowRight': {
const nextTab = tabRefs.indexOf(event.currentTarget) + 1; const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
focusElement = tabRefs[nextTab] || tabRefs[0]; focusElement = tabRefs[nextTab] || tabRefs[0]!;
break; break;
} }
case 'ArrowLeft': { case 'ArrowLeft': {
const prevTab = tabRefs.indexOf(event.currentTarget) - 1; const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
focusElement = tabRefs[prevTab] || tabRefs[tabRefs.length - 1]; focusElement = tabRefs[prevTab] || tabRefs[tabRefs.length - 1]!;
break; break;
} }
default: default:
@ -181,7 +181,7 @@ function TabsComponent(props: Props): JSX.Element {
cloneElement( cloneElement(
children.filter( children.filter(
(tabItem) => tabItem.props.value === selectedValue, (tabItem) => tabItem.props.value === selectedValue,
)[0], )[0]!,
{className: 'margin-vert--md'}, {className: 'margin-vert--md'},
) )
) : ( ) : (

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -25,7 +25,7 @@ export function useDocsPreferredVersion(
const docsData = useDocsData(pluginId); const docsData = useDocsData(pluginId);
const [state, api] = useDocsPreferredVersionContext(); const [state, api] = useDocsPreferredVersionContext();
const {preferredVersionName} = state[pluginId]; const {preferredVersionName} = state[pluginId]!;
const preferredVersion = preferredVersionName const preferredVersion = preferredVersionName
? docsData.versions.find((version) => version.name === preferredVersionName) ? docsData.versions.find((version) => version.name === preferredVersionName)
@ -49,8 +49,8 @@ export function useDocsPreferredVersionByPluginId(): Record<
const [state] = useDocsPreferredVersionContext(); const [state] = useDocsPreferredVersionContext();
function getPluginIdPreferredVersion(pluginId: string) { function getPluginIdPreferredVersion(pluginId: string) {
const docsData = allDocsData[pluginId]; const docsData = allDocsData[pluginId]!;
const {preferredVersionName} = state[pluginId]; const {preferredVersionName} = state[pluginId]!;
return preferredVersionName return preferredVersionName
? docsData.versions.find( ? 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[]}>; export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>;
function getTagLetter(tag: string): string { function getTagLetter(tag: string): string {
return tag[0].toUpperCase(); return tag[0]!.toUpperCase();
} }
export function listTagsByLetters( export function listTagsByLetters(
@ -29,8 +29,8 @@ export function listTagsByLetters(
const groups: Record<string, TagsListItem[]> = {}; const groups: Record<string, TagsListItem[]> = {};
Object.values(tags).forEach((tag) => { Object.values(tags).forEach((tag) => {
const letter = getTagLetter(tag.name); const letter = getTagLetter(tag.name);
groups[letter] = groups[letter] ?? []; groups[letter] ??= [];
groups[letter].push(tag); groups[letter]!.push(tag);
}); });
return ( return (

View file

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

View file

@ -34,7 +34,9 @@ export function useContextualSearchFilters(): useContextualSearchFiltersReturns
const preferredVersion = docsPreferredVersionByPluginId[pluginId]; 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; const version = activeVersion ?? preferredVersion ?? latestVersion;

View file

@ -99,7 +99,7 @@ function selectPluralMessage(
const parts = pluralMessages.split(separator); const parts = pluralMessages.split(separator);
if (parts.length === 1) { if (parts.length === 1) {
return parts[0]; return parts[0]!;
} }
if (parts.length > localePluralForms.pluralForms.length) { if (parts.length > localePluralForms.pluralForms.length) {
console.error( console.error(
@ -110,7 +110,7 @@ function selectPluralMessage(
const pluralFormIndex = localePluralForms.pluralForms.indexOf(pluralForm); const pluralFormIndex = localePluralForms.pluralForms.indexOf(pluralForm);
// In case of not enough plural form messages, we take the last one (other) // In case of not enough plural form messages, we take the last one (other)
// instead of returning undefined // instead of returning undefined
return parts[Math.min(pluralFormIndex, parts.length - 1)]; return parts[Math.min(pluralFormIndex, parts.length - 1)]!;
} }
export function usePluralForm(): { 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) // no anchor under viewport top? (ie we are at the bottom of the page)
// => highlight the last anchor found // => highlight the last anchor found
return anchors[anchors.length - 1]; return anchors[anchors.length - 1] ?? null;
} }
function getLinkAnchorValue(link: HTMLAnchorElement): string { function getLinkAnchorValue(link: HTMLAnchorElement): string {

View file

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

View file

@ -41,7 +41,7 @@ export default function applyTrailingSlash(
} }
// The trailing slash should be handled before the ?search#hash ! // 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 transform '/' to ''
// Never remove the baseUrl trailing slash! // Never remove the baseUrl trailing slash!

View file

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

View file

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

View file

@ -18,8 +18,8 @@ export function parseMarkdownHeadingId(heading: string): {
const matches = customHeadingIdRegex.exec(heading); const matches = customHeadingIdRegex.exec(heading);
if (matches) { if (matches) {
return { return {
text: matches.groups!.text, text: matches.groups!.text!,
id: matches.groups!.id, id: matches.groups!.id!,
}; };
} }
return {text: heading, id: undefined}; return {text: heading, id: undefined};
@ -51,14 +51,13 @@ export function createExcerpt(fileString: string): string | undefined {
// Skip code block line. // Skip code block line.
if (fileLine.trim().startsWith('```')) { if (fileLine.trim().startsWith('```')) {
const codeFence = fileLine.trim().match(/^`+/)![0]!;
if (!inCode) { if (!inCode) {
inCode = true; inCode = true;
[lastCodeFence] = fileLine.trim().match(/^`+/)!; lastCodeFence = codeFence;
// If we are in a ````-fenced block, all ``` would be plain text instead // If we are in a ````-fenced block, all ``` would be plain text instead
// of fences // of fences
} else if ( } else if (codeFence.length >= lastCodeFence.length) {
fileLine.trim().match(/^`+/)![0].length >= lastCodeFence.length
) {
inCode = false; inCode = false;
} }
continue; 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 // 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 // the same tag but the permalink is different for each
// For now, the first tag found wins // For now, the first tag found wins
result[tag.permalink] = result[tag.permalink] ?? { result[tag.permalink] ??= {
tag, tag,
items: [], items: [],
}; };
// Add item to group // Add item to group
result[tag.permalink].items.push(item); result[tag.permalink]!.items.push(item);
} }
items.forEach((item) => { items.forEach((item) => {

View file

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

View file

@ -38,7 +38,7 @@ function clearConsole(): void {
function getProcessIdOnPort(port: number): string { function getProcessIdOnPort(port: number): string {
return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions) return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
.toString() .toString()
.split('\n')[0] .split('\n')[0]!
.trim(); .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 // Intercept location update and still show current route until next route
// is done loading. // is done loading.
shouldComponentUpdate(nextProps: Props, nextState: State) { override shouldComponentUpdate(nextProps: Props, nextState: State) {
const routeDidChange = nextProps.location !== this.props.location; const routeDidChange = nextProps.location !== this.props.location;
const {routes, delay} = this.props; const {routes, delay} = this.props;
@ -116,7 +116,7 @@ class PendingNavigation extends React.Component<Props, State> {
nprogress.done(); nprogress.done();
} }
render() { override render() {
const {children, location} = this.props; const {children, location} = this.props;
return ( return (
<Route location={normalizeLocation(location)} render={() => children} /> <Route location={normalizeLocation(location)} render={() => children} />

View file

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

View file

@ -21,14 +21,14 @@ export default class ErrorBoundary extends React.Component<Props, State> {
this.state = {error: null}; 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 // Catch errors in any components below and re-render with error message
if (ExecutionEnvironment.canUseDOM) { if (ExecutionEnvironment.canUseDOM) {
this.setState({error}); this.setState({error});
} }
} }
render(): ReactNode { override render(): ReactNode {
const {children} = this.props; const {children} = this.props;
const {error} = this.state; 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: // 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> = {}; const output: Record<string, string> = {};
function step(object: RouteChunksTree, prefix?: string | number) { function step(object: RouteChunksTree, prefix?: string | number) {
Object.keys(object).forEach((key: string | number) => { Object.entries(object).forEach(([key, value]) => {
const value = object[key];
const newKey = prefix ? `${prefix}${delimiter}${key}` : key; const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
if (isTree(value)) { if (isTree(value)) {

View file

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

View file

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

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import type {ReactNode} from 'react'; import React, {type ReactNode} from 'react';
// Wrapper at the very top of the app, that is applied constantly // Wrapper at the very top of the app, that is applied constantly
// and does not depend on current route (unlike the layout) // 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 // and these providers won't reset state when we navigate
// //
// See https://github.com/facebook/docusaurus/issues/3919 // See https://github.com/facebook/docusaurus/issues/3919
export default function Root({children}: {children: ReactNode}): ReactNode { export default function Root({children}: {children: ReactNode}): JSX.Element {
return children; 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 // 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 // last, it would "erase" the localized sites built in sub-folders
const orderedLocales: string[] = [ const orderedLocales: [string, ...string[]] = [
i18n.defaultLocale, i18n.defaultLocale,
...i18n.locales.filter((locale) => locale !== i18n.defaultLocale), ...i18n.locales.filter((locale) => locale !== i18n.defaultLocale),
]; ];
@ -89,7 +89,7 @@ export default async function build(
orderedLocales.indexOf(locale) === orderedLocales.length - 1; orderedLocales.indexOf(locale) === orderedLocales.length - 1;
return tryToBuildLocale({locale, isLastLocale}); return tryToBuildLocale({locale, isLastLocale});
}); });
return results[0]; return results[0]!;
} }
async function buildLocale({ async function buildLocale({

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,7 +20,7 @@ export async function loadThemeAliases(
for (const themePath of themePaths) { for (const themePath of themePaths) {
const themeAliases = await themeAlias(themePath, true); 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 // 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 // initial one. @theme-init is only applied once: to the initial theme
// that provided this component // that provided this component
@ -28,10 +28,10 @@ export async function loadThemeAliases(
const componentName = aliasKey.substring(aliasKey.indexOf('/') + 1); const componentName = aliasKey.substring(aliasKey.indexOf('/') + 1);
const initAlias = `@theme-init/${componentName}`; const initAlias = `@theme-init/${componentName}`;
if (!(initAlias in aliases)) { 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'); const args = path.get('arguments');
if (args.length === 1 || args.length === 2) { if (args.length === 1 || args.length === 2) {
const firstArgPath = args[0]; const firstArgPath = args[0]!;
// translate("x" + "y"); => translate("xy"); // translate("x" + "y"); => translate("xy");
const firstArgEvaluated = firstArgPath.evaluate(); const firstArgEvaluated = firstArgPath.evaluate();

View file

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

View file

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

View file

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

View file

@ -39,7 +39,7 @@ export default async function lqipLoader(
if (contentIsUrlExport) { if (contentIsUrlExport) {
source = content.match( source = content.match(
/^(?:export default|module.exports =) (?<source>.*)/, /^(?:export default|module.exports =) (?<source>.*)/,
)!.groups!.source; )!.groups!.source!;
} else { } else {
if (!contentIsFileExport) { if (!contentIsFileExport) {
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
@ -48,7 +48,7 @@ export default async function lqipLoader(
} }
source = content.match( source = content.match(
/^(?:export default|module.exports =) (?<source>.*);/, /^(?:export default|module.exports =) (?<source>.*);/,
)!.groups!.source; )!.groups!.source!;
} }
const outputPromises: [Promise<string> | null, Promise<string[]> | null] = [ 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> { export async function base64(file: string): Promise<string> {
let extension = path.extname(file); let extension = path.extname(file);
extension = extension.split('.').pop()!; extension = extension.split('.').pop()!;
const mime = SUPPORTED_MIMES[extension];
if (!SUPPORTED_MIMES[extension]) { if (!mime) {
throw new Error(ERROR_EXT); throw new Error(ERROR_EXT);
} }
try { try {
const data = await sharp(file).resize(10).toBuffer(); const data = await sharp(file).resize(10).toBuffer();
return toBase64(SUPPORTED_MIMES[extension], data); return toBase64(mime, data);
} catch (err) { } catch (err) {
logger.error`Generation of base64 failed for image path=${file}.`; logger.error`Generation of base64 failed for image path=${file}.`;
throw err; throw err;

View file

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