chore(v2): Fix more eslint errors (#2976)

This commit is contained in:
Sam Zhou 2020-06-21 03:09:00 -04:00 committed by GitHub
parent 3611c96f90
commit 6e43c9bd34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
81 changed files with 375 additions and 237 deletions

View file

@ -85,27 +85,23 @@ module.exports = {
],
'no-unused-vars': OFF,
'@typescript-eslint/no-unused-vars': [ERROR, {argsIgnorePattern: '^_'}],
'@typescript-eslint/ban-ts-comment': [
ERROR,
{'ts-expect-error': 'allow-with-description'},
],
// TODO re-enable some these as errors
// context: https://github.com/facebook/docusaurus/pull/2949
'@typescript-eslint/ban-ts-comment': WARNING,
'@typescript-eslint/ban-types': WARNING,
'import/prefer-default-export': WARNING,
'import/no-extraneous-dependencies': WARNING,
'no-useless-escape': WARNING,
'prefer-template': WARNING,
'no-shadow': WARNING,
'no-param-reassign': WARNING,
'no-else-return': WARNING,
'no-template-curly-in-string': WARNING,
'array-callback-return': WARNING,
camelcase: WARNING,
'no-nested-ternary': WARNING,
'object-shorthand': WARNING,
'no-restricted-syntax': WARNING,
'no-unused-expressions': WARNING,
'consistent-return': WARNING,
'no-useless-return': WARNING,
'@typescript-eslint/no-empty-function': WARNING,
'global-require': WARNING,
'prefer-destructuring': WARNING,
@ -114,8 +110,6 @@ module.exports = {
'no-empty': WARNING,
'no-prototype-builtins': WARNING,
'no-case-declarations': WARNING,
'default-case': WARNING,
'dot-notation': WARNING,
},
overrides: [
{

View file

@ -37,8 +37,6 @@
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
"@babel/preset-typescript": "^7.9.0",
"@typescript-eslint/eslint-plugin": "^3.3.0",
"@typescript-eslint/parser": "^3.3.0",
"@types/express": "^4.17.2",
"@types/fs-extra": "^8.0.1",
"@types/inquirer": "^6.5.0",
@ -54,13 +52,18 @@
"@types/lodash.pick": "^4.4.6",
"@types/lodash.pickby": "^4.6.6",
"@types/node": "^13.11.0",
"@types/react": "^16.9.13",
"@types/react": "^16.9.38",
"@types/react-dev-utils": "^9.0.1",
"@types/react-helmet": "^6.0.0",
"@types/react-loadable": "^5.5.3",
"@types/react-router-config": "^5.0.1",
"@types/semver": "^7.1.0",
"@types/shelljs": "^0.8.6",
"@types/webpack": "^4.41.0",
"@types/webpack-dev-server": "^3.9.0",
"@types/webpack-merge": "^4.1.5",
"@typescript-eslint/eslint-plugin": "^3.3.0",
"@typescript-eslint/parser": "^3.3.0",
"babel-eslint": "^10.0.3",
"concurrently": "^5.2.0",
"enzyme": "^3.10.0",
@ -85,7 +88,7 @@
"rimraf": "^3.0.2",
"serve": "^11.3.2",
"stylelint": "^13.2.1",
"typescript": "^3.7.2"
"typescript": "^3.9.5"
},
"peerDependencies": {
"stylelint-copyright": "^2.0.0"

View file

@ -11,7 +11,7 @@ const chalk = require('chalk');
const semver = require('semver');
const path = require('path');
const program = require('commander');
const {init} = require('../lib');
const {default: init} = require('../lib');
const requiredVersion = require('../package.json').engines.node;
if (!semver.satisfies(process.version, requiredVersion)) {

View file

@ -26,7 +26,10 @@ function isValidGitRepoUrl(gitRepoUrl: string): boolean {
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
}
async function updatePkg(pkgPath: string, obj: any): Promise<void> {
async function updatePkg(
pkgPath: string,
obj: Record<string, unknown>,
): Promise<void> {
const content = await fs.readFile(pkgPath, 'utf-8');
const pkg = JSON.parse(content);
const newPkg = Object.assign(pkg, obj);
@ -34,7 +37,7 @@ async function updatePkg(pkgPath: string, obj: any): Promise<void> {
await fs.outputFile(pkgPath, JSON.stringify(newPkg, null, 2));
}
export async function init(
export default async function init(
rootDir: string,
siteName?: string,
reqTemplate?: string,

View file

@ -14,8 +14,11 @@
"dependencies": {
"@docusaurus/types": "^2.0.0-alpha.58",
"@docusaurus/utils": "^2.0.0-alpha.58",
"chalk": "^3.0.0",
"eta": "^1.1.1",
"fs-extra": "^8.1.0",
"globby": "^10.0.1",
"lodash": "^4.17.15",
"yup": "^0.29.0"
},
"peerDependencies": {

View file

@ -208,7 +208,7 @@ describe('collectRedirects', () => {
{
createRedirects: (routePath) => {
if (routePath === '/') {
return [[`/fromPath`]] as any;
return ([[`/fromPath`]] as unknown) as string;
}
return undefined;
},

View file

@ -49,7 +49,7 @@ describe('normalizePluginOptions', () => {
test('should reject bad fromExtensions user inputs', () => {
expect(() =>
normalizePluginOptions({
fromExtensions: [null, undefined, 123, true] as any,
fromExtensions: ([null, undefined, 123, true] as unknown) as string[],
}),
).toThrowErrorMatchingSnapshot();
});
@ -57,7 +57,7 @@ describe('normalizePluginOptions', () => {
test('should reject bad toExtensions user inputs', () => {
expect(() =>
normalizePluginOptions({
toExtensions: [null, undefined, 123, true] as any,
toExtensions: ([null, undefined, 123, true] as unknown) as string[],
}),
).toThrowErrorMatchingSnapshot();
});
@ -65,7 +65,10 @@ describe('normalizePluginOptions', () => {
test('should reject bad createRedirects user inputs', () => {
expect(() =>
normalizePluginOptions({
createRedirects: ['bad', 'value'] as any,
createRedirects: ([
'bad',
'value',
] as unknown) as CreateRedirectsFnOption,
}),
).toThrowErrorMatchingSnapshot();
});

View file

@ -36,6 +36,7 @@ function validateCollectedRedirects(
.map((redirect) => {
try {
validateRedirect(redirect);
return undefined;
} catch (e) {
return e.message;
}
@ -132,12 +133,11 @@ function createRedirectsOptionRedirects(
function optionToRedirects(option: RedirectOption): RedirectMetadata[] {
if (typeof option.from === 'string') {
return [{from: option.from, to: option.to}];
} else {
return option.from.map((from) => ({
from,
to: option.to,
}));
}
return option.from.map((from) => ({
from,
to: option.to,
}));
}
return flatten(redirectsOption.map(optionToRedirects));

View file

@ -12,6 +12,8 @@ import {RedirectMetadata} from './types';
export const PathnameValidator = Yup.string().test({
name: 'isValidPathname',
message:
// Yup requires this format.
// eslint-disable-next-line no-template-curly-in-string
'${path} is not a valid pathname. Pathname should start with / and not contain any domain or query string',
test: isValidPathname,
});

View file

@ -31,7 +31,7 @@ describe('blogFeed', () => {
routeBasePath: 'blog',
include: ['*.md', '*.mdx'],
feedOptions: {
type: feedType as any,
type: feedType,
copyright: 'Copyright',
},
} as PluginOptions,
@ -62,7 +62,7 @@ describe('blogFeed', () => {
routeBasePath: 'blog',
include: ['*r*.md', '*.mdx'], // skip no-date.md - it won't play nice with snapshots
feedOptions: {
type: feedType as any,
type: feedType,
copyright: 'Copyright',
},
} as PluginOptions,

View file

@ -72,10 +72,10 @@ export async function generateBlogFeed(
blogPosts.forEach((post) => {
const {
id,
metadata: {title, permalink, date, description},
metadata: {title: metadataTitle, permalink, date, description},
} = post;
feed.addItem({
title,
title: metadataTitle,
id,
link: normalizeUrl([siteUrl, permalink]),
date,

View file

@ -205,9 +205,8 @@ export default function pluginContentBlog(
label: tag,
permalink,
};
} else {
return tag;
}
return tag;
});
});
@ -244,7 +243,7 @@ export default function pluginContentBlog(
`~blog/${path.relative(dataDir, source)}`;
const {addRoute, createData} = actions;
const {
blogPosts,
blogPosts: loadedBlogPosts,
blogListPaginated,
blogTags,
blogTagsListPath,
@ -254,7 +253,7 @@ export default function pluginContentBlog(
// Create routes for blog entries.
await Promise.all(
blogPosts.map(async (blogPost) => {
loadedBlogPosts.map(async (blogPost) => {
const {id, metadata} = blogPost;
await createData(
// Note that this created data path must be in sync with
@ -292,12 +291,11 @@ export default function pluginContentBlog(
exact: true,
modules: {
items: items.map((postID) => {
const metadata = blogItemsToMetadata[postID];
// To tell routes.js this is an import and not a nested object to recurse.
return {
content: {
__import: true,
path: metadata.source,
path: blogItemsToMetadata[postID].source,
query: {
truncated: true,
},
@ -481,22 +479,26 @@ export default function pluginContentBlog(
};
const headTags: HtmlTags = [];
feedTypes.map((feedType) => {
feedTypes.forEach((feedType) => {
const feedConfig = feedsConfig[feedType] || {};
if (!feedsConfig) {
return;
}
const {type, path, title} = feedConfig;
const {type, path: feedConfigPath, title: feedConfigTitle} = feedConfig;
headTags.push({
tagName: 'link',
attributes: {
rel: 'alternate',
type,
href: normalizeUrl([baseUrl, options.routeBasePath, path]),
title,
href: normalizeUrl([
baseUrl,
options.routeBasePath,
feedConfigPath,
]),
title: feedConfigTitle,
},
});
});

View file

@ -170,7 +170,8 @@ describe('simple site', () => {
});
// unrelated frontmatter is not part of metadata
expect(data['unrelated_frontmatter']).toBeUndefined();
// @ts-expect-error: It doesn't exist, so the test will show it's undefined.
expect(data.unrelated_frontmatter).toBeUndefined();
});
test('docs with last update time and author', async () => {

View file

@ -14,15 +14,15 @@ import {
VERSIONED_SIDEBARS_DIR,
} from './constants';
export function getVersionedDocsDir(siteDir: string) {
export function getVersionedDocsDir(siteDir: string): string {
return path.join(siteDir, VERSIONED_DOCS_DIR);
}
export function getVersionedSidebarsDir(siteDir: string) {
export function getVersionedSidebarsDir(siteDir: string): string {
return path.join(siteDir, VERSIONED_SIDEBARS_DIR);
}
export function getVersionsJSONFile(siteDir: string) {
export function getVersionsJSONFile(siteDir: string): string {
return path.join(siteDir, VERSIONS_JSON_FILE);
}
@ -41,6 +41,7 @@ export default function (siteDir: string): Env {
fs.readFileSync(versionsJSONFile, 'utf8'),
);
if (parsedVersions && parsedVersions.length > 0) {
// eslint-disable-next-line prefer-destructuring
versioning.latestVersion = parsedVersions[0];
versioning.enabled = true;
versioning.versions = parsedVersions;

View file

@ -378,9 +378,7 @@ Available document ids=
}),
);
return routes.sort((a, b) =>
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
);
return routes.sort((a, b) => a.path.localeCompare(b.path));
};
// This is the base route of the document root (for a doc given version)
@ -400,10 +398,10 @@ Available document ids=
// Important: the layout component should not end with /,
// as it conflicts with the home doc
// Workaround fix for https://github.com/facebook/docusaurus/issues/2917
const path = docsBaseRoute === '/' ? '' : docsBaseRoute;
const docsPath = docsBaseRoute === '/' ? '' : docsBaseRoute;
addRoute({
path,
path: docsPath,
exact: false, // allow matching /docs/* as well
component: docLayoutComponent, // main docs component (DocPage)
routes, // subroute for each doc
@ -466,7 +464,7 @@ Available document ids=
const routes = await genRoutes(Object.values(content.docsMetadata));
const docsBaseMetadata = createDocsBaseMetadata();
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath]);
return addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
await addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
}
},

View file

@ -41,13 +41,12 @@ function inferVersion(
.replace(/^version-/, '');
if (inferredVersion && versioning.versions.includes(inferredVersion)) {
return inferredVersion;
} else {
throw new Error(
`Can't infer version from folder=${dirName}
}
throw new Error(
`Can't infer version from folder=${dirName}
Expected versions:
- ${versioning.versions.join('- ')}`,
);
}
);
} else {
return 'next';
}

View file

@ -30,6 +30,7 @@ export default function createOrder(allSidebars: Sidebar = {}): Order {
case 'doc':
ids.push(item.id);
break;
default:
}
});
};

View file

@ -45,8 +45,12 @@ function normalizeCategoryShorthand(
/**
* Check that item contains only allowed keys.
*/
function assertItem(item: Object, keys: string[]): void {
function assertItem<K extends string>(
item: any,
keys: K[],
): asserts item is Record<K, any> {
const unknownKeys = Object.keys(item).filter(
// @ts-expect-error: key is always string
(key) => !keys.includes(key) && key !== 'type',
);
@ -59,7 +63,9 @@ function assertItem(item: Object, keys: string[]): void {
}
}
function assertIsCategory(item: any): asserts item is SidebarItemCategoryRaw {
function assertIsCategory(
item: unknown,
): asserts item is SidebarItemCategoryRaw {
assertItem(item, ['items', 'label', 'collapsed']);
if (typeof item.label !== 'string') {
throw new Error(
@ -79,7 +85,7 @@ function assertIsCategory(item: any): asserts item is SidebarItemCategoryRaw {
}
}
function assertIsDoc(item: any): asserts item is SidebarItemDoc {
function assertIsDoc(item: unknown): asserts item is SidebarItemDoc {
assertItem(item, ['id']);
if (typeof item.id !== 'string') {
throw new Error(
@ -88,7 +94,7 @@ function assertIsDoc(item: any): asserts item is SidebarItemDoc {
}
}
function assertIsLink(item: any): asserts item is SidebarItemLink {
function assertIsLink(item: unknown): asserts item is SidebarItemLink {
assertItem(item, ['href', 'label']);
if (typeof item.href !== 'string') {
throw new Error(
@ -175,7 +181,7 @@ export default function loadSidebars(sidebarPaths?: string[]): Sidebar {
return {} as Sidebar;
}
sidebarPaths.map((sidebarPath) => {
sidebarPaths.forEach((sidebarPath) => {
if (sidebarPath && fs.existsSync(sidebarPath)) {
const sidebar = importFresh(sidebarPath) as SidebarRaw;
Object.assign(allSidebars, sidebar);

View file

@ -5,13 +5,20 @@
* LICENSE file in the root directory of this source tree.
*/
let versions: string[] = [];
let versions: string[];
try {
// eslint-disable-next-line global-require
versions = require('@site/versions.json');
} catch (e) {}
} catch {
versions = [];
}
function useVersioning() {
function useVersioning(): {
versioningEnabled: boolean;
versions: string[];
latestVersion: string;
} {
return {
versioningEnabled: versions.length > 0,
versions,

View file

@ -65,7 +65,7 @@ export type SidebarItemRaw =
| SidebarItemCategoryRaw
| {
type: string;
[key: string]: any;
[key: string]: unknown;
};
export interface SidebarCategoryShorthandRaw {

View file

@ -15,6 +15,8 @@ import path from 'path';
import {Sidebar, PathOptions, SidebarItem} from './types';
import loadSidebars from './sidebars';
// Tests depend on non-default export for mocking.
// eslint-disable-next-line import/prefer-default-export
export function docsVersion(
version: string | null | undefined,
siteDir: string,

View file

@ -4,13 +4,16 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {LoadContext} from '@docusaurus/types';
import {LoadContext, Plugin} from '@docusaurus/types';
import {PluginOptions} from './types';
import {Configuration} from 'webpack';
import path from 'path';
export default function (_context: LoadContext, options: PluginOptions) {
export default function (
_context: LoadContext,
options: PluginOptions,
): Plugin<void> {
const isProd = process.env.NODE_ENV === 'production';
return {

View file

@ -13,6 +13,7 @@
"license": "MIT",
"dependencies": {
"@docusaurus/types": "^2.0.0-alpha.58",
"fs-extra": "^8.1.0",
"sitemap": "^3.2.2"
},
"peerDependencies": {

View file

@ -28,7 +28,7 @@ describe('createSitemap', () => {
test('empty site', () => {
expect(() => {
createSitemap({} as DocusaurusConfig, [], {} as any);
createSitemap({} as DocusaurusConfig, [], {});
}).toThrowErrorMatchingInlineSnapshot(
`"url in docusaurus.config.js cannot be empty/undefined"`,
);

View file

@ -13,7 +13,7 @@ export default function createSitemap(
siteConfig: DocusaurusConfig,
routesPaths: string[],
options: PluginOptions,
) {
): sitemap.Sitemap {
const {url: hostname} = siteConfig;
if (!hostname) {
throw new Error('url in docusaurus.config.js cannot be empty/undefined');

View file

@ -11,7 +11,7 @@ import {PluginOptions} from './types';
import createSitemap from './createSitemap';
import {LoadContext, Props, Plugin} from '@docusaurus/types';
const DEFAULT_OPTIONS: PluginOptions = {
const DEFAULT_OPTIONS: Required<PluginOptions> = {
cacheTime: 600 * 1000, // 600 sec - cache purge period.
changefreq: 'weekly',
priority: 0.5,

View file

@ -6,7 +6,7 @@
*/
export interface PluginOptions {
cacheTime: number;
changefreq: string;
priority: number;
cacheTime?: number;
changefreq?: string;
priority?: number;
}

View file

@ -52,6 +52,8 @@ function Footer() {
<li
key={key}
className="mb-2"
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: item.html,
}}

View file

@ -32,6 +32,8 @@ function AnnouncementBar() {
role="banner">
<div
className={styles.announcementBarContent}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: content}}
/>

View file

@ -47,6 +47,8 @@ function Headings({headings, isChild}) {
<a
href={`#${heading.id}`}
className={LINK_CLASS_NAME}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<Headings isChild headings={heading.children} />

View file

@ -74,6 +74,8 @@ function Footer() {
<li
key={key}
className="footer__item"
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: item.html,
}}
@ -109,6 +111,8 @@ function Footer() {
)}
<div
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: copyright,
}}

View file

@ -323,6 +323,8 @@ function Search() {
{breadcrumbs.length > 0 && (
<span
className={styles.searchResultItemPath}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: breadcrumbs.join(' '),
}}
@ -332,6 +334,8 @@ function Search() {
{summary && (
<p
className={styles.searchResultItemSummary}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: summary}}
/>
)}

View file

@ -22,23 +22,23 @@ export interface DocusaurusConfig {
themes?: PluginConfig[];
presets?: PresetConfig[];
themeConfig?: {
[key: string]: any;
[key: string]: unknown;
};
customFields?: {
[key: string]: any;
[key: string]: unknown;
};
scripts?: (
| string
| {
src: string;
[key: string]: any;
[key: string]: unknown;
}
)[];
stylesheets?: (
| string
| {
href: string;
[key: string]: any;
[key: string]: unknown;
}
)[];
}
@ -53,7 +53,10 @@ export interface Preset {
themes?: PluginConfig[];
}
export type PresetConfig = [string, Object] | [string] | string;
export type PresetConfig =
| [string, Record<string, unknown>]
| [string]
| string;
export interface StartCLIOptions {
port: string;
@ -88,7 +91,7 @@ export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
export interface Props extends LoadContext, InjectedHtmlTags {
routesPaths: string[];
plugins: Plugin<any>[];
plugins: Plugin<unknown>[];
}
export interface PluginContentLoadedActions {
@ -125,7 +128,10 @@ export interface Plugin<T> {
};
}
export type PluginConfig = [string, Object] | [string] | string;
export type PluginConfig =
| [string, Record<string, unknown>]
| [string]
| string;
export interface ChunkRegistry {
loader: string;
@ -165,11 +171,17 @@ export interface ConfigureWebpackUtils {
getStyleLoaders: (
isServer: boolean,
cssOptions: {
[key: string]: any;
[key: string]: unknown;
},
) => Loader[];
getCacheLoader: (isServer: boolean, cacheOptions?: {}) => Loader | null;
getBabelLoader: (isServer: boolean, babelOptions?: {}) => Loader;
getCacheLoader: (
isServer: boolean,
cacheOptions?: Record<string, unknown>,
) => Loader | null;
getBabelLoader: (
isServer: boolean,
babelOptions?: Record<string, unknown>,
) => Loader;
}
interface HtmlTagObject {

View file

@ -160,6 +160,8 @@ export function genChunkName(
return chunkName;
}
// Too dynamic
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
export function idx(target: any, keyPaths?: string | (string | number)[]): any {
return (
target &&
@ -231,13 +233,15 @@ export function createExcerpt(fileString: string): string | undefined {
type ParsedMarkdown = {
frontMatter: {
// Returned by gray-matter
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
};
content: string;
excerpt: string | undefined;
};
export function parseMarkdownString(markdownString: string): ParsedMarkdown {
const options: {} = {
const options: Record<string, unknown> = {
excerpt: (file: matter.GrayMatterFile<string>): void => {
// Hacky way of stripping out import statements from the excerpt
// TODO: Find a better way to do so, possibly by compiling the Markdown content,

View file

@ -50,7 +50,7 @@ function getTransformOptions(isServer: boolean): TransformOptions {
// By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0, better to
// explicitly specify the version so that it can reuse the helper better
// See https://github.com/babel/babel/issues/10261
// eslint-disable-next-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
version: require('@babel/runtime/package.json').version,
regenerator: true,
useESModules: true,

View file

@ -28,7 +28,7 @@ interface State {
class PendingNavigation extends React.Component<Props, State> {
previousLocation: any;
progressBarTimeout: any;
progressBarTimeout: NodeJS.Timeout | null;
constructor(props: Props) {
super(props);
@ -43,7 +43,7 @@ class PendingNavigation extends React.Component<Props, State> {
// Intercept location update and still show current route until next route
// is done loading.
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps: Props, nextState: State) {
const routeDidChange = nextProps.location !== this.props.location;
const {routes, delay = 1000} = this.props;

View file

@ -5,9 +5,20 @@
* LICENSE file in the root directory of this source tree.
*/
// too dynamic
/* eslint-disable @typescript-eslint/no-explicit-any */
import clientModules from '@generated/client-modules';
function dispatchLifecycleAction(lifecycleAction, ...args) {
interface Dispatchers {
onRouteUpdate: (...args: any) => void;
onRouteUpdateDelayed: (...args: any) => void;
}
function dispatchLifecycleAction(
lifecycleAction: keyof Dispatchers,
...args: any[]
) {
clientModules.forEach((clientModule) => {
const mod = clientModule.__esModule ? clientModule.default : clientModule;
if (mod && mod[lifecycleAction]) {
@ -16,26 +27,13 @@ function dispatchLifecycleAction(lifecycleAction, ...args) {
});
}
interface Dispatchers {
onRouteUpdate: Function;
onRouteUpdateDelayed: Function;
}
const clientLifecyclesDispatchers: Dispatchers = {
onRouteUpdate(...args) {
dispatchLifecycleAction('onRouteUpdate', ...args);
},
onRouteUpdateDelayed(...args) {
dispatchLifecycleAction('onRouteUpdateDelayed', ...args);
},
};
function createLifecyclesDispatcher(): Dispatchers {
// TODO: Not sure whether it's better to declare an explicit object
// with all the lifecycles. It's better for typing but quite verbose.
// On the other hand, there's some runtime cost generating this object
// on initial load.
return ['onRouteUpdate', 'onRouteUpdateDelayed'].reduce(
(lifecycles, lifecycleAction) => {
// eslint-disable-next-line no-param-reassign
lifecycles[lifecycleAction] = function (...args) {
dispatchLifecycleAction(lifecycleAction, ...args);
};
return lifecycles;
},
{},
) as Dispatchers;
}
export default createLifecyclesDispatcher();
export default clientLifecyclesDispatchers;

View file

@ -17,7 +17,7 @@ import docusaurus from './docusaurus';
declare global {
interface NodeModule {
hot?: any;
hot?: {accept: () => void};
}
}

View file

@ -15,8 +15,8 @@ const fetched = {};
const loaded = {};
declare global {
// eslint-disable-next-line camelcase
const __webpack_require__: any;
// eslint-disable-next-line camelcase, @typescript-eslint/no-explicit-any
const __webpack_require__: {gca: (name: string) => string};
interface Navigator {
connection: any;
}
@ -35,13 +35,14 @@ const isSlowConnection = () => {
return false;
};
const canPrefetch = (routePath) =>
const canPrefetch = (routePath: string) =>
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
const canPreload = (routePath) => !isSlowConnection() && !loaded[routePath];
const canPreload = (routePath: string) =>
!isSlowConnection() && !loaded[routePath];
const docusaurus = {
prefetch: (routePath) => {
prefetch: (routePath: string): boolean => {
if (!canPrefetch(routePath)) {
return false;
}
@ -50,13 +51,13 @@ const docusaurus = {
// Find all webpack chunk names needed.
const matches = matchRoutes(routes, routePath);
const chunkNamesNeeded = matches.reduce((arr, match) => {
const chunk = routesChunkNames[match.route.path];
const chunkNamesNeeded = matches.reduce((arr: string[], match) => {
const chunk = routesChunkNames[match.route.path as string];
if (!chunk) {
return arr;
}
const chunkNames = Object.values(flat(chunk));
const chunkNames = Object.values(flat(chunk)) as string[];
return arr.concat(chunkNames);
}, []);
@ -77,7 +78,7 @@ const docusaurus = {
return true;
},
preload: (routePath) => {
preload: (routePath: string): boolean => {
if (!canPreload(routePath)) {
return false;
}

View file

@ -8,9 +8,15 @@
import React from 'react';
import ExecutionEnvironment from './ExecutionEnvironment';
function BrowserOnly({children, fallback}) {
function BrowserOnly({
children,
fallback,
}: {
children?: () => JSX.Element;
fallback?: JSX.Element;
}): JSX.Element | undefined {
if (!ExecutionEnvironment.canUseDOM || children == null) {
return fallback || null;
return fallback || undefined;
}
return <>{children()}</>;

View file

@ -12,7 +12,7 @@ import routesChunkNames from '@generated/routesChunkNames';
import registry from '@generated/registry';
import flat from '../flat';
function ComponentCreator(path: string) {
function ComponentCreator(path: string): ReturnType<typeof Loadable> {
// 404 page
if (path === '*') {
return Loadable({

View file

@ -15,7 +15,8 @@ const ExecutionEnvironment = {
canUseDOM,
canUseEventListeners:
// @ts-ignore
// @ts-expect-error: window.attachEvent is IE specific.
// See https://github.com/Microsoft/TypeScript/issues/3953#issuecomment-123396830
canUseDOM && !!(window.addEventListener || window.attachEvent),
canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window,

View file

@ -6,9 +6,9 @@
*/
import React from 'react';
import {Helmet} from 'react-helmet';
import {Helmet, HelmetProps} from 'react-helmet';
function Head(props): JSX.Element {
function Head(props: HelmetProps): JSX.Element {
return <Helmet {...props} />;
}

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import React, {useEffect, useRef} from 'react';
import React, {ReactNode, useEffect, useRef} from 'react';
import {NavLink, Link as RRLink} from 'react-router-dom';
import isInternalUrl from './isInternalUrl';
@ -21,6 +21,7 @@ interface Props {
readonly isNavLink?: boolean;
readonly to?: string;
readonly href: string;
readonly children?: ReactNode;
}
function Link({isNavLink, ...props}: Props): JSX.Element {
@ -85,6 +86,7 @@ function Link({isNavLink, ...props}: Props): JSX.Element {
return !targetLink || !isInternal || targetLink.startsWith('#') ? (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
// @ts-expect-error: href specified twice needed to pass children and other user specified props
href={targetLink}
{...(!isInternal && {target: '_blank', rel: 'noopener noreferrer'})}
{...props}

View file

@ -5,7 +5,9 @@
* LICENSE file in the root directory of this source tree.
*/
function flat(target) {
// Too dynamic
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function flat(target: unknown): any {
const delimiter = '.';
const output = {};

View file

@ -5,10 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/
// Memoize previously normalized pathnames.
const pathnames = {};
type Location = {pathname: string};
function normalizeLocation(location) {
// Memoize previously normalized pathnames.
const pathnames: Record<string, string> = {};
function normalizeLocation<T extends Location>(location: T): T {
if (pathnames[location.pathname]) {
return {
...location,

View file

@ -5,24 +5,29 @@
* LICENSE file in the root directory of this source tree.
*/
import {matchRoutes} from 'react-router-config';
import {matchRoutes, RouteConfig} from 'react-router-config';
/**
* Helper function to make sure all async components for that particular route
* is preloaded before rendering. This is especially useful to avoid loading screens.
*
* @param {Array<RouteConfig>} routes react-router-config
* @param {string} pathname the route pathname, example: /docs/installation
* @returns {Promise} Promise object represents whether pathname has been preloaded
* @param routes react-router-config
* @param pathname the route pathname, example: /docs/installation
* @returns Promise object represents whether pathname has been preloaded
*/
export default function preload(routes, pathname: string) {
export default function preload(
routes: RouteConfig[],
pathname: string,
): Promise<void[]> {
const matches = matchRoutes(routes, pathname);
return Promise.all(
matches.map((match) => {
const {component} = match.route;
// @ts-expect-error: ComponentCreator injected this method.
if (component && component.preload) {
// @ts-expect-error: checked above.
return component.preload();
}

View file

@ -16,12 +16,12 @@ import merge from 'webpack-merge';
import {STATIC_DIR_NAME} from '../constants';
import {load} from '../server';
import {BuildCLIOptions, Props} from '@docusaurus/types';
import {createClientConfig} from '../webpack/client';
import {createServerConfig} from '../webpack/server';
import createClientConfig from '../webpack/client';
import createServerConfig from '../webpack/server';
import {applyConfigureWebpack} from '../webpack/utils';
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
function compile(config: Configuration[]): Promise<any> {
function compile(config: Configuration[]): Promise<void> {
return new Promise((resolve, reject) => {
const compiler = webpack(config);
compiler.run((err, stats) => {
@ -55,7 +55,7 @@ function compile(config: Configuration[]): Promise<any> {
});
}
export async function build(
export default async function build(
siteDir: string,
cliOptions: Partial<BuildCLIOptions> = {},
forceTerminate: boolean = true,

View file

@ -10,11 +10,11 @@ import path from 'path';
import shell from 'shelljs';
import {CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME} from '../constants';
import {loadContext} from '../server';
import {loadConfig} from '../server/config';
import {build} from './build';
import loadConfig from '../server/config';
import build from './build';
import {BuildCLIOptions} from '@docusaurus/types';
export async function deploy(
export default async function deploy(
siteDir: string,
cliOptions: Partial<BuildCLIOptions> = {},
): Promise<void> {
@ -98,7 +98,7 @@ export async function deploy(
// out to deployment branch.
const currentCommit = shell.exec('git rev-parse HEAD').stdout.trim();
const runDeploy = (outDir) => {
const runDeploy = (outputDirectory) => {
if (shell.cd(tempDir).code !== 0) {
throw new Error(
`Temp dir ${GENERATED_FILES_DIR_NAME} does not exists. Run build website first.`,
@ -141,7 +141,7 @@ export async function deploy(
shell.cd('../..');
const fromPath = outDir;
const fromPath = outputDirectory;
const toPath = path.join(
GENERATED_FILES_DIR_NAME,
`${projectName}-${deploymentBranch}`,

View file

@ -7,9 +7,12 @@
import {CommanderStatic} from 'commander';
import {loadContext, loadPluginConfigs} from '../server';
import {initPlugins} from '../server/plugins/init';
import initPlugins from '../server/plugins/init';
export function externalCommand(cli: CommanderStatic, siteDir: string): void {
export default function externalCommand(
cli: CommanderStatic,
siteDir: string,
): void {
const context = loadContext(siteDir);
const pluginConfigs = loadPluginConfigs(context);
const plugins = initPlugins({pluginConfigs, context});

View file

@ -23,7 +23,7 @@ import HotModuleReplacementPlugin from 'webpack/lib/HotModuleReplacementPlugin';
import {load} from '../server';
import {StartCLIOptions} from '@docusaurus/types';
import {CONFIG_FILE_NAME, STATIC_DIR_NAME, DEFAULT_PORT} from '../constants';
import {createClientConfig} from '../webpack/client';
import createClientConfig from '../webpack/client';
import {applyConfigureWebpack} from '../webpack/utils';
function getHost(reqHost: string | undefined): string {
@ -36,7 +36,7 @@ async function getPort(reqPort: string | undefined): Promise<number> {
return port;
}
export async function start(
export default async function start(
siteDir: string,
cliOptions: Partial<StartCLIOptions> = {},
): Promise<void> {
@ -65,9 +65,7 @@ export async function start(
const pluginPaths: string[] = ([] as string[])
.concat(
...plugins
.map<any>(
(plugin) => plugin.getPathsToWatch && plugin.getPathsToWatch(),
)
.map((plugin) => plugin.getPathsToWatch?.() ?? [])
.filter(Boolean),
)
.map(normalizeToSiteDir);
@ -172,7 +170,9 @@ export async function start(
if (err) {
console.log(err);
}
cliOptions.open && openBrowser(openUrl);
if (cliOptions.open) {
openBrowser(openUrl);
}
});
['SIGINT', 'SIGTERM'].forEach((sig) => {
process.on(sig as NodeJS.Signals, () => {

View file

@ -9,19 +9,22 @@ import chalk = require('chalk');
import fs from 'fs-extra';
import importFresh from 'import-fresh';
import path from 'path';
import {Plugin, LoadContext} from '@docusaurus/types';
import {THEME_PATH} from '../constants';
import {loadContext} from '../server';
export async function swizzle(
export default async function swizzle(
siteDir: string,
themeName: string,
componentName?: string,
): Promise<void> {
const plugin: any = importFresh(themeName);
const plugin = importFresh(themeName) as (
context: LoadContext,
) => Plugin<unknown>;
const context = loadContext(siteDir);
const pluginInstance = plugin(context);
let fromPath = pluginInstance.getThemePath();
let fromPath = pluginInstance.getThemePath?.();
if (fromPath) {
let toPath = path.resolve(siteDir, THEME_PATH);

View file

@ -5,8 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
export {build} from './commands/build';
export {start} from './commands/start';
export {swizzle} from './commands/swizzle';
export {deploy} from './commands/deploy';
export {externalCommand} from './commands/external';
export {default as build} from './commands/build';
export {default as start} from './commands/start';
export {default as swizzle} from './commands/swizzle';
export {default as deploy} from './commands/deploy';
export {default as externalCommand} from './commands/external';

View file

@ -6,7 +6,7 @@
*/
import path from 'path';
import {loadConfig} from '../config';
import loadConfig from '../config';
describe('loadConfig', () => {
test('website with valid siteConfig', async () => {

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {loadRoutes} from '../routes';
import loadRoutes from '../routes';
import {RouteConfig} from '@docusaurus/types';
describe('loadRoutes', () => {

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {loadClientModules} from '../index';
import loadClientModules from '../index';
import pluginEmpty from './__fixtures__/plugin-empty';
import pluginFooBar from './__fixtures__/plugin-foo-bar';

View file

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

View file

@ -48,7 +48,7 @@ function formatFields(fields: string[]): string {
return fields.map((field) => `'${field}'`).join(', ');
}
export function loadConfig(siteDir: string): DocusaurusConfig {
export default function loadConfig(siteDir: string): DocusaurusConfig {
const configPath = path.resolve(siteDir, CONFIG_FILE_NAME);
if (!fs.existsSync(configPath)) {

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {htmlTagObjectToString} from '../htmlTags';
import htmlTagObjectToString from '../htmlTags';
describe('htmlTagObjectToString', () => {
test('simple html tag', () => {

View file

@ -10,10 +10,11 @@ import {HtmlTagObject} from '@docusaurus/types';
import htmlTags from 'html-tags';
import voidHtmlTags from 'html-tags/void';
function assertIsHtmlTagObject(val: any): asserts val is HtmlTagObject {
function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject {
if (!isPlainObject(val)) {
throw new Error(`"${val}" is not a valid HTML tag object`);
}
// @ts-expect-error: If tagName doesn't exist, it will throw.
if (typeof val.tagName !== 'string') {
throw new Error(
`${JSON.stringify(
@ -23,7 +24,7 @@ function assertIsHtmlTagObject(val: any): asserts val is HtmlTagObject {
}
}
export function htmlTagObjectToString(tagDefinition: unknown): string {
export default function htmlTagObjectToString(tagDefinition: unknown): string {
assertIsHtmlTagObject(tagDefinition);
if (htmlTags.indexOf(tagDefinition.tagName) === -1) {
throw new Error(

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {htmlTagObjectToString} from './htmlTags';
import htmlTagObjectToString from './htmlTags';
import {
Plugin,
InjectedHtmlTags,
@ -21,7 +21,7 @@ export function createHtmlTagsString(tags: HtmlTags): string {
return Array.isArray(tags) ? tags.map(toString).join('\n') : toString(tags);
}
export function loadHtmlTags(plugins: Plugin<any>[]): InjectedHtmlTags {
export function loadHtmlTags(plugins: Plugin<unknown>[]): InjectedHtmlTags {
const htmlTags = plugins.reduce(
(acc, plugin) => {
if (!plugin.injectHtmlTags) {

View file

@ -13,12 +13,12 @@ import {
GENERATED_FILES_DIR_NAME,
THEME_PATH,
} from '../constants';
import {loadClientModules} from './client-modules';
import {loadConfig} from './config';
import loadClientModules from './client-modules';
import loadConfig from './config';
import {loadPlugins} from './plugins';
import {loadPresets} from './presets';
import {loadRoutes} from './routes';
import {loadThemeAlias} from './themes';
import loadPresets from './presets';
import loadRoutes from './routes';
import loadThemeAlias from './themes';
import {
DocusaurusConfig,
LoadContext,
@ -84,11 +84,9 @@ export async function load(
// Themes.
const fallbackTheme = path.resolve(__dirname, '../client/theme-fallback');
const pluginThemes = ([] as string[]).concat(
...plugins
.map<any>((plugin) => plugin.getThemePath && plugin.getThemePath())
.filter(Boolean),
);
const pluginThemes: string[] = plugins
.map((plugin) => plugin.getThemePath && plugin.getThemePath())
.filter((x): x is string => Boolean(x));
const userTheme = path.resolve(siteDir, THEME_PATH);
const alias = loadThemeAlias([fallbackTheme, ...pluginThemes], [userTheme]);

View file

@ -10,7 +10,7 @@ import {load} from './index';
import {Props} from '@docusaurus/types';
// Helper methods to setup dummy/fake projects.
export const loadSetup = async (name: string): Promise<Props> => {
const loadSetup = async (name: string): Promise<Props> => {
const fixtures = path.join(__dirname, '__tests__', '__fixtures__');
const simpleSite = path.join(fixtures, 'simple-site');
const customSite = path.join(fixtures, 'custom-site');
@ -23,3 +23,5 @@ export const loadSetup = async (name: string): Promise<Props> => {
return load(simpleSite);
}
};
export default loadSetup;

View file

@ -15,7 +15,7 @@ import {
PluginContentLoadedActions,
RouteConfig,
} from '@docusaurus/types';
import {initPlugins} from './init';
import initPlugins from './init';
export function sortConfig(routeConfigs: RouteConfig[]): void {
// Sort the route config. This ensures that route with nested
@ -31,20 +31,18 @@ export function sortConfig(routeConfigs: RouteConfig[]): void {
if (a.priority || b.priority) {
const priorityA = a.priority || 0;
const priorityB = b.priority || 0;
const score = priorityA > priorityB ? -1 : priorityB > priorityA ? 1 : 0;
const score = priorityB - priorityA;
if (score !== 0) {
return score;
}
}
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
return a.path.localeCompare(b.path);
});
routeConfigs.forEach((routeConfig) => {
routeConfig.routes?.sort((a, b) => {
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
});
routeConfig.routes?.sort((a, b) => a.path.localeCompare(b.path));
});
}

View file

@ -11,13 +11,13 @@ import importFresh from 'import-fresh';
import {LoadContext, Plugin, PluginConfig} from '@docusaurus/types';
import {CONFIG_FILE_NAME} from '../../constants';
export function initPlugins({
export default function initPlugins({
pluginConfigs,
context,
}: {
pluginConfigs: PluginConfig[];
context: LoadContext;
}): Plugin<any>[] {
}): Plugin<unknown>[] {
// We need to resolve plugins from the perspective of the siteDir, since the siteDir's package.json
// declares the dependency on these plugins.
// We need to fallback to createRequireFromPath since createRequire is only available in node v12.
@ -25,7 +25,7 @@ export function initPlugins({
const createRequire = Module.createRequire || Module.createRequireFromPath;
const pluginRequire = createRequire(join(context.siteDir, CONFIG_FILE_NAME));
const plugins: Plugin<any>[] = pluginConfigs
const plugins: Plugin<unknown>[] = pluginConfigs
.map((pluginItem) => {
let pluginModuleImport: string | undefined;
let pluginOptions = {};
@ -37,8 +37,7 @@ export function initPlugins({
if (typeof pluginItem === 'string') {
pluginModuleImport = pluginItem;
} else if (Array.isArray(pluginItem)) {
pluginModuleImport = pluginItem[0];
pluginOptions = pluginItem[1] || {};
[pluginModuleImport, pluginOptions = {}] = pluginItem;
}
if (!pluginModuleImport) {

View file

@ -7,7 +7,7 @@
import path from 'path';
import {loadPresets} from '../index';
import loadPresets from '../index';
import {LoadContext} from '@docusaurus/types';
describe('loadPresets', () => {

View file

@ -13,7 +13,7 @@ import {
PresetConfig,
} from '@docusaurus/types';
export function loadPresets(
export default function loadPresets(
context: LoadContext,
): {
plugins: PluginConfig[];

View file

@ -36,10 +36,21 @@ function getModulePath(target: Module): string {
return `${target.path}${queryStr}`;
}
export async function loadRoutes(
type LoadedRoutes = {
registry: {
[chunkName: string]: ChunkRegistry;
};
routesConfig: string;
routesChunkNames: {
[routePath: string]: ChunkNames;
};
routesPaths: string[];
};
export default async function loadRoutes(
pluginsRouteConfigs: RouteConfig[],
baseUrl: string,
) {
): Promise<LoadedRoutes> {
const routesImports = [
`import React from 'react';`,
`import ComponentCreator from '@docusaurus/ComponentCreator';`,

View file

@ -7,7 +7,7 @@
import path from 'path';
import fs from 'fs-extra';
import {themeAlias} from '../alias';
import themeAlias from '../alias';
describe('themeAlias', () => {
test('valid themePath 1 with components', () => {

View file

@ -6,7 +6,7 @@
*/
import path from 'path';
import {loadThemeAlias} from '../index';
import loadThemeAlias from '../index';
describe('loadThemeAlias', () => {
test('next alias can override the previous alias', () => {

View file

@ -11,7 +11,7 @@ import path from 'path';
import {fileToPath, posixPath, normalizeUrl} from '@docusaurus/utils';
import {ThemeAlias} from '@docusaurus/types';
export function themeAlias(
export default function themeAlias(
themePath: string,
addOriginalAlias: boolean = true,
): ThemeAlias {

View file

@ -6,9 +6,9 @@
*/
import {ThemeAlias} from '@docusaurus/types';
import {themeAlias} from './alias';
import themeAlias from './alias';
export function loadThemeAlias(
export default function loadThemeAlias(
themePaths: string[],
userThemePaths: string[] = [],
): ThemeAlias {

View file

@ -7,8 +7,8 @@
import {validate} from 'webpack';
import {createClientConfig} from '../client';
import {loadSetup} from '../../server/loadSetup';
import createClientConfig from '../client';
import loadSetup from '../../server/loadSetup';
describe('webpack dev config', () => {
test('simple', async () => {

View file

@ -7,8 +7,8 @@
import {validate} from 'webpack';
import {createServerConfig} from '../server';
import {loadSetup} from '../../server/loadSetup';
import createServerConfig from '../server';
import loadSetup from '../../server/loadSetup';
describe('webpack production config', () => {
test('simple', async () => {

View file

@ -15,7 +15,7 @@ import {createBaseConfig} from './base';
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
import LogPlugin from './plugins/LogPlugin';
export function createClientConfig(
export default function createClientConfig(
props: Props,
minify: boolean = true,
): Configuration {
@ -46,7 +46,7 @@ export function createClientConfig(
// When building include the plugin to force terminate building if errors happened in the client bundle.
if (isBuilding) {
clientConfig.plugins!.push({
clientConfig.plugins?.push({
apply: (compiler) => {
compiler.hooks.done.tap('client:done', (stats) => {
if (stats.hasErrors()) {

View file

@ -33,6 +33,9 @@ import path from 'path';
import {sync as delSync} from 'del';
export interface Options {
/** @deprecated */
allowExternal?: unknown;
/**
* Simulate the removal of files
*
@ -110,7 +113,6 @@ class CleanWebpackPlugin {
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional`);
}
// @ts-ignore
if (options.allowExternal) {
throw new Error(
'clean-webpack-plugin: `allowExternal` option no longer supported. Use `dangerouslyAllowCleanPatternsOutsideProject`',

View file

@ -15,7 +15,7 @@ import {createBaseConfig} from './base';
import WaitPlugin from './plugins/WaitPlugin';
import LogPlugin from './plugins/LogPlugin';
export function createServerConfig(
export default function createServerConfig(
props: Props,
minify: boolean = true,
): Configuration {

View file

@ -10,6 +10,7 @@ import env from 'std-env';
import merge from 'webpack-merge';
import {Configuration, Loader} from 'webpack';
import {TransformOptions} from '@babel/core';
import {ConfigureWebpackUtils} from '@docusaurus/types';
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
@ -17,7 +18,7 @@ import {version as cacheLoaderVersion} from 'cache-loader/package.json';
export function getStyleLoaders(
isServer: boolean,
cssOptions: {
[key: string]: any;
[key: string]: unknown;
} = {},
): Loader[] {
if (isServer) {
@ -53,7 +54,7 @@ export function getStyleLoaders(
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
// eslint-disable-next-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
@ -69,7 +70,7 @@ export function getStyleLoaders(
export function getCacheLoader(
isServer: boolean,
cacheOptions?: {},
cacheOptions?: {[key: string]: unknown},
): Loader | null {
if (env.ci || env.test) {
return null;
@ -113,13 +114,19 @@ export function getBabelLoader(
/**
* Helper function to modify webpack config
* @param {Object | Function} configureWebpack a webpack config or a function to modify config
* @param {Object} config initial webpack config
* @param {boolean} isServer indicates if this is a server webpack configuration
* @returns {Object} final/ modified webpack config
* @param configureWebpack a webpack config or a function to modify config
* @param config initial webpack config
* @param isServer indicates if this is a server webpack configuration
* @returns final/ modified webpack config
*/
export function applyConfigureWebpack(
configureWebpack: any,
configureWebpack:
| Configuration
| ((
config: Configuration,
isServer: boolean,
utils: ConfigureWebpackUtils,
) => Configuration),
config: Configuration,
isServer: boolean,
): Configuration {

View file

@ -7,10 +7,9 @@
import path from 'path';
import Vibrant from 'node-vibrant';
import {Palette} from 'node-vibrant/lib/color';
// @ts-ignore
import {toPalette, toBase64} from '../utils';
// @ts-ignore
import lqip from '../lqip';
describe('lqip-loader', () => {
@ -24,8 +23,8 @@ describe('lqip-loader', () => {
});
describe('toPalette', () => {
let correctTestSwatch: object = {};
let testSwatchWithNull: object = {};
let correctTestSwatch: Palette = {};
let testSwatchWithNull: Palette & {Vibrant?: null} = {};
beforeAll(() => {
const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg');

View file

@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
// @ts-check
const sortBy = require('lodash.sortby');
/**
@ -12,7 +14,7 @@ const sortBy = require('lodash.sortby');
* @description it returns a Base64 image string with required formatting
* to work on the web (<img src=".." /> or in CSS url('..'))
*
* @param extMimeType: image mime type string
* @param {string} extMimeType: image mime type string
* @param data: base64 string
* @returns {string}
*/
@ -25,10 +27,11 @@ const toBase64 = (extMimeType, data) => {
* @description takes a color swatch object, converts it to an array & returns
* only hex color
*
* @param swatch
* @returns {{palette: Array}}
* @param {import("node-vibrant/lib/color").Palette} swatch
* @returns {string[]}
*/
const toPalette = (swatch) => {
/** @type {Array<{popularity: number, hex: string}>} */
let palette = Object.keys(swatch).reduce((result, key) => {
if (swatch[key] !== null) {
result.push({
@ -39,8 +42,7 @@ const toPalette = (swatch) => {
return result;
}, []);
palette = sortBy(palette, ['popularity']);
palette = palette.map((color) => color.hex).reverse();
return palette;
return palette.map((color) => color.hex).reverse();
};
module.exports = {

View file

@ -2795,6 +2795,11 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/history@*":
version "4.7.6"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.6.tgz#ed8fc802c45b8e8f54419c2d054e55c9ea344356"
integrity sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==
"@types/html-minifier-terser@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.0.0.tgz#7532440c138605ced1b555935c3115ddd20e8bef"
@ -3032,10 +3037,42 @@
"@types/webpack" "*"
"@types/webpack-dev-server" "*"
"@types/react@^16.9.13":
version "16.9.32"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.32.tgz#f6368625b224604148d1ddf5920e4fefbd98d383"
integrity sha512-fmejdp0CTH00mOJmxUPPbWCEBWPvRIL4m8r0qD+BSDUqmutPyGQCHifzMpMzdvZwROdEdL78IuZItntFWgPXHQ==
"@types/react-helmet@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.0.0.tgz#5b74e44a12662ffb12d1c97ee702cf4e220958cf"
integrity sha512-NBMPAxgjpaMooXa51cU1BTgrX6T+hQbMiLm77JhBbfOzPQea3RB5rNpPOD5xGWHIVpGXHd59cltEzIq0qglGcQ==
dependencies:
"@types/react" "*"
"@types/react-loadable@^5.5.3":
version "5.5.3"
resolved "https://registry.yarnpkg.com/@types/react-loadable/-/react-loadable-5.5.3.tgz#65d50a6f9f7ff62513010bd6a460ed60ba58ca7d"
integrity sha512-BRzQhbMo5CjfxFU2tmmBNh16QqKUwNiaX0vflCwIVPVG8g/pCOyJ3rOdSPo4m+TPS7C9q/TupaqYXXTMtFoyng==
dependencies:
"@types/react" "*"
"@types/webpack" "*"
"@types/react-router-config@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.1.tgz#54da8418190ee47484dee279975e2b8038fb8b5d"
integrity sha512-D4srFL4XP21GjWWnM7mL8j+Nrrw13pc2TYr57WTHJxU9YTxnrXL7p1iqGtwecgwhyeXJSm4WrGwq0SOgSALVbA==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react-router" "*"
"@types/react-router@*":
version "5.1.7"
resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.7.tgz#e9d12ed7dcfc79187e4d36667745b69a5aa11556"
integrity sha512-2ouP76VQafKjtuc0ShpwUebhHwJo0G6rhahW9Pb8au3tQTjYXd2jta4wv6U2tGLR/I42yuG00+UXjNYY0dTzbg==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.38":
version "16.9.38"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.38.tgz#868405dace93a4095d3e054f4c4a1de7a1ac0680"
integrity sha512-pHAeZbjjNRa/hxyNuLrvbxhhnKyKNiLC6I5fRF2Zr/t/S6zS41MiyzH4+c+1I9vVfvuRt1VS2Lodjr4ZWnxrdA==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
@ -17815,10 +17852,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.7.2:
version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
typescript@^3.9.5:
version "3.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
ua-parser-js@^0.7.18:
version "0.7.21"