mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-14 17:47:40 +02:00
chore(v2): Fix more eslint errors (#2976)
This commit is contained in:
parent
3611c96f90
commit
6e43c9bd34
81 changed files with 375 additions and 237 deletions
14
.eslintrc.js
14
.eslintrc.js
|
@ -85,27 +85,23 @@ module.exports = {
|
||||||
],
|
],
|
||||||
'no-unused-vars': OFF,
|
'no-unused-vars': OFF,
|
||||||
'@typescript-eslint/no-unused-vars': [ERROR, {argsIgnorePattern: '^_'}],
|
'@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
|
// TODO re-enable some these as errors
|
||||||
// context: https://github.com/facebook/docusaurus/pull/2949
|
// context: https://github.com/facebook/docusaurus/pull/2949
|
||||||
'@typescript-eslint/ban-ts-comment': WARNING,
|
|
||||||
'@typescript-eslint/ban-types': WARNING,
|
'@typescript-eslint/ban-types': WARNING,
|
||||||
'import/prefer-default-export': WARNING,
|
|
||||||
'import/no-extraneous-dependencies': WARNING,
|
'import/no-extraneous-dependencies': WARNING,
|
||||||
'no-useless-escape': WARNING,
|
'no-useless-escape': WARNING,
|
||||||
'prefer-template': WARNING,
|
'prefer-template': WARNING,
|
||||||
'no-shadow': WARNING,
|
|
||||||
'no-param-reassign': WARNING,
|
'no-param-reassign': WARNING,
|
||||||
'no-else-return': WARNING,
|
|
||||||
'no-template-curly-in-string': WARNING,
|
'no-template-curly-in-string': WARNING,
|
||||||
'array-callback-return': WARNING,
|
'array-callback-return': WARNING,
|
||||||
camelcase: WARNING,
|
camelcase: WARNING,
|
||||||
'no-nested-ternary': WARNING,
|
|
||||||
'object-shorthand': WARNING,
|
|
||||||
'no-restricted-syntax': WARNING,
|
'no-restricted-syntax': WARNING,
|
||||||
'no-unused-expressions': WARNING,
|
'no-unused-expressions': WARNING,
|
||||||
'consistent-return': WARNING,
|
|
||||||
'no-useless-return': WARNING,
|
|
||||||
'@typescript-eslint/no-empty-function': WARNING,
|
'@typescript-eslint/no-empty-function': WARNING,
|
||||||
'global-require': WARNING,
|
'global-require': WARNING,
|
||||||
'prefer-destructuring': WARNING,
|
'prefer-destructuring': WARNING,
|
||||||
|
@ -114,8 +110,6 @@ module.exports = {
|
||||||
'no-empty': WARNING,
|
'no-empty': WARNING,
|
||||||
'no-prototype-builtins': WARNING,
|
'no-prototype-builtins': WARNING,
|
||||||
'no-case-declarations': WARNING,
|
'no-case-declarations': WARNING,
|
||||||
'default-case': WARNING,
|
|
||||||
'dot-notation': WARNING,
|
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
|
11
package.json
11
package.json
|
@ -37,8 +37,6 @@
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||||
"@babel/preset-typescript": "^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/express": "^4.17.2",
|
||||||
"@types/fs-extra": "^8.0.1",
|
"@types/fs-extra": "^8.0.1",
|
||||||
"@types/inquirer": "^6.5.0",
|
"@types/inquirer": "^6.5.0",
|
||||||
|
@ -54,13 +52,18 @@
|
||||||
"@types/lodash.pick": "^4.4.6",
|
"@types/lodash.pick": "^4.4.6",
|
||||||
"@types/lodash.pickby": "^4.6.6",
|
"@types/lodash.pickby": "^4.6.6",
|
||||||
"@types/node": "^13.11.0",
|
"@types/node": "^13.11.0",
|
||||||
"@types/react": "^16.9.13",
|
"@types/react": "^16.9.38",
|
||||||
"@types/react-dev-utils": "^9.0.1",
|
"@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/semver": "^7.1.0",
|
||||||
"@types/shelljs": "^0.8.6",
|
"@types/shelljs": "^0.8.6",
|
||||||
"@types/webpack": "^4.41.0",
|
"@types/webpack": "^4.41.0",
|
||||||
"@types/webpack-dev-server": "^3.9.0",
|
"@types/webpack-dev-server": "^3.9.0",
|
||||||
"@types/webpack-merge": "^4.1.5",
|
"@types/webpack-merge": "^4.1.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^3.3.0",
|
||||||
|
"@typescript-eslint/parser": "^3.3.0",
|
||||||
"babel-eslint": "^10.0.3",
|
"babel-eslint": "^10.0.3",
|
||||||
"concurrently": "^5.2.0",
|
"concurrently": "^5.2.0",
|
||||||
"enzyme": "^3.10.0",
|
"enzyme": "^3.10.0",
|
||||||
|
@ -85,7 +88,7 @@
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"serve": "^11.3.2",
|
"serve": "^11.3.2",
|
||||||
"stylelint": "^13.2.1",
|
"stylelint": "^13.2.1",
|
||||||
"typescript": "^3.7.2"
|
"typescript": "^3.9.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"stylelint-copyright": "^2.0.0"
|
"stylelint-copyright": "^2.0.0"
|
||||||
|
|
|
@ -11,7 +11,7 @@ const chalk = require('chalk');
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const program = require('commander');
|
const program = require('commander');
|
||||||
const {init} = require('../lib');
|
const {default: init} = require('../lib');
|
||||||
const requiredVersion = require('../package.json').engines.node;
|
const requiredVersion = require('../package.json').engines.node;
|
||||||
|
|
||||||
if (!semver.satisfies(process.version, requiredVersion)) {
|
if (!semver.satisfies(process.version, requiredVersion)) {
|
||||||
|
|
|
@ -26,7 +26,10 @@ function isValidGitRepoUrl(gitRepoUrl: string): boolean {
|
||||||
return ['https://', 'git@'].some((item) => gitRepoUrl.startsWith(item));
|
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 content = await fs.readFile(pkgPath, 'utf-8');
|
||||||
const pkg = JSON.parse(content);
|
const pkg = JSON.parse(content);
|
||||||
const newPkg = Object.assign(pkg, obj);
|
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));
|
await fs.outputFile(pkgPath, JSON.stringify(newPkg, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function init(
|
export default async function init(
|
||||||
rootDir: string,
|
rootDir: string,
|
||||||
siteName?: string,
|
siteName?: string,
|
||||||
reqTemplate?: string,
|
reqTemplate?: string,
|
||||||
|
|
|
@ -14,8 +14,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "^2.0.0-alpha.58",
|
"@docusaurus/types": "^2.0.0-alpha.58",
|
||||||
"@docusaurus/utils": "^2.0.0-alpha.58",
|
"@docusaurus/utils": "^2.0.0-alpha.58",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
"eta": "^1.1.1",
|
"eta": "^1.1.1",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
"globby": "^10.0.1",
|
"globby": "^10.0.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
"yup": "^0.29.0"
|
"yup": "^0.29.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -208,7 +208,7 @@ describe('collectRedirects', () => {
|
||||||
{
|
{
|
||||||
createRedirects: (routePath) => {
|
createRedirects: (routePath) => {
|
||||||
if (routePath === '/') {
|
if (routePath === '/') {
|
||||||
return [[`/fromPath`]] as any;
|
return ([[`/fromPath`]] as unknown) as string;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,7 @@ describe('normalizePluginOptions', () => {
|
||||||
test('should reject bad fromExtensions user inputs', () => {
|
test('should reject bad fromExtensions user inputs', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
normalizePluginOptions({
|
normalizePluginOptions({
|
||||||
fromExtensions: [null, undefined, 123, true] as any,
|
fromExtensions: ([null, undefined, 123, true] as unknown) as string[],
|
||||||
}),
|
}),
|
||||||
).toThrowErrorMatchingSnapshot();
|
).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ describe('normalizePluginOptions', () => {
|
||||||
test('should reject bad toExtensions user inputs', () => {
|
test('should reject bad toExtensions user inputs', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
normalizePluginOptions({
|
normalizePluginOptions({
|
||||||
toExtensions: [null, undefined, 123, true] as any,
|
toExtensions: ([null, undefined, 123, true] as unknown) as string[],
|
||||||
}),
|
}),
|
||||||
).toThrowErrorMatchingSnapshot();
|
).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -65,7 +65,10 @@ describe('normalizePluginOptions', () => {
|
||||||
test('should reject bad createRedirects user inputs', () => {
|
test('should reject bad createRedirects user inputs', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
normalizePluginOptions({
|
normalizePluginOptions({
|
||||||
createRedirects: ['bad', 'value'] as any,
|
createRedirects: ([
|
||||||
|
'bad',
|
||||||
|
'value',
|
||||||
|
] as unknown) as CreateRedirectsFnOption,
|
||||||
}),
|
}),
|
||||||
).toThrowErrorMatchingSnapshot();
|
).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,6 +36,7 @@ function validateCollectedRedirects(
|
||||||
.map((redirect) => {
|
.map((redirect) => {
|
||||||
try {
|
try {
|
||||||
validateRedirect(redirect);
|
validateRedirect(redirect);
|
||||||
|
return undefined;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return e.message;
|
return e.message;
|
||||||
}
|
}
|
||||||
|
@ -132,13 +133,12 @@ function createRedirectsOptionRedirects(
|
||||||
function optionToRedirects(option: RedirectOption): RedirectMetadata[] {
|
function optionToRedirects(option: RedirectOption): RedirectMetadata[] {
|
||||||
if (typeof option.from === 'string') {
|
if (typeof option.from === 'string') {
|
||||||
return [{from: option.from, to: option.to}];
|
return [{from: option.from, to: option.to}];
|
||||||
} else {
|
}
|
||||||
return option.from.map((from) => ({
|
return option.from.map((from) => ({
|
||||||
from,
|
from,
|
||||||
to: option.to,
|
to: option.to,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return flatten(redirectsOption.map(optionToRedirects));
|
return flatten(redirectsOption.map(optionToRedirects));
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {RedirectMetadata} from './types';
|
||||||
export const PathnameValidator = Yup.string().test({
|
export const PathnameValidator = Yup.string().test({
|
||||||
name: 'isValidPathname',
|
name: 'isValidPathname',
|
||||||
message:
|
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',
|
'${path} is not a valid pathname. Pathname should start with / and not contain any domain or query string',
|
||||||
test: isValidPathname,
|
test: isValidPathname,
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,7 @@ describe('blogFeed', () => {
|
||||||
routeBasePath: 'blog',
|
routeBasePath: 'blog',
|
||||||
include: ['*.md', '*.mdx'],
|
include: ['*.md', '*.mdx'],
|
||||||
feedOptions: {
|
feedOptions: {
|
||||||
type: feedType as any,
|
type: feedType,
|
||||||
copyright: 'Copyright',
|
copyright: 'Copyright',
|
||||||
},
|
},
|
||||||
} as PluginOptions,
|
} as PluginOptions,
|
||||||
|
@ -62,7 +62,7 @@ describe('blogFeed', () => {
|
||||||
routeBasePath: 'blog',
|
routeBasePath: 'blog',
|
||||||
include: ['*r*.md', '*.mdx'], // skip no-date.md - it won't play nice with snapshots
|
include: ['*r*.md', '*.mdx'], // skip no-date.md - it won't play nice with snapshots
|
||||||
feedOptions: {
|
feedOptions: {
|
||||||
type: feedType as any,
|
type: feedType,
|
||||||
copyright: 'Copyright',
|
copyright: 'Copyright',
|
||||||
},
|
},
|
||||||
} as PluginOptions,
|
} as PluginOptions,
|
||||||
|
|
|
@ -72,10 +72,10 @@ export async function generateBlogFeed(
|
||||||
blogPosts.forEach((post) => {
|
blogPosts.forEach((post) => {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
metadata: {title, permalink, date, description},
|
metadata: {title: metadataTitle, permalink, date, description},
|
||||||
} = post;
|
} = post;
|
||||||
feed.addItem({
|
feed.addItem({
|
||||||
title,
|
title: metadataTitle,
|
||||||
id,
|
id,
|
||||||
link: normalizeUrl([siteUrl, permalink]),
|
link: normalizeUrl([siteUrl, permalink]),
|
||||||
date,
|
date,
|
||||||
|
|
|
@ -205,9 +205,8 @@ export default function pluginContentBlog(
|
||||||
label: tag,
|
label: tag,
|
||||||
permalink,
|
permalink,
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return tag;
|
|
||||||
}
|
}
|
||||||
|
return tag;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,7 +243,7 @@ export default function pluginContentBlog(
|
||||||
`~blog/${path.relative(dataDir, source)}`;
|
`~blog/${path.relative(dataDir, source)}`;
|
||||||
const {addRoute, createData} = actions;
|
const {addRoute, createData} = actions;
|
||||||
const {
|
const {
|
||||||
blogPosts,
|
blogPosts: loadedBlogPosts,
|
||||||
blogListPaginated,
|
blogListPaginated,
|
||||||
blogTags,
|
blogTags,
|
||||||
blogTagsListPath,
|
blogTagsListPath,
|
||||||
|
@ -254,7 +253,7 @@ export default function pluginContentBlog(
|
||||||
|
|
||||||
// Create routes for blog entries.
|
// Create routes for blog entries.
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
blogPosts.map(async (blogPost) => {
|
loadedBlogPosts.map(async (blogPost) => {
|
||||||
const {id, metadata} = blogPost;
|
const {id, metadata} = blogPost;
|
||||||
await createData(
|
await createData(
|
||||||
// Note that this created data path must be in sync with
|
// Note that this created data path must be in sync with
|
||||||
|
@ -292,12 +291,11 @@ export default function pluginContentBlog(
|
||||||
exact: true,
|
exact: true,
|
||||||
modules: {
|
modules: {
|
||||||
items: items.map((postID) => {
|
items: items.map((postID) => {
|
||||||
const metadata = blogItemsToMetadata[postID];
|
|
||||||
// To tell routes.js this is an import and not a nested object to recurse.
|
// To tell routes.js this is an import and not a nested object to recurse.
|
||||||
return {
|
return {
|
||||||
content: {
|
content: {
|
||||||
__import: true,
|
__import: true,
|
||||||
path: metadata.source,
|
path: blogItemsToMetadata[postID].source,
|
||||||
query: {
|
query: {
|
||||||
truncated: true,
|
truncated: true,
|
||||||
},
|
},
|
||||||
|
@ -481,22 +479,26 @@ export default function pluginContentBlog(
|
||||||
};
|
};
|
||||||
const headTags: HtmlTags = [];
|
const headTags: HtmlTags = [];
|
||||||
|
|
||||||
feedTypes.map((feedType) => {
|
feedTypes.forEach((feedType) => {
|
||||||
const feedConfig = feedsConfig[feedType] || {};
|
const feedConfig = feedsConfig[feedType] || {};
|
||||||
|
|
||||||
if (!feedsConfig) {
|
if (!feedsConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {type, path, title} = feedConfig;
|
const {type, path: feedConfigPath, title: feedConfigTitle} = feedConfig;
|
||||||
|
|
||||||
headTags.push({
|
headTags.push({
|
||||||
tagName: 'link',
|
tagName: 'link',
|
||||||
attributes: {
|
attributes: {
|
||||||
rel: 'alternate',
|
rel: 'alternate',
|
||||||
type,
|
type,
|
||||||
href: normalizeUrl([baseUrl, options.routeBasePath, path]),
|
href: normalizeUrl([
|
||||||
title,
|
baseUrl,
|
||||||
|
options.routeBasePath,
|
||||||
|
feedConfigPath,
|
||||||
|
]),
|
||||||
|
title: feedConfigTitle,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -170,7 +170,8 @@ describe('simple site', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// unrelated frontmatter is not part of metadata
|
// 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 () => {
|
test('docs with last update time and author', async () => {
|
||||||
|
|
|
@ -14,15 +14,15 @@ import {
|
||||||
VERSIONED_SIDEBARS_DIR,
|
VERSIONED_SIDEBARS_DIR,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export function getVersionedDocsDir(siteDir: string) {
|
export function getVersionedDocsDir(siteDir: string): string {
|
||||||
return path.join(siteDir, VERSIONED_DOCS_DIR);
|
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);
|
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);
|
return path.join(siteDir, VERSIONS_JSON_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ export default function (siteDir: string): Env {
|
||||||
fs.readFileSync(versionsJSONFile, 'utf8'),
|
fs.readFileSync(versionsJSONFile, 'utf8'),
|
||||||
);
|
);
|
||||||
if (parsedVersions && parsedVersions.length > 0) {
|
if (parsedVersions && parsedVersions.length > 0) {
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
versioning.latestVersion = parsedVersions[0];
|
versioning.latestVersion = parsedVersions[0];
|
||||||
versioning.enabled = true;
|
versioning.enabled = true;
|
||||||
versioning.versions = parsedVersions;
|
versioning.versions = parsedVersions;
|
||||||
|
|
|
@ -378,9 +378,7 @@ Available document ids=
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return routes.sort((a, b) =>
|
return routes.sort((a, b) => a.path.localeCompare(b.path));
|
||||||
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is the base route of the document root (for a doc given version)
|
// 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 /,
|
// Important: the layout component should not end with /,
|
||||||
// as it conflicts with the home doc
|
// as it conflicts with the home doc
|
||||||
// Workaround fix for https://github.com/facebook/docusaurus/issues/2917
|
// Workaround fix for https://github.com/facebook/docusaurus/issues/2917
|
||||||
const path = docsBaseRoute === '/' ? '' : docsBaseRoute;
|
const docsPath = docsBaseRoute === '/' ? '' : docsBaseRoute;
|
||||||
|
|
||||||
addRoute({
|
addRoute({
|
||||||
path,
|
path: docsPath,
|
||||||
exact: false, // allow matching /docs/* as well
|
exact: false, // allow matching /docs/* as well
|
||||||
component: docLayoutComponent, // main docs component (DocPage)
|
component: docLayoutComponent, // main docs component (DocPage)
|
||||||
routes, // subroute for each doc
|
routes, // subroute for each doc
|
||||||
|
@ -466,7 +464,7 @@ Available document ids=
|
||||||
const routes = await genRoutes(Object.values(content.docsMetadata));
|
const routes = await genRoutes(Object.values(content.docsMetadata));
|
||||||
const docsBaseMetadata = createDocsBaseMetadata();
|
const docsBaseMetadata = createDocsBaseMetadata();
|
||||||
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath]);
|
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath]);
|
||||||
return addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
await addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,12 @@ function inferVersion(
|
||||||
.replace(/^version-/, '');
|
.replace(/^version-/, '');
|
||||||
if (inferredVersion && versioning.versions.includes(inferredVersion)) {
|
if (inferredVersion && versioning.versions.includes(inferredVersion)) {
|
||||||
return inferredVersion;
|
return inferredVersion;
|
||||||
} else {
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Can't infer version from folder=${dirName}
|
`Can't infer version from folder=${dirName}
|
||||||
Expected versions:
|
Expected versions:
|
||||||
- ${versioning.versions.join('- ')}`,
|
- ${versioning.versions.join('- ')}`,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return 'next';
|
return 'next';
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ export default function createOrder(allSidebars: Sidebar = {}): Order {
|
||||||
case 'doc':
|
case 'doc':
|
||||||
ids.push(item.id);
|
ids.push(item.id);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,8 +45,12 @@ function normalizeCategoryShorthand(
|
||||||
/**
|
/**
|
||||||
* Check that item contains only allowed keys.
|
* 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(
|
const unknownKeys = Object.keys(item).filter(
|
||||||
|
// @ts-expect-error: key is always string
|
||||||
(key) => !keys.includes(key) && key !== 'type',
|
(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']);
|
assertItem(item, ['items', 'label', 'collapsed']);
|
||||||
if (typeof item.label !== 'string') {
|
if (typeof item.label !== 'string') {
|
||||||
throw new Error(
|
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']);
|
assertItem(item, ['id']);
|
||||||
if (typeof item.id !== 'string') {
|
if (typeof item.id !== 'string') {
|
||||||
throw new Error(
|
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']);
|
assertItem(item, ['href', 'label']);
|
||||||
if (typeof item.href !== 'string') {
|
if (typeof item.href !== 'string') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -175,7 +181,7 @@ export default function loadSidebars(sidebarPaths?: string[]): Sidebar {
|
||||||
return {} as Sidebar;
|
return {} as Sidebar;
|
||||||
}
|
}
|
||||||
|
|
||||||
sidebarPaths.map((sidebarPath) => {
|
sidebarPaths.forEach((sidebarPath) => {
|
||||||
if (sidebarPath && fs.existsSync(sidebarPath)) {
|
if (sidebarPath && fs.existsSync(sidebarPath)) {
|
||||||
const sidebar = importFresh(sidebarPath) as SidebarRaw;
|
const sidebar = importFresh(sidebarPath) as SidebarRaw;
|
||||||
Object.assign(allSidebars, sidebar);
|
Object.assign(allSidebars, sidebar);
|
||||||
|
|
|
@ -5,13 +5,20 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let versions: string[] = [];
|
let versions: string[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// eslint-disable-next-line global-require
|
||||||
versions = require('@site/versions.json');
|
versions = require('@site/versions.json');
|
||||||
} catch (e) {}
|
} catch {
|
||||||
|
versions = [];
|
||||||
|
}
|
||||||
|
|
||||||
function useVersioning() {
|
function useVersioning(): {
|
||||||
|
versioningEnabled: boolean;
|
||||||
|
versions: string[];
|
||||||
|
latestVersion: string;
|
||||||
|
} {
|
||||||
return {
|
return {
|
||||||
versioningEnabled: versions.length > 0,
|
versioningEnabled: versions.length > 0,
|
||||||
versions,
|
versions,
|
||||||
|
|
|
@ -65,7 +65,7 @@ export type SidebarItemRaw =
|
||||||
| SidebarItemCategoryRaw
|
| SidebarItemCategoryRaw
|
||||||
| {
|
| {
|
||||||
type: string;
|
type: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface SidebarCategoryShorthandRaw {
|
export interface SidebarCategoryShorthandRaw {
|
||||||
|
|
|
@ -15,6 +15,8 @@ import path from 'path';
|
||||||
import {Sidebar, PathOptions, SidebarItem} from './types';
|
import {Sidebar, PathOptions, SidebarItem} from './types';
|
||||||
import loadSidebars from './sidebars';
|
import loadSidebars from './sidebars';
|
||||||
|
|
||||||
|
// Tests depend on non-default export for mocking.
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export function docsVersion(
|
export function docsVersion(
|
||||||
version: string | null | undefined,
|
version: string | null | undefined,
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
|
|
|
@ -4,13 +4,16 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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 {PluginOptions} from './types';
|
||||||
import {Configuration} from 'webpack';
|
import {Configuration} from 'webpack';
|
||||||
|
|
||||||
import path from 'path';
|
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';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/types": "^2.0.0-alpha.58",
|
"@docusaurus/types": "^2.0.0-alpha.58",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
"sitemap": "^3.2.2"
|
"sitemap": "^3.2.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('createSitemap', () => {
|
||||||
|
|
||||||
test('empty site', () => {
|
test('empty site', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
createSitemap({} as DocusaurusConfig, [], {} as any);
|
createSitemap({} as DocusaurusConfig, [], {});
|
||||||
}).toThrowErrorMatchingInlineSnapshot(
|
}).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"url in docusaurus.config.js cannot be empty/undefined"`,
|
`"url in docusaurus.config.js cannot be empty/undefined"`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default function createSitemap(
|
||||||
siteConfig: DocusaurusConfig,
|
siteConfig: DocusaurusConfig,
|
||||||
routesPaths: string[],
|
routesPaths: string[],
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
) {
|
): sitemap.Sitemap {
|
||||||
const {url: hostname} = siteConfig;
|
const {url: hostname} = siteConfig;
|
||||||
if (!hostname) {
|
if (!hostname) {
|
||||||
throw new Error('url in docusaurus.config.js cannot be empty/undefined');
|
throw new Error('url in docusaurus.config.js cannot be empty/undefined');
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {PluginOptions} from './types';
|
||||||
import createSitemap from './createSitemap';
|
import createSitemap from './createSitemap';
|
||||||
import {LoadContext, Props, Plugin} from '@docusaurus/types';
|
import {LoadContext, Props, Plugin} from '@docusaurus/types';
|
||||||
|
|
||||||
const DEFAULT_OPTIONS: PluginOptions = {
|
const DEFAULT_OPTIONS: Required<PluginOptions> = {
|
||||||
cacheTime: 600 * 1000, // 600 sec - cache purge period.
|
cacheTime: 600 * 1000, // 600 sec - cache purge period.
|
||||||
changefreq: 'weekly',
|
changefreq: 'weekly',
|
||||||
priority: 0.5,
|
priority: 0.5,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface PluginOptions {
|
export interface PluginOptions {
|
||||||
cacheTime: number;
|
cacheTime?: number;
|
||||||
changefreq: string;
|
changefreq?: string;
|
||||||
priority: number;
|
priority?: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,8 @@ function Footer() {
|
||||||
<li
|
<li
|
||||||
key={key}
|
key={key}
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: item.html,
|
__html: item.html,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -32,6 +32,8 @@ function AnnouncementBar() {
|
||||||
role="banner">
|
role="banner">
|
||||||
<div
|
<div
|
||||||
className={styles.announcementBarContent}
|
className={styles.announcementBarContent}
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{__html: content}}
|
dangerouslySetInnerHTML={{__html: content}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ function Headings({headings, isChild}) {
|
||||||
<a
|
<a
|
||||||
href={`#${heading.id}`}
|
href={`#${heading.id}`}
|
||||||
className={LINK_CLASS_NAME}
|
className={LINK_CLASS_NAME}
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{__html: heading.value}}
|
dangerouslySetInnerHTML={{__html: heading.value}}
|
||||||
/>
|
/>
|
||||||
<Headings isChild headings={heading.children} />
|
<Headings isChild headings={heading.children} />
|
||||||
|
|
|
@ -74,6 +74,8 @@ function Footer() {
|
||||||
<li
|
<li
|
||||||
key={key}
|
key={key}
|
||||||
className="footer__item"
|
className="footer__item"
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: item.html,
|
__html: item.html,
|
||||||
}}
|
}}
|
||||||
|
@ -109,6 +111,8 @@ function Footer() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: copyright,
|
__html: copyright,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -323,6 +323,8 @@ function Search() {
|
||||||
{breadcrumbs.length > 0 && (
|
{breadcrumbs.length > 0 && (
|
||||||
<span
|
<span
|
||||||
className={styles.searchResultItemPath}
|
className={styles.searchResultItemPath}
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: breadcrumbs.join(' › '),
|
__html: breadcrumbs.join(' › '),
|
||||||
}}
|
}}
|
||||||
|
@ -332,6 +334,8 @@ function Search() {
|
||||||
{summary && (
|
{summary && (
|
||||||
<p
|
<p
|
||||||
className={styles.searchResultItemSummary}
|
className={styles.searchResultItemSummary}
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
dangerouslySetInnerHTML={{__html: summary}}
|
dangerouslySetInnerHTML={{__html: summary}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
32
packages/docusaurus-types/src/index.d.ts
vendored
32
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -22,23 +22,23 @@ export interface DocusaurusConfig {
|
||||||
themes?: PluginConfig[];
|
themes?: PluginConfig[];
|
||||||
presets?: PresetConfig[];
|
presets?: PresetConfig[];
|
||||||
themeConfig?: {
|
themeConfig?: {
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
customFields?: {
|
customFields?: {
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
scripts?: (
|
scripts?: (
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
src: string;
|
src: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
)[];
|
)[];
|
||||||
stylesheets?: (
|
stylesheets?: (
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
href: string;
|
href: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
)[];
|
)[];
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,10 @@ export interface Preset {
|
||||||
themes?: PluginConfig[];
|
themes?: PluginConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PresetConfig = [string, Object] | [string] | string;
|
export type PresetConfig =
|
||||||
|
| [string, Record<string, unknown>]
|
||||||
|
| [string]
|
||||||
|
| string;
|
||||||
|
|
||||||
export interface StartCLIOptions {
|
export interface StartCLIOptions {
|
||||||
port: string;
|
port: string;
|
||||||
|
@ -88,7 +91,7 @@ export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
|
||||||
|
|
||||||
export interface Props extends LoadContext, InjectedHtmlTags {
|
export interface Props extends LoadContext, InjectedHtmlTags {
|
||||||
routesPaths: string[];
|
routesPaths: string[];
|
||||||
plugins: Plugin<any>[];
|
plugins: Plugin<unknown>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginContentLoadedActions {
|
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 {
|
export interface ChunkRegistry {
|
||||||
loader: string;
|
loader: string;
|
||||||
|
@ -165,11 +171,17 @@ export interface ConfigureWebpackUtils {
|
||||||
getStyleLoaders: (
|
getStyleLoaders: (
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
cssOptions: {
|
cssOptions: {
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
},
|
},
|
||||||
) => Loader[];
|
) => Loader[];
|
||||||
getCacheLoader: (isServer: boolean, cacheOptions?: {}) => Loader | null;
|
getCacheLoader: (
|
||||||
getBabelLoader: (isServer: boolean, babelOptions?: {}) => Loader;
|
isServer: boolean,
|
||||||
|
cacheOptions?: Record<string, unknown>,
|
||||||
|
) => Loader | null;
|
||||||
|
getBabelLoader: (
|
||||||
|
isServer: boolean,
|
||||||
|
babelOptions?: Record<string, unknown>,
|
||||||
|
) => Loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HtmlTagObject {
|
interface HtmlTagObject {
|
||||||
|
|
|
@ -160,6 +160,8 @@ export function genChunkName(
|
||||||
return chunkName;
|
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 {
|
export function idx(target: any, keyPaths?: string | (string | number)[]): any {
|
||||||
return (
|
return (
|
||||||
target &&
|
target &&
|
||||||
|
@ -231,13 +233,15 @@ export function createExcerpt(fileString: string): string | undefined {
|
||||||
|
|
||||||
type ParsedMarkdown = {
|
type ParsedMarkdown = {
|
||||||
frontMatter: {
|
frontMatter: {
|
||||||
|
// Returned by gray-matter
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
content: string;
|
content: string;
|
||||||
excerpt: string | undefined;
|
excerpt: string | undefined;
|
||||||
};
|
};
|
||||||
export function parseMarkdownString(markdownString: string): ParsedMarkdown {
|
export function parseMarkdownString(markdownString: string): ParsedMarkdown {
|
||||||
const options: {} = {
|
const options: Record<string, unknown> = {
|
||||||
excerpt: (file: matter.GrayMatterFile<string>): void => {
|
excerpt: (file: matter.GrayMatterFile<string>): void => {
|
||||||
// Hacky way of stripping out import statements from the excerpt
|
// Hacky way of stripping out import statements from the excerpt
|
||||||
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
|
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
|
||||||
|
|
|
@ -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
|
// 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
|
// explicitly specify the version so that it can reuse the helper better
|
||||||
// See https://github.com/babel/babel/issues/10261
|
// 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,
|
version: require('@babel/runtime/package.json').version,
|
||||||
regenerator: true,
|
regenerator: true,
|
||||||
useESModules: true,
|
useESModules: true,
|
||||||
|
|
|
@ -28,7 +28,7 @@ interface State {
|
||||||
|
|
||||||
class PendingNavigation extends React.Component<Props, State> {
|
class PendingNavigation extends React.Component<Props, State> {
|
||||||
previousLocation: any;
|
previousLocation: any;
|
||||||
progressBarTimeout: any;
|
progressBarTimeout: NodeJS.Timeout | null;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(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
|
// Intercept location update and still show current route until next route
|
||||||
// is done loading.
|
// is done loading.
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||||
const routeDidChange = nextProps.location !== this.props.location;
|
const routeDidChange = nextProps.location !== this.props.location;
|
||||||
const {routes, delay = 1000} = this.props;
|
const {routes, delay = 1000} = this.props;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,20 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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';
|
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) => {
|
clientModules.forEach((clientModule) => {
|
||||||
const mod = clientModule.__esModule ? clientModule.default : clientModule;
|
const mod = clientModule.__esModule ? clientModule.default : clientModule;
|
||||||
if (mod && mod[lifecycleAction]) {
|
if (mod && mod[lifecycleAction]) {
|
||||||
|
@ -16,26 +27,13 @@ function dispatchLifecycleAction(lifecycleAction, ...args) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Dispatchers {
|
const clientLifecyclesDispatchers: Dispatchers = {
|
||||||
onRouteUpdate: Function;
|
onRouteUpdate(...args) {
|
||||||
onRouteUpdateDelayed: Function;
|
dispatchLifecycleAction('onRouteUpdate', ...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;
|
|
||||||
},
|
},
|
||||||
{},
|
onRouteUpdateDelayed(...args) {
|
||||||
) as Dispatchers;
|
dispatchLifecycleAction('onRouteUpdateDelayed', ...args);
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default createLifecyclesDispatcher();
|
export default clientLifecyclesDispatchers;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import docusaurus from './docusaurus';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface NodeModule {
|
interface NodeModule {
|
||||||
hot?: any;
|
hot?: {accept: () => void};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ const fetched = {};
|
||||||
const loaded = {};
|
const loaded = {};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase, @typescript-eslint/no-explicit-any
|
||||||
const __webpack_require__: any;
|
const __webpack_require__: {gca: (name: string) => string};
|
||||||
interface Navigator {
|
interface Navigator {
|
||||||
connection: any;
|
connection: any;
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,14 @@ const isSlowConnection = () => {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const canPrefetch = (routePath) =>
|
const canPrefetch = (routePath: string) =>
|
||||||
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
|
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
|
||||||
|
|
||||||
const canPreload = (routePath) => !isSlowConnection() && !loaded[routePath];
|
const canPreload = (routePath: string) =>
|
||||||
|
!isSlowConnection() && !loaded[routePath];
|
||||||
|
|
||||||
const docusaurus = {
|
const docusaurus = {
|
||||||
prefetch: (routePath) => {
|
prefetch: (routePath: string): boolean => {
|
||||||
if (!canPrefetch(routePath)) {
|
if (!canPrefetch(routePath)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -50,13 +51,13 @@ const docusaurus = {
|
||||||
|
|
||||||
// Find all webpack chunk names needed.
|
// Find all webpack chunk names needed.
|
||||||
const matches = matchRoutes(routes, routePath);
|
const matches = matchRoutes(routes, routePath);
|
||||||
const chunkNamesNeeded = matches.reduce((arr, match) => {
|
const chunkNamesNeeded = matches.reduce((arr: string[], match) => {
|
||||||
const chunk = routesChunkNames[match.route.path];
|
const chunk = routesChunkNames[match.route.path as string];
|
||||||
if (!chunk) {
|
if (!chunk) {
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chunkNames = Object.values(flat(chunk));
|
const chunkNames = Object.values(flat(chunk)) as string[];
|
||||||
return arr.concat(chunkNames);
|
return arr.concat(chunkNames);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ const docusaurus = {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
preload: (routePath) => {
|
preload: (routePath: string): boolean => {
|
||||||
if (!canPreload(routePath)) {
|
if (!canPreload(routePath)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ExecutionEnvironment from './ExecutionEnvironment';
|
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) {
|
if (!ExecutionEnvironment.canUseDOM || children == null) {
|
||||||
return fallback || null;
|
return fallback || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>{children()}</>;
|
return <>{children()}</>;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import routesChunkNames from '@generated/routesChunkNames';
|
||||||
import registry from '@generated/registry';
|
import registry from '@generated/registry';
|
||||||
import flat from '../flat';
|
import flat from '../flat';
|
||||||
|
|
||||||
function ComponentCreator(path: string) {
|
function ComponentCreator(path: string): ReturnType<typeof Loadable> {
|
||||||
// 404 page
|
// 404 page
|
||||||
if (path === '*') {
|
if (path === '*') {
|
||||||
return Loadable({
|
return Loadable({
|
||||||
|
|
|
@ -15,7 +15,8 @@ const ExecutionEnvironment = {
|
||||||
canUseDOM,
|
canUseDOM,
|
||||||
|
|
||||||
canUseEventListeners:
|
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),
|
canUseDOM && !!(window.addEventListener || window.attachEvent),
|
||||||
|
|
||||||
canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window,
|
canUseIntersectionObserver: canUseDOM && 'IntersectionObserver' in window,
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
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} />;
|
return <Helmet {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 React, {useEffect, useRef} from 'react';
|
import React, {ReactNode, useEffect, useRef} from 'react';
|
||||||
|
|
||||||
import {NavLink, Link as RRLink} from 'react-router-dom';
|
import {NavLink, Link as RRLink} from 'react-router-dom';
|
||||||
import isInternalUrl from './isInternalUrl';
|
import isInternalUrl from './isInternalUrl';
|
||||||
|
@ -21,6 +21,7 @@ interface Props {
|
||||||
readonly isNavLink?: boolean;
|
readonly isNavLink?: boolean;
|
||||||
readonly to?: string;
|
readonly to?: string;
|
||||||
readonly href: string;
|
readonly href: string;
|
||||||
|
readonly children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Link({isNavLink, ...props}: Props): JSX.Element {
|
function Link({isNavLink, ...props}: Props): JSX.Element {
|
||||||
|
@ -85,6 +86,7 @@ function Link({isNavLink, ...props}: Props): JSX.Element {
|
||||||
return !targetLink || !isInternal || targetLink.startsWith('#') ? (
|
return !targetLink || !isInternal || targetLink.startsWith('#') ? (
|
||||||
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
||||||
<a
|
<a
|
||||||
|
// @ts-expect-error: href specified twice needed to pass children and other user specified props
|
||||||
href={targetLink}
|
href={targetLink}
|
||||||
{...(!isInternal && {target: '_blank', rel: 'noopener noreferrer'})}
|
{...(!isInternal && {target: '_blank', rel: 'noopener noreferrer'})}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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 delimiter = '.';
|
||||||
const output = {};
|
const output = {};
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Memoize previously normalized pathnames.
|
type Location = {pathname: string};
|
||||||
const pathnames = {};
|
|
||||||
|
|
||||||
function normalizeLocation(location) {
|
// Memoize previously normalized pathnames.
|
||||||
|
const pathnames: Record<string, string> = {};
|
||||||
|
|
||||||
|
function normalizeLocation<T extends Location>(location: T): T {
|
||||||
if (pathnames[location.pathname]) {
|
if (pathnames[location.pathname]) {
|
||||||
return {
|
return {
|
||||||
...location,
|
...location,
|
||||||
|
|
|
@ -5,24 +5,29 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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
|
* Helper function to make sure all async components for that particular route
|
||||||
* is preloaded before rendering. This is especially useful to avoid loading screens.
|
* is preloaded before rendering. This is especially useful to avoid loading screens.
|
||||||
*
|
*
|
||||||
* @param {Array<RouteConfig>} routes react-router-config
|
* @param routes react-router-config
|
||||||
* @param {string} pathname the route pathname, example: /docs/installation
|
* @param pathname the route pathname, example: /docs/installation
|
||||||
* @returns {Promise} Promise object represents whether pathname has been preloaded
|
* @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);
|
const matches = matchRoutes(routes, pathname);
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
matches.map((match) => {
|
matches.map((match) => {
|
||||||
const {component} = match.route;
|
const {component} = match.route;
|
||||||
|
|
||||||
|
// @ts-expect-error: ComponentCreator injected this method.
|
||||||
if (component && component.preload) {
|
if (component && component.preload) {
|
||||||
|
// @ts-expect-error: checked above.
|
||||||
return component.preload();
|
return component.preload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@ import merge from 'webpack-merge';
|
||||||
import {STATIC_DIR_NAME} from '../constants';
|
import {STATIC_DIR_NAME} from '../constants';
|
||||||
import {load} from '../server';
|
import {load} from '../server';
|
||||||
import {BuildCLIOptions, Props} from '@docusaurus/types';
|
import {BuildCLIOptions, Props} from '@docusaurus/types';
|
||||||
import {createClientConfig} from '../webpack/client';
|
import createClientConfig from '../webpack/client';
|
||||||
import {createServerConfig} from '../webpack/server';
|
import createServerConfig from '../webpack/server';
|
||||||
import {applyConfigureWebpack} from '../webpack/utils';
|
import {applyConfigureWebpack} from '../webpack/utils';
|
||||||
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
|
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
|
||||||
|
|
||||||
function compile(config: Configuration[]): Promise<any> {
|
function compile(config: Configuration[]): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const compiler = webpack(config);
|
const compiler = webpack(config);
|
||||||
compiler.run((err, stats) => {
|
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,
|
siteDir: string,
|
||||||
cliOptions: Partial<BuildCLIOptions> = {},
|
cliOptions: Partial<BuildCLIOptions> = {},
|
||||||
forceTerminate: boolean = true,
|
forceTerminate: boolean = true,
|
||||||
|
|
|
@ -10,11 +10,11 @@ import path from 'path';
|
||||||
import shell from 'shelljs';
|
import shell from 'shelljs';
|
||||||
import {CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME} from '../constants';
|
import {CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME} from '../constants';
|
||||||
import {loadContext} from '../server';
|
import {loadContext} from '../server';
|
||||||
import {loadConfig} from '../server/config';
|
import loadConfig from '../server/config';
|
||||||
import {build} from './build';
|
import build from './build';
|
||||||
import {BuildCLIOptions} from '@docusaurus/types';
|
import {BuildCLIOptions} from '@docusaurus/types';
|
||||||
|
|
||||||
export async function deploy(
|
export default async function deploy(
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
cliOptions: Partial<BuildCLIOptions> = {},
|
cliOptions: Partial<BuildCLIOptions> = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
@ -98,7 +98,7 @@ export async function deploy(
|
||||||
// out to deployment branch.
|
// out to deployment branch.
|
||||||
const currentCommit = shell.exec('git rev-parse HEAD').stdout.trim();
|
const currentCommit = shell.exec('git rev-parse HEAD').stdout.trim();
|
||||||
|
|
||||||
const runDeploy = (outDir) => {
|
const runDeploy = (outputDirectory) => {
|
||||||
if (shell.cd(tempDir).code !== 0) {
|
if (shell.cd(tempDir).code !== 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Temp dir ${GENERATED_FILES_DIR_NAME} does not exists. Run build website first.`,
|
`Temp dir ${GENERATED_FILES_DIR_NAME} does not exists. Run build website first.`,
|
||||||
|
@ -141,7 +141,7 @@ export async function deploy(
|
||||||
|
|
||||||
shell.cd('../..');
|
shell.cd('../..');
|
||||||
|
|
||||||
const fromPath = outDir;
|
const fromPath = outputDirectory;
|
||||||
const toPath = path.join(
|
const toPath = path.join(
|
||||||
GENERATED_FILES_DIR_NAME,
|
GENERATED_FILES_DIR_NAME,
|
||||||
`${projectName}-${deploymentBranch}`,
|
`${projectName}-${deploymentBranch}`,
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
import {CommanderStatic} from 'commander';
|
import {CommanderStatic} from 'commander';
|
||||||
import {loadContext, loadPluginConfigs} from '../server';
|
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 context = loadContext(siteDir);
|
||||||
const pluginConfigs = loadPluginConfigs(context);
|
const pluginConfigs = loadPluginConfigs(context);
|
||||||
const plugins = initPlugins({pluginConfigs, context});
|
const plugins = initPlugins({pluginConfigs, context});
|
||||||
|
|
|
@ -23,7 +23,7 @@ import HotModuleReplacementPlugin from 'webpack/lib/HotModuleReplacementPlugin';
|
||||||
import {load} from '../server';
|
import {load} from '../server';
|
||||||
import {StartCLIOptions} from '@docusaurus/types';
|
import {StartCLIOptions} from '@docusaurus/types';
|
||||||
import {CONFIG_FILE_NAME, STATIC_DIR_NAME, DEFAULT_PORT} from '../constants';
|
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';
|
import {applyConfigureWebpack} from '../webpack/utils';
|
||||||
|
|
||||||
function getHost(reqHost: string | undefined): string {
|
function getHost(reqHost: string | undefined): string {
|
||||||
|
@ -36,7 +36,7 @@ async function getPort(reqPort: string | undefined): Promise<number> {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function start(
|
export default async function start(
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
cliOptions: Partial<StartCLIOptions> = {},
|
cliOptions: Partial<StartCLIOptions> = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
@ -65,9 +65,7 @@ export async function start(
|
||||||
const pluginPaths: string[] = ([] as string[])
|
const pluginPaths: string[] = ([] as string[])
|
||||||
.concat(
|
.concat(
|
||||||
...plugins
|
...plugins
|
||||||
.map<any>(
|
.map((plugin) => plugin.getPathsToWatch?.() ?? [])
|
||||||
(plugin) => plugin.getPathsToWatch && plugin.getPathsToWatch(),
|
|
||||||
)
|
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
)
|
)
|
||||||
.map(normalizeToSiteDir);
|
.map(normalizeToSiteDir);
|
||||||
|
@ -172,7 +170,9 @@ export async function start(
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
cliOptions.open && openBrowser(openUrl);
|
if (cliOptions.open) {
|
||||||
|
openBrowser(openUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
||||||
process.on(sig as NodeJS.Signals, () => {
|
process.on(sig as NodeJS.Signals, () => {
|
||||||
|
|
|
@ -9,19 +9,22 @@ import chalk = require('chalk');
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import importFresh from 'import-fresh';
|
import importFresh from 'import-fresh';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import {Plugin, LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
import {THEME_PATH} from '../constants';
|
import {THEME_PATH} from '../constants';
|
||||||
import {loadContext} from '../server';
|
import {loadContext} from '../server';
|
||||||
|
|
||||||
export async function swizzle(
|
export default async function swizzle(
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
themeName: string,
|
themeName: string,
|
||||||
componentName?: string,
|
componentName?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const plugin: any = importFresh(themeName);
|
const plugin = importFresh(themeName) as (
|
||||||
|
context: LoadContext,
|
||||||
|
) => Plugin<unknown>;
|
||||||
const context = loadContext(siteDir);
|
const context = loadContext(siteDir);
|
||||||
const pluginInstance = plugin(context);
|
const pluginInstance = plugin(context);
|
||||||
let fromPath = pluginInstance.getThemePath();
|
let fromPath = pluginInstance.getThemePath?.();
|
||||||
|
|
||||||
if (fromPath) {
|
if (fromPath) {
|
||||||
let toPath = path.resolve(siteDir, THEME_PATH);
|
let toPath = path.resolve(siteDir, THEME_PATH);
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {build} from './commands/build';
|
export {default as build} from './commands/build';
|
||||||
export {start} from './commands/start';
|
export {default as start} from './commands/start';
|
||||||
export {swizzle} from './commands/swizzle';
|
export {default as swizzle} from './commands/swizzle';
|
||||||
export {deploy} from './commands/deploy';
|
export {default as deploy} from './commands/deploy';
|
||||||
export {externalCommand} from './commands/external';
|
export {default as externalCommand} from './commands/external';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {loadConfig} from '../config';
|
import loadConfig from '../config';
|
||||||
|
|
||||||
describe('loadConfig', () => {
|
describe('loadConfig', () => {
|
||||||
test('website with valid siteConfig', async () => {
|
test('website with valid siteConfig', async () => {
|
||||||
|
|
|
@ -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 {loadRoutes} from '../routes';
|
import loadRoutes from '../routes';
|
||||||
import {RouteConfig} from '@docusaurus/types';
|
import {RouteConfig} from '@docusaurus/types';
|
||||||
|
|
||||||
describe('loadRoutes', () => {
|
describe('loadRoutes', () => {
|
||||||
|
|
|
@ -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 {loadClientModules} from '../index';
|
import loadClientModules from '../index';
|
||||||
|
|
||||||
import pluginEmpty from './__fixtures__/plugin-empty';
|
import pluginEmpty from './__fixtures__/plugin-empty';
|
||||||
import pluginFooBar from './__fixtures__/plugin-foo-bar';
|
import pluginFooBar from './__fixtures__/plugin-foo-bar';
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
|
|
||||||
import {Plugin} from '@docusaurus/types';
|
import {Plugin} from '@docusaurus/types';
|
||||||
|
|
||||||
export function loadClientModules(plugins: Plugin<unknown>[]): string[] {
|
export default function loadClientModules(
|
||||||
|
plugins: Plugin<unknown>[],
|
||||||
|
): string[] {
|
||||||
return ([] as string[]).concat(
|
return ([] as string[]).concat(
|
||||||
...plugins
|
...plugins
|
||||||
.map<any>(
|
.map((plugin) => plugin.getClientModules?.() ?? [])
|
||||||
(plugin) => plugin.getClientModules && plugin.getClientModules(),
|
|
||||||
)
|
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ function formatFields(fields: string[]): string {
|
||||||
return fields.map((field) => `'${field}'`).join(', ');
|
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);
|
const configPath = path.resolve(siteDir, CONFIG_FILE_NAME);
|
||||||
|
|
||||||
if (!fs.existsSync(configPath)) {
|
if (!fs.existsSync(configPath)) {
|
||||||
|
|
|
@ -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 {htmlTagObjectToString} from '../htmlTags';
|
import htmlTagObjectToString from '../htmlTags';
|
||||||
|
|
||||||
describe('htmlTagObjectToString', () => {
|
describe('htmlTagObjectToString', () => {
|
||||||
test('simple html tag', () => {
|
test('simple html tag', () => {
|
||||||
|
|
|
@ -10,10 +10,11 @@ import {HtmlTagObject} from '@docusaurus/types';
|
||||||
import htmlTags from 'html-tags';
|
import htmlTags from 'html-tags';
|
||||||
import voidHtmlTags from 'html-tags/void';
|
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)) {
|
if (!isPlainObject(val)) {
|
||||||
throw new Error(`"${val}" is not a valid HTML tag object`);
|
throw new Error(`"${val}" is not a valid HTML tag object`);
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error: If tagName doesn't exist, it will throw.
|
||||||
if (typeof val.tagName !== 'string') {
|
if (typeof val.tagName !== 'string') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${JSON.stringify(
|
`${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);
|
assertIsHtmlTagObject(tagDefinition);
|
||||||
if (htmlTags.indexOf(tagDefinition.tagName) === -1) {
|
if (htmlTags.indexOf(tagDefinition.tagName) === -1) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
@ -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 {htmlTagObjectToString} from './htmlTags';
|
import htmlTagObjectToString from './htmlTags';
|
||||||
import {
|
import {
|
||||||
Plugin,
|
Plugin,
|
||||||
InjectedHtmlTags,
|
InjectedHtmlTags,
|
||||||
|
@ -21,7 +21,7 @@ export function createHtmlTagsString(tags: HtmlTags): string {
|
||||||
return Array.isArray(tags) ? tags.map(toString).join('\n') : toString(tags);
|
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(
|
const htmlTags = plugins.reduce(
|
||||||
(acc, plugin) => {
|
(acc, plugin) => {
|
||||||
if (!plugin.injectHtmlTags) {
|
if (!plugin.injectHtmlTags) {
|
||||||
|
|
|
@ -13,12 +13,12 @@ import {
|
||||||
GENERATED_FILES_DIR_NAME,
|
GENERATED_FILES_DIR_NAME,
|
||||||
THEME_PATH,
|
THEME_PATH,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import {loadClientModules} from './client-modules';
|
import loadClientModules from './client-modules';
|
||||||
import {loadConfig} from './config';
|
import loadConfig from './config';
|
||||||
import {loadPlugins} from './plugins';
|
import {loadPlugins} from './plugins';
|
||||||
import {loadPresets} from './presets';
|
import loadPresets from './presets';
|
||||||
import {loadRoutes} from './routes';
|
import loadRoutes from './routes';
|
||||||
import {loadThemeAlias} from './themes';
|
import loadThemeAlias from './themes';
|
||||||
import {
|
import {
|
||||||
DocusaurusConfig,
|
DocusaurusConfig,
|
||||||
LoadContext,
|
LoadContext,
|
||||||
|
@ -84,11 +84,9 @@ export async function load(
|
||||||
|
|
||||||
// Themes.
|
// Themes.
|
||||||
const fallbackTheme = path.resolve(__dirname, '../client/theme-fallback');
|
const fallbackTheme = path.resolve(__dirname, '../client/theme-fallback');
|
||||||
const pluginThemes = ([] as string[]).concat(
|
const pluginThemes: string[] = plugins
|
||||||
...plugins
|
.map((plugin) => plugin.getThemePath && plugin.getThemePath())
|
||||||
.map<any>((plugin) => plugin.getThemePath && plugin.getThemePath())
|
.filter((x): x is string => Boolean(x));
|
||||||
.filter(Boolean),
|
|
||||||
);
|
|
||||||
const userTheme = path.resolve(siteDir, THEME_PATH);
|
const userTheme = path.resolve(siteDir, THEME_PATH);
|
||||||
const alias = loadThemeAlias([fallbackTheme, ...pluginThemes], [userTheme]);
|
const alias = loadThemeAlias([fallbackTheme, ...pluginThemes], [userTheme]);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {load} from './index';
|
||||||
import {Props} from '@docusaurus/types';
|
import {Props} from '@docusaurus/types';
|
||||||
|
|
||||||
// Helper methods to setup dummy/fake projects.
|
// 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 fixtures = path.join(__dirname, '__tests__', '__fixtures__');
|
||||||
const simpleSite = path.join(fixtures, 'simple-site');
|
const simpleSite = path.join(fixtures, 'simple-site');
|
||||||
const customSite = path.join(fixtures, 'custom-site');
|
const customSite = path.join(fixtures, 'custom-site');
|
||||||
|
@ -23,3 +23,5 @@ export const loadSetup = async (name: string): Promise<Props> => {
|
||||||
return load(simpleSite);
|
return load(simpleSite);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default loadSetup;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
PluginContentLoadedActions,
|
PluginContentLoadedActions,
|
||||||
RouteConfig,
|
RouteConfig,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {initPlugins} from './init';
|
import initPlugins from './init';
|
||||||
|
|
||||||
export function sortConfig(routeConfigs: RouteConfig[]): void {
|
export function sortConfig(routeConfigs: RouteConfig[]): void {
|
||||||
// Sort the route config. This ensures that route with nested
|
// 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) {
|
if (a.priority || b.priority) {
|
||||||
const priorityA = a.priority || 0;
|
const priorityA = a.priority || 0;
|
||||||
const priorityB = b.priority || 0;
|
const priorityB = b.priority || 0;
|
||||||
const score = priorityA > priorityB ? -1 : priorityB > priorityA ? 1 : 0;
|
const score = priorityB - priorityA;
|
||||||
|
|
||||||
if (score !== 0) {
|
if (score !== 0) {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
return a.path.localeCompare(b.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
routeConfigs.forEach((routeConfig) => {
|
routeConfigs.forEach((routeConfig) => {
|
||||||
routeConfig.routes?.sort((a, b) => {
|
routeConfig.routes?.sort((a, b) => a.path.localeCompare(b.path));
|
||||||
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ import importFresh from 'import-fresh';
|
||||||
import {LoadContext, Plugin, PluginConfig} from '@docusaurus/types';
|
import {LoadContext, Plugin, PluginConfig} from '@docusaurus/types';
|
||||||
import {CONFIG_FILE_NAME} from '../../constants';
|
import {CONFIG_FILE_NAME} from '../../constants';
|
||||||
|
|
||||||
export function initPlugins({
|
export default function initPlugins({
|
||||||
pluginConfigs,
|
pluginConfigs,
|
||||||
context,
|
context,
|
||||||
}: {
|
}: {
|
||||||
pluginConfigs: PluginConfig[];
|
pluginConfigs: PluginConfig[];
|
||||||
context: LoadContext;
|
context: LoadContext;
|
||||||
}): Plugin<any>[] {
|
}): Plugin<unknown>[] {
|
||||||
// We need to resolve plugins from the perspective of the siteDir, since the siteDir's package.json
|
// We need to resolve plugins from the perspective of the siteDir, since the siteDir's package.json
|
||||||
// declares the dependency on these plugins.
|
// declares the dependency on these plugins.
|
||||||
// We need to fallback to createRequireFromPath since createRequire is only available in node v12.
|
// 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 createRequire = Module.createRequire || Module.createRequireFromPath;
|
||||||
const pluginRequire = createRequire(join(context.siteDir, CONFIG_FILE_NAME));
|
const pluginRequire = createRequire(join(context.siteDir, CONFIG_FILE_NAME));
|
||||||
|
|
||||||
const plugins: Plugin<any>[] = pluginConfigs
|
const plugins: Plugin<unknown>[] = pluginConfigs
|
||||||
.map((pluginItem) => {
|
.map((pluginItem) => {
|
||||||
let pluginModuleImport: string | undefined;
|
let pluginModuleImport: string | undefined;
|
||||||
let pluginOptions = {};
|
let pluginOptions = {};
|
||||||
|
@ -37,8 +37,7 @@ export function initPlugins({
|
||||||
if (typeof pluginItem === 'string') {
|
if (typeof pluginItem === 'string') {
|
||||||
pluginModuleImport = pluginItem;
|
pluginModuleImport = pluginItem;
|
||||||
} else if (Array.isArray(pluginItem)) {
|
} else if (Array.isArray(pluginItem)) {
|
||||||
pluginModuleImport = pluginItem[0];
|
[pluginModuleImport, pluginOptions = {}] = pluginItem;
|
||||||
pluginOptions = pluginItem[1] || {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginModuleImport) {
|
if (!pluginModuleImport) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import {loadPresets} from '../index';
|
import loadPresets from '../index';
|
||||||
import {LoadContext} from '@docusaurus/types';
|
import {LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
describe('loadPresets', () => {
|
describe('loadPresets', () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
PresetConfig,
|
PresetConfig,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
|
|
||||||
export function loadPresets(
|
export default function loadPresets(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
): {
|
): {
|
||||||
plugins: PluginConfig[];
|
plugins: PluginConfig[];
|
||||||
|
|
|
@ -36,10 +36,21 @@ function getModulePath(target: Module): string {
|
||||||
return `${target.path}${queryStr}`;
|
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[],
|
pluginsRouteConfigs: RouteConfig[],
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
) {
|
): Promise<LoadedRoutes> {
|
||||||
const routesImports = [
|
const routesImports = [
|
||||||
`import React from 'react';`,
|
`import React from 'react';`,
|
||||||
`import ComponentCreator from '@docusaurus/ComponentCreator';`,
|
`import ComponentCreator from '@docusaurus/ComponentCreator';`,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import {themeAlias} from '../alias';
|
import themeAlias from '../alias';
|
||||||
|
|
||||||
describe('themeAlias', () => {
|
describe('themeAlias', () => {
|
||||||
test('valid themePath 1 with components', () => {
|
test('valid themePath 1 with components', () => {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {loadThemeAlias} from '../index';
|
import loadThemeAlias from '../index';
|
||||||
|
|
||||||
describe('loadThemeAlias', () => {
|
describe('loadThemeAlias', () => {
|
||||||
test('next alias can override the previous alias', () => {
|
test('next alias can override the previous alias', () => {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import path from 'path';
|
||||||
import {fileToPath, posixPath, normalizeUrl} from '@docusaurus/utils';
|
import {fileToPath, posixPath, normalizeUrl} from '@docusaurus/utils';
|
||||||
import {ThemeAlias} from '@docusaurus/types';
|
import {ThemeAlias} from '@docusaurus/types';
|
||||||
|
|
||||||
export function themeAlias(
|
export default function themeAlias(
|
||||||
themePath: string,
|
themePath: string,
|
||||||
addOriginalAlias: boolean = true,
|
addOriginalAlias: boolean = true,
|
||||||
): ThemeAlias {
|
): ThemeAlias {
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ThemeAlias} from '@docusaurus/types';
|
import {ThemeAlias} from '@docusaurus/types';
|
||||||
import {themeAlias} from './alias';
|
import themeAlias from './alias';
|
||||||
|
|
||||||
export function loadThemeAlias(
|
export default function loadThemeAlias(
|
||||||
themePaths: string[],
|
themePaths: string[],
|
||||||
userThemePaths: string[] = [],
|
userThemePaths: string[] = [],
|
||||||
): ThemeAlias {
|
): ThemeAlias {
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
import {validate} from 'webpack';
|
import {validate} from 'webpack';
|
||||||
|
|
||||||
import {createClientConfig} from '../client';
|
import createClientConfig from '../client';
|
||||||
import {loadSetup} from '../../server/loadSetup';
|
import loadSetup from '../../server/loadSetup';
|
||||||
|
|
||||||
describe('webpack dev config', () => {
|
describe('webpack dev config', () => {
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
import {validate} from 'webpack';
|
import {validate} from 'webpack';
|
||||||
|
|
||||||
import {createServerConfig} from '../server';
|
import createServerConfig from '../server';
|
||||||
import {loadSetup} from '../../server/loadSetup';
|
import loadSetup from '../../server/loadSetup';
|
||||||
|
|
||||||
describe('webpack production config', () => {
|
describe('webpack production config', () => {
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {createBaseConfig} from './base';
|
||||||
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
|
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
|
||||||
import LogPlugin from './plugins/LogPlugin';
|
import LogPlugin from './plugins/LogPlugin';
|
||||||
|
|
||||||
export function createClientConfig(
|
export default function createClientConfig(
|
||||||
props: Props,
|
props: Props,
|
||||||
minify: boolean = true,
|
minify: boolean = true,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
|
@ -46,7 +46,7 @@ export function createClientConfig(
|
||||||
|
|
||||||
// When building include the plugin to force terminate building if errors happened in the client bundle.
|
// When building include the plugin to force terminate building if errors happened in the client bundle.
|
||||||
if (isBuilding) {
|
if (isBuilding) {
|
||||||
clientConfig.plugins!.push({
|
clientConfig.plugins?.push({
|
||||||
apply: (compiler) => {
|
apply: (compiler) => {
|
||||||
compiler.hooks.done.tap('client:done', (stats) => {
|
compiler.hooks.done.tap('client:done', (stats) => {
|
||||||
if (stats.hasErrors()) {
|
if (stats.hasErrors()) {
|
||||||
|
|
|
@ -33,6 +33,9 @@ import path from 'path';
|
||||||
import {sync as delSync} from 'del';
|
import {sync as delSync} from 'del';
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
|
/** @deprecated */
|
||||||
|
allowExternal?: unknown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate the removal of files
|
* Simulate the removal of files
|
||||||
*
|
*
|
||||||
|
@ -110,7 +113,6 @@ class CleanWebpackPlugin {
|
||||||
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional`);
|
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
if (options.allowExternal) {
|
if (options.allowExternal) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'clean-webpack-plugin: `allowExternal` option no longer supported. Use `dangerouslyAllowCleanPatternsOutsideProject`',
|
'clean-webpack-plugin: `allowExternal` option no longer supported. Use `dangerouslyAllowCleanPatternsOutsideProject`',
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {createBaseConfig} from './base';
|
||||||
import WaitPlugin from './plugins/WaitPlugin';
|
import WaitPlugin from './plugins/WaitPlugin';
|
||||||
import LogPlugin from './plugins/LogPlugin';
|
import LogPlugin from './plugins/LogPlugin';
|
||||||
|
|
||||||
export function createServerConfig(
|
export default function createServerConfig(
|
||||||
props: Props,
|
props: Props,
|
||||||
minify: boolean = true,
|
minify: boolean = true,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import env from 'std-env';
|
||||||
import merge from 'webpack-merge';
|
import merge from 'webpack-merge';
|
||||||
import {Configuration, Loader} from 'webpack';
|
import {Configuration, Loader} from 'webpack';
|
||||||
import {TransformOptions} from '@babel/core';
|
import {TransformOptions} from '@babel/core';
|
||||||
|
import {ConfigureWebpackUtils} from '@docusaurus/types';
|
||||||
|
|
||||||
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
|
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(
|
export function getStyleLoaders(
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
cssOptions: {
|
cssOptions: {
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
} = {},
|
} = {},
|
||||||
): Loader[] {
|
): Loader[] {
|
||||||
if (isServer) {
|
if (isServer) {
|
||||||
|
@ -53,7 +54,7 @@ export function getStyleLoaders(
|
||||||
// https://github.com/facebook/create-react-app/issues/2677
|
// https://github.com/facebook/create-react-app/issues/2677
|
||||||
ident: 'postcss',
|
ident: 'postcss',
|
||||||
plugins: () => [
|
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')({
|
require('postcss-preset-env')({
|
||||||
autoprefixer: {
|
autoprefixer: {
|
||||||
flexbox: 'no-2009',
|
flexbox: 'no-2009',
|
||||||
|
@ -69,7 +70,7 @@ export function getStyleLoaders(
|
||||||
|
|
||||||
export function getCacheLoader(
|
export function getCacheLoader(
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
cacheOptions?: {},
|
cacheOptions?: {[key: string]: unknown},
|
||||||
): Loader | null {
|
): Loader | null {
|
||||||
if (env.ci || env.test) {
|
if (env.ci || env.test) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -113,13 +114,19 @@ export function getBabelLoader(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to modify webpack config
|
* Helper function to modify webpack config
|
||||||
* @param {Object | Function} configureWebpack a webpack config or a function to modify config
|
* @param configureWebpack a webpack config or a function to modify config
|
||||||
* @param {Object} config initial webpack config
|
* @param config initial webpack config
|
||||||
* @param {boolean} isServer indicates if this is a server webpack configuration
|
* @param isServer indicates if this is a server webpack configuration
|
||||||
* @returns {Object} final/ modified webpack config
|
* @returns final/ modified webpack config
|
||||||
*/
|
*/
|
||||||
export function applyConfigureWebpack(
|
export function applyConfigureWebpack(
|
||||||
configureWebpack: any,
|
configureWebpack:
|
||||||
|
| Configuration
|
||||||
|
| ((
|
||||||
|
config: Configuration,
|
||||||
|
isServer: boolean,
|
||||||
|
utils: ConfigureWebpackUtils,
|
||||||
|
) => Configuration),
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
|
|
|
@ -7,10 +7,9 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import Vibrant from 'node-vibrant';
|
import Vibrant from 'node-vibrant';
|
||||||
|
import {Palette} from 'node-vibrant/lib/color';
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import {toPalette, toBase64} from '../utils';
|
import {toPalette, toBase64} from '../utils';
|
||||||
// @ts-ignore
|
|
||||||
import lqip from '../lqip';
|
import lqip from '../lqip';
|
||||||
|
|
||||||
describe('lqip-loader', () => {
|
describe('lqip-loader', () => {
|
||||||
|
@ -24,8 +23,8 @@ describe('lqip-loader', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toPalette', () => {
|
describe('toPalette', () => {
|
||||||
let correctTestSwatch: object = {};
|
let correctTestSwatch: Palette = {};
|
||||||
let testSwatchWithNull: object = {};
|
let testSwatchWithNull: Palette & {Vibrant?: null} = {};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg');
|
const imgPath = path.join(__dirname, '__fixtures__', 'endi.jpg');
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
const sortBy = require('lodash.sortby');
|
const sortBy = require('lodash.sortby');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,7 +14,7 @@ const sortBy = require('lodash.sortby');
|
||||||
* @description it returns a Base64 image string with required formatting
|
* @description it returns a Base64 image string with required formatting
|
||||||
* to work on the web (<img src=".." /> or in CSS url('..'))
|
* 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
|
* @param data: base64 string
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
@ -25,10 +27,11 @@ const toBase64 = (extMimeType, data) => {
|
||||||
* @description takes a color swatch object, converts it to an array & returns
|
* @description takes a color swatch object, converts it to an array & returns
|
||||||
* only hex color
|
* only hex color
|
||||||
*
|
*
|
||||||
* @param swatch
|
* @param {import("node-vibrant/lib/color").Palette} swatch
|
||||||
* @returns {{palette: Array}}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
const toPalette = (swatch) => {
|
const toPalette = (swatch) => {
|
||||||
|
/** @type {Array<{popularity: number, hex: string}>} */
|
||||||
let palette = Object.keys(swatch).reduce((result, key) => {
|
let palette = Object.keys(swatch).reduce((result, key) => {
|
||||||
if (swatch[key] !== null) {
|
if (swatch[key] !== null) {
|
||||||
result.push({
|
result.push({
|
||||||
|
@ -39,8 +42,7 @@ const toPalette = (swatch) => {
|
||||||
return result;
|
return result;
|
||||||
}, []);
|
}, []);
|
||||||
palette = sortBy(palette, ['popularity']);
|
palette = sortBy(palette, ['popularity']);
|
||||||
palette = palette.map((color) => color.hex).reverse();
|
return palette.map((color) => color.hex).reverse();
|
||||||
return palette;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
53
yarn.lock
53
yarn.lock
|
@ -2795,6 +2795,11 @@
|
||||||
"@types/minimatch" "*"
|
"@types/minimatch" "*"
|
||||||
"@types/node" "*"
|
"@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":
|
"@types/html-minifier-terser@^5.0.0":
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.0.0.tgz#7532440c138605ced1b555935c3115ddd20e8bef"
|
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" "*"
|
||||||
"@types/webpack-dev-server" "*"
|
"@types/webpack-dev-server" "*"
|
||||||
|
|
||||||
"@types/react@^16.9.13":
|
"@types/react-helmet@^6.0.0":
|
||||||
version "16.9.32"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.32.tgz#f6368625b224604148d1ddf5920e4fefbd98d383"
|
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.0.0.tgz#5b74e44a12662ffb12d1c97ee702cf4e220958cf"
|
||||||
integrity sha512-fmejdp0CTH00mOJmxUPPbWCEBWPvRIL4m8r0qD+BSDUqmutPyGQCHifzMpMzdvZwROdEdL78IuZItntFWgPXHQ==
|
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:
|
dependencies:
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
csstype "^2.2.0"
|
csstype "^2.2.0"
|
||||||
|
@ -17815,10 +17852,10 @@ typedarray@^0.0.6:
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||||
|
|
||||||
typescript@^3.7.2:
|
typescript@^3.9.5:
|
||||||
version "3.8.3"
|
version "3.9.5"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
|
||||||
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
|
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
|
||||||
|
|
||||||
ua-parser-js@^0.7.18:
|
ua-parser-js@^0.7.18:
|
||||||
version "0.7.21"
|
version "0.7.21"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue