refactor: capitalize comments (#7188)

* refactor: capitalize comments

* revert...
This commit is contained in:
Joshua Chen 2022-04-17 16:39:11 +08:00 committed by GitHub
parent 200009008b
commit fa1ce230ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
99 changed files with 241 additions and 350 deletions

View file

@ -16,9 +16,12 @@ const PlaygroundConfigs = {
codesandbox: codesandbox:
'https://codesandbox.io/s/github/facebook/docusaurus/tree/main/examples/classic', 'https://codesandbox.io/s/github/facebook/docusaurus/tree/main/examples/classic',
// stackblitz: 'https://stackblitz.com/fork/docusaurus', // not updated // Not updated
// stackblitz: 'https://stackblitz.com/github/facebook/docusaurus/tree/main/examples/classic', // slow to load // stackblitz: 'https://stackblitz.com/fork/docusaurus',
stackblitz: 'https://stackblitz.com/github/facebook/docusaurus/tree/starter', // dedicated branch: faster load // Slow to load
// stackblitz: 'https://stackblitz.com/github/facebook/docusaurus/tree/main/examples/classic',
// Dedicated branch: faster load
stackblitz: 'https://stackblitz.com/github/facebook/docusaurus/tree/starter',
}; };
const PlaygroundDocumentationUrl = 'https://docusaurus.io/docs/playground'; const PlaygroundDocumentationUrl = 'https://docusaurus.io/docs/playground';

View file

@ -24,27 +24,26 @@ async function generateTemplateExample(template) {
`generating ${template} template for codesandbox in the examples folder...`, `generating ${template} template for codesandbox in the examples folder...`,
); );
// run the docusaurus script to create the template in the examples folder // Run the docusaurus script to create the template in the examples folder
const command = template.endsWith('-typescript') const command = template.endsWith('-typescript')
? template.replace('-typescript', ' -- --typescript') ? template.replace('-typescript', ' -- --typescript')
: template; : template;
shell.exec( shell.exec(
// /!\ we use the published init script on purpose, // We use the published init script on purpose, because the local init is
// because using the local init script is too early and could generate // too new and could generate upcoming/unavailable config options.
// upcoming/unavailable config options. Remember CodeSandbox templates // Remember CodeSandbox templates will use the published version,
// will use the published version, not the repo version // not the repo version.
`npm init docusaurus@latest examples/${template} ${command}`, `npm init docusaurus@latest examples/${template} ${command}`,
); );
// read the content of the package.json
const templatePackageJson = await fs.readJSON( const templatePackageJson = await fs.readJSON(
`examples/${template}/package.json`, `examples/${template}/package.json`,
); );
// attach the dev script which would be used in code sandbox by default // Attach the dev script which would be used in code sandbox by default
templatePackageJson.scripts.dev = 'docusaurus start'; templatePackageJson.scripts.dev = 'docusaurus start';
// these example projects are not meant to be published to npm // These example projects are not meant to be published to npm
templatePackageJson.private = true; templatePackageJson.private = true;
// Make sure package.json name is not "examples-classic". The package.json // Make sure package.json name is not "examples-classic". The package.json
@ -58,13 +57,12 @@ async function generateTemplateExample(template) {
? 'Docusaurus example project' ? 'Docusaurus example project'
: `Docusaurus example project (${template} template)`; : `Docusaurus example project (${template} template)`;
// rewrite the package.json file with the new edit
await fs.writeFile( await fs.writeFile(
`./examples/${template}/package.json`, `./examples/${template}/package.json`,
`${JSON.stringify(templatePackageJson, null, 2)}\n`, `${JSON.stringify(templatePackageJson, null, 2)}\n`,
); );
// create sandbox.config.json file at the root of template // Create sandbox/stackblitz config file at the root of template
const codeSandboxConfig = { const codeSandboxConfig = {
infiniteLoopProtection: true, infiniteLoopProtection: true,
hardReloadOnChange: true, hardReloadOnChange: true,
@ -162,7 +160,7 @@ console.log(`
# Generate examples start! # Generate examples start!
`); `);
// delete the examples directories if they exists // Delete the examples directories if they exist
console.log(`------- console.log(`-------
## Removing example folders... ## Removing example folders...
`); `);
@ -170,7 +168,7 @@ await fs.rm('./examples/classic', {recursive: true, force: true});
await fs.rm('./examples/classic-typescript', {recursive: true, force: true}); await fs.rm('./examples/classic-typescript', {recursive: true, force: true});
await fs.rm('./examples/facebook', {recursive: true, force: true}); await fs.rm('./examples/facebook', {recursive: true, force: true});
// get the list of all available templates // Get the list of all available templates
console.log(` console.log(`
------- -------
## Generate example folders... ## Generate example folders...
@ -187,7 +185,7 @@ console.log('Committing changes');
shell.exec('git add examples'); shell.exec('git add examples');
shell.exec("git commit -am 'update examples' --allow-empty"); shell.exec("git commit -am 'update examples' --allow-empty");
// update starters // Update starters
console.log(` console.log(`
------- -------
# Updating starter repos and branches ... # Updating starter repos and branches ...

View file

@ -90,7 +90,7 @@ function normalizePaths<T>(value: T): T {
(val) => val.split(homeDirReal).join('<HOME_DIR>'), (val) => val.split(homeDirReal).join('<HOME_DIR>'),
(val) => val.split(homeDir).join('<HOME_DIR>'), (val) => val.split(homeDir).join('<HOME_DIR>'),
// handle HOME_DIR nested inside TEMP_DIR // Handle HOME_DIR nested inside TEMP_DIR
(val) => (val) =>
val val
.split(`<TEMP_DIR>${path.sep + homeRelativeToTemp}`) .split(`<TEMP_DIR>${path.sep + homeRelativeToTemp}`)
@ -98,7 +98,7 @@ function normalizePaths<T>(value: T): T {
(val) => (val) =>
val val
.split(`<TEMP_DIR>${path.sep + homeRelativeToTempReal}`) .split(`<TEMP_DIR>${path.sep + homeRelativeToTempReal}`)
.join('<HOME_DIR>'), // untested .join('<HOME_DIR>'),
(val) => (val) =>
val val
.split(`<TEMP_DIR>${path.sep + homeRealRelativeToTempReal}`) .split(`<TEMP_DIR>${path.sep + homeRealRelativeToTempReal}`)
@ -106,7 +106,7 @@ function normalizePaths<T>(value: T): T {
(val) => (val) =>
val val
.split(`<TEMP_DIR>${path.sep + homeRealRelativeToTemp}`) .split(`<TEMP_DIR>${path.sep + homeRealRelativeToTemp}`)
.join('<HOME_DIR>'), // untested .join('<HOME_DIR>'),
// Replace the Docusaurus version with a stub // Replace the Docusaurus version with a stub
(val) => val.split(version).join('<CURRENT_VERSION>'), (val) => val.split(version).join('<CURRENT_VERSION>'),
@ -134,7 +134,6 @@ function normalizePaths<T>(value: T): T {
} }
function shouldUpdate(value: unknown) { function shouldUpdate(value: unknown) {
// return true if value is different from normalized value
return typeof value === 'string' && normalizePaths(value) !== value; return typeof value === 'string' && normalizePaths(value) !== value;
} }

View file

@ -79,7 +79,7 @@ export default function plugin(options: PluginOptions = {}): Transformer {
visit(root, 'heading', (child: Heading, index, parent) => { visit(root, 'heading', (child: Heading, index, parent) => {
const value = toString(child); const value = toString(child);
// depth:1 headings are titles and not included in the TOC // depth: 1 headings are titles and not included in the TOC
if (parent !== root || !value || child.depth < 2) { if (parent !== root || !value || child.depth < 2) {
return; return;
} }

View file

@ -103,7 +103,7 @@ async function getImageAbsolutePath(
await ensureImageFileExist(imageFilePath, filePath); await ensureImageFileExist(imageFilePath, filePath);
return imageFilePath; return imageFilePath;
} else if (path.isAbsolute(imagePath)) { } else if (path.isAbsolute(imagePath)) {
// absolute paths are expected to exist in the static folder // Absolute paths are expected to exist in the static folder.
const possiblePaths = staticDirs.map((dir) => path.join(dir, imagePath)); const possiblePaths = staticDirs.map((dir) => path.join(dir, imagePath));
const imageFilePath = await findAsyncSequential( const imageFilePath = await findAsyncSequential(
possiblePaths, possiblePaths,
@ -120,7 +120,7 @@ async function getImageAbsolutePath(
} }
return imageFilePath; return imageFilePath;
} }
// relative paths are resolved against the source file's folder // Relative paths are resolved against the source file's folder.
const imageFilePath = path.join( const imageFilePath = path.join(
path.dirname(filePath), path.dirname(filePath),
decodeURIComponent(imagePath), decodeURIComponent(imagePath),

View file

@ -34,7 +34,9 @@ type Context = PluginOptions & {
filePath: string; filePath: string;
}; };
// transform the link node to a jsx link with a require() call /**
* Transforms the link node to a JSX `<a>` element with a `require()` call.
*/
function toAssetRequireNode(node: Link, assetPath: string, filePath: string) { function toAssetRequireNode(node: Link, assetPath: string, filePath: string) {
const jsxNode = node as Literal & Partial<Link>; const jsxNode = node as Literal & Partial<Link>;
let relativeAssetPath = posixPath( let relativeAssetPath = posixPath(
@ -106,7 +108,7 @@ async function getAssetAbsolutePath(
async function processLinkNode(node: Link, context: Context) { async function processLinkNode(node: Link, context: Context) {
if (!node.url) { if (!node.url) {
// try to improve error feedback // Try to improve error feedback
// see https://github.com/facebook/docusaurus/issues/3309#issuecomment-690371675 // see https://github.com/facebook/docusaurus/issues/3309#issuecomment-690371675
const title = node.title || (node.children[0] as Literal)?.value || '?'; const title = node.title || (node.children[0] as Literal)?.value || '?';
const line = node?.position?.start?.line || '?'; const line = node?.position?.start?.line || '?';

View file

@ -207,7 +207,7 @@ export function createConfigFile({
>): VersionTwoConfig { >): VersionTwoConfig {
const siteConfig = v1Config; const siteConfig = v1Config;
const customConfigFields: {[key: string]: unknown} = {}; const customConfigFields: {[key: string]: unknown} = {};
// add fields that are unknown to v2 to customConfigFields // Add fields that are unknown to v2 to customConfigFields
Object.keys(siteConfig).forEach((key) => { Object.keys(siteConfig).forEach((key) => {
const knownFields = [ const knownFields = [
'title', 'title',

View file

@ -152,9 +152,7 @@ declare module '@docusaurus/Link' {
readonly href?: string; readonly href?: string;
readonly autoAddBaseUrl?: boolean; readonly autoAddBaseUrl?: boolean;
/** /** Escape hatch in case broken links check doesn't make sense. */
* escape hatch in case broken links check is annoying for a specific link
*/
readonly 'data-noBrokenLinkCheck'?: boolean; readonly 'data-noBrokenLinkCheck'?: boolean;
}; };
export default function Link(props: Props): JSX.Element; export default function Link(props: Props): JSX.Element;

View file

@ -96,8 +96,8 @@ function filterUnwantedRedirects(
redirects: RedirectMetadata[], redirects: RedirectMetadata[],
pluginContext: PluginContext, pluginContext: PluginContext,
): RedirectMetadata[] { ): RedirectMetadata[] {
// we don't want to create twice the same redirect // We don't want to create the same redirect twice, since that would lead to
// that would lead to writing twice the same html redirection file // writing the same html redirection file twice.
Object.entries(_.groupBy(redirects, (redirect) => redirect.from)).forEach( Object.entries(_.groupBy(redirects, (redirect) => redirect.from)).forEach(
([from, groupedFromRedirects]) => { ([from, groupedFromRedirects]) => {
if (groupedFromRedirects.length > 1) { if (groupedFromRedirects.length > 1) {

View file

@ -158,7 +158,6 @@ describe('blog plugin', () => {
readingTime: 0.015, readingTime: 0.015,
source: path.posix.join( source: path.posix.join(
'@site', '@site',
// pluginPath,
path.posix.join('i18n', 'en', 'docusaurus-plugin-content-blog'), path.posix.join('i18n', 'en', 'docusaurus-plugin-content-blog'),
'2018-12-14-Happy-First-Birthday-Slash.md', '2018-12-14-Happy-First-Birthday-Slash.md',
), ),
@ -421,7 +420,7 @@ describe('blog plugin', () => {
const blogPosts = await getBlogPosts(siteDir); const blogPosts = await getBlogPosts(siteDir);
const noDateSource = path.posix.join('@site', PluginPath, 'no date.md'); const noDateSource = path.posix.join('@site', PluginPath, 'no date.md');
const noDateSourceFile = path.posix.join(siteDir, PluginPath, 'no date.md'); const noDateSourceFile = path.posix.join(siteDir, PluginPath, 'no date.md');
// we know the file exist and we know we have git // We know the file exists and we know we have git
const result = getFileCommitDate(noDateSourceFile, {age: 'oldest'}); const result = getFileCommitDate(noDateSourceFile, {age: 'oldest'});
const noDateSourceTime = result.date; const noDateSourceTime = result.date;
const formattedDate = Intl.DateTimeFormat('en', { const formattedDate = Intl.DateTimeFormat('en', {

View file

@ -13,7 +13,7 @@ function testValidate(options: Options) {
return validateOptions({validate: normalizePluginOptions, options}); return validateOptions({validate: normalizePluginOptions, options});
} }
// the type of remark/rehype plugins can be either function, object or array // The type of remark/rehype plugins can be either function, object or array
const markdownPluginsFunctionStub = () => {}; const markdownPluginsFunctionStub = () => {};
const markdownPluginsObjectStub = {}; const markdownPluginsObjectStub = {};

View file

@ -218,7 +218,7 @@ export default async function pluginContentBlog(
routeBasePath, routeBasePath,
archiveBasePath, archiveBasePath,
]); ]);
// creates a blog archive route // Create a blog archive route
const archiveProp = await createData( const archiveProp = await createData(
`${docuHash(archiveUrl)}.json`, `${docuHash(archiveUrl)}.json`,
JSON.stringify({blogPosts}, null, 2), JSON.stringify({blogPosts}, null, 2),

View file

@ -111,7 +111,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
.default(DEFAULT_OPTIONS.feedOptions.type), .default(DEFAULT_OPTIONS.feedOptions.type),
title: Joi.string().allow(''), title: Joi.string().allow(''),
description: Joi.string().allow(''), description: Joi.string().allow(''),
// only add default value when user actually wants a feed (type is not null) // Only add default value when user actually wants a feed (type is not null)
copyright: Joi.when('type', { copyright: Joi.when('type', {
is: Joi.any().valid(null), is: Joi.any().valid(null),
then: Joi.string().optional(), then: Joi.string().optional(),

View file

@ -849,7 +849,6 @@ describe('versioned site', () => {
const {siteDir, context, options, version100} = await loadSite({ const {siteDir, context, options, version100} = await loadSite({
options: { options: {
editUrl: 'https://github.com/facebook/docusaurus/edit/main/website', editUrl: 'https://github.com/facebook/docusaurus/edit/main/website',
// editCurrentVersion: true,
}, },
}); });

View file

@ -68,8 +68,8 @@ const createFakeActions = (contentDir: string) => {
}, },
}; };
// query by prefix, because files have a hash at the end // Query by prefix, because files have a hash at the end so it's not
// so it's not convenient to query by full filename // convenient to query by full filename
const getCreatedDataByPrefix = (prefix: string) => { const getCreatedDataByPrefix = (prefix: string) => {
const entry = Object.entries(dataContainer).find(([key]) => const entry = Object.entries(dataContainer).find(([key]) =>
key.startsWith(prefix), key.startsWith(prefix),

View file

@ -23,7 +23,7 @@ const IgnoredNumberPrefixPatterns = [
'00abc01-My Doc', '00abc01-My Doc',
'My 001- Doc', 'My 001- Doc',
'My -001 Doc', 'My -001 Doc',
// ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640 // Ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
'2021-01-31 - Doc', '2021-01-31 - Doc',
'31-01-2021 - Doc', '31-01-2021 - Doc',
'2021_01_31 - Doc', '2021_01_31 - Doc',
@ -36,7 +36,7 @@ const IgnoredNumberPrefixPatterns = [
'01-2021 - Doc', '01-2021 - Doc',
'01_2021 - Doc', '01_2021 - Doc',
'01.2021 - Doc', '01.2021 - Doc',
// date patterns without suffix // Date patterns without suffix
'2021-01-31', '2021-01-31',
'2021-01', '2021-01',
'21-01-31', '21-01-31',
@ -49,7 +49,7 @@ const IgnoredNumberPrefixPatterns = [
'01', '01',
'2021', '2021',
'01', '01',
// ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653 // Ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
'8.0', '8.0',
'8.0.0', '8.0.0',
'14.2.16', '14.2.16',

View file

@ -15,7 +15,7 @@ import {
import {GlobExcludeDefault} from '@docusaurus/utils'; import {GlobExcludeDefault} from '@docusaurus/utils';
import type {Options} from '@docusaurus/plugin-content-docs'; import type {Options} from '@docusaurus/plugin-content-docs';
// the type of remark/rehype plugins is function // The type of remark/rehype plugins can be function/object
const markdownPluginsFunctionStub = () => {}; const markdownPluginsFunctionStub = () => {};
const markdownPluginsObjectStub = {}; const markdownPluginsObjectStub = {};

View file

@ -57,7 +57,7 @@ describe('toTagDocListProp', () => {
count: 2, count: 2,
label: tag.label, label: tag.label,
permalink: tag.permalink, permalink: tag.permalink,
items: [doc3, doc1], // docs sorted by title, ignore "id5" absence items: [doc3, doc1], // Docs sorted by title, ignore "id5" absence
}); });
}); });
}); });

View file

@ -226,7 +226,7 @@ describe('docsClientUtils', () => {
], ],
}; };
// shuffle, because order shouldn't matter // Shuffle, because order shouldn't matter
const versions: GlobalVersion[] = _.shuffle([ const versions: GlobalVersion[] = _.shuffle([
versionNext, versionNext,
version2, version2,
@ -355,7 +355,7 @@ describe('docsClientUtils', () => {
], ],
}; };
// shuffle, because order shouldn't matter // Shuffle, because order shouldn't matter
const versions: GlobalVersion[] = _.shuffle([ const versions: GlobalVersion[] = _.shuffle([
versionNext, versionNext,
version2, version2,
@ -395,7 +395,7 @@ describe('docsClientUtils', () => {
latestVersionSuggestion: version2, latestVersionSuggestion: version2,
}); });
expect(getDocVersionSuggestions(data, '/docs/version1/doc2')).toEqual({ expect(getDocVersionSuggestions(data, '/docs/version1/doc2')).toEqual({
latestDocSuggestion: undefined, // because /docs/version1/doc2 does not exist latestDocSuggestion: undefined, // Because /docs/version1/doc2 does not exist
latestVersionSuggestion: version2, latestVersionSuggestion: version2,
}); });
}); });

View file

@ -156,15 +156,13 @@ function doProcessDocMetadata({
parse_number_prefixes: parseNumberPrefixes = true, parse_number_prefixes: parseNumberPrefixes = true,
} = frontMatter; } = frontMatter;
// ex: api/plugins/myDoc -> myDoc // E.g. api/plugins/myDoc -> myDoc; myDoc -> myDoc
// ex: myDoc -> myDoc
const sourceFileNameWithoutExtension = path.basename( const sourceFileNameWithoutExtension = path.basename(
source, source,
path.extname(source), path.extname(source),
); );
// ex: api/plugins/myDoc -> api/plugins // E.g. api/plugins/myDoc -> api/plugins; myDoc -> .
// ex: myDoc -> .
const sourceDirName = path.dirname(source); const sourceDirName = path.dirname(source);
const {filename: unprefixedFileName, numberPrefix} = parseNumberPrefixes const {filename: unprefixedFileName, numberPrefix} = parseNumberPrefixes
@ -347,7 +345,7 @@ export function addDocNavigation(
} }
const docsWithNavigation = docsBase.map(addNavData); const docsWithNavigation = docsBase.map(addNavData);
// sort to ensure consistent output for tests // Sort to ensure consistent output for tests
docsWithNavigation.sort((a, b) => a.id.localeCompare(b.id)); docsWithNavigation.sort((a, b) => a.id.localeCompare(b.id));
return docsWithNavigation; return docsWithNavigation;
} }
@ -434,7 +432,7 @@ export function getDocIds(doc: DocMetadataBase): [string, string] {
return [doc.unversionedId, doc.id]; return [doc.unversionedId, doc.id];
} }
// docs are indexed by both versioned and unversioned ids at the same time // Docs are indexed by both versioned and unversioned ids at the same time
// TODO legacy retro-compatibility due to old versioned sidebars using // TODO legacy retro-compatibility due to old versioned sidebars using
// versioned doc ids ("id" should be removed & "versionedId" should be renamed // versioned doc ids ("id" should be removed & "versionedId" should be renamed
// to "id") // to "id")

View file

@ -20,12 +20,14 @@ import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
// We use default values in code instead // We use default values in code instead
const DocFrontMatterSchema = Joi.object<DocFrontMatter>({ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
id: Joi.string(), id: Joi.string(),
title: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
title: Joi.string().allow(''),
hide_title: Joi.boolean(), hide_title: Joi.boolean(),
hide_table_of_contents: Joi.boolean(), hide_table_of_contents: Joi.boolean(),
keywords: Joi.array().items(Joi.string().required()), keywords: Joi.array().items(Joi.string().required()),
image: URISchema, image: URISchema,
description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
description: Joi.string().allow(''),
slug: Joi.string(), slug: Joi.string(),
sidebar_label: Joi.string(), sidebar_label: Joi.string(),
sidebar_position: Joi.number(), sidebar_position: Joi.number(),

View file

@ -19,7 +19,7 @@ declare module '@docusaurus/plugin-content-docs' {
* Custom callback for parsing number prefixes from file/folder names. * Custom callback for parsing number prefixes from file/folder names.
*/ */
export type NumberPrefixParser = (filename: string) => { export type NumberPrefixParser = (filename: string) => {
/** file name without number prefix, without any other modification. */ /** File name without number prefix, without any other modification. */
filename: string; filename: string;
/** The number prefix. Can be float, integer, negative, or anything. */ /** The number prefix. Can be float, integer, negative, or anything. */
numberPrefix?: number; numberPrefix?: number;
@ -621,9 +621,9 @@ declare module '@docusaurus/plugin-content-docs/client' {
breadcrumbs: boolean; breadcrumbs: boolean;
}; };
export type DocVersionSuggestions = { export type DocVersionSuggestions = {
/** suggest the latest version */ /** Suggest the latest version */
latestVersionSuggestion: GlobalVersion; latestVersionSuggestion: GlobalVersion;
/** suggest the same doc, in latest version (if exist) */ /** Suggest the same doc, in latest version (if one exists) */
latestDocSuggestion?: GlobalDoc; latestDocSuggestion?: GlobalDoc;
}; };

View file

@ -139,11 +139,9 @@ export async function createVersionRoutes({
actions.addRoute({ actions.addRoute({
path: version.path, path: version.path,
// allow matching /docs/* as well // Allow matching /docs/* since this is the wrapping route
exact: false, exact: false,
// main docs component (DocPage)
component: docLayoutComponent, component: docLayoutComponent,
// sub-routes for each doc
routes: await createVersionSubRoutes(), routes: await createVersionSubRoutes(),
modules: { modules: {
versionMetadata: aliasedSource(versionMetadataPropPath), versionMetadata: aliasedSource(versionMetadataPropPath),

View file

@ -76,9 +76,9 @@ Available doc IDs:
return ( return (
// Doc at the root of the autogenerated sidebar dir // Doc at the root of the autogenerated sidebar dir
doc.sourceDirName === autogenDir || doc.sourceDirName === autogenDir ||
// autogen dir is . and doc is in subfolder // Autogen dir is . and doc is in subfolder
autogenDir === '.' || autogenDir === '.' ||
// autogen dir is not . and doc is in subfolder // Autogen dir is not . and doc is in subfolder
// "api/myDoc" startsWith "api/" (note "api2/myDoc" is not included) // "api/myDoc" startsWith "api/" (note "api2/myDoc" is not included)
doc.sourceDirName.startsWith(addTrailingSlash(autogenDir)) doc.sourceDirName.startsWith(addTrailingSlash(autogenDir))
); );

View file

@ -22,7 +22,7 @@ function normalizeCategoryLink(
params: SidebarProcessorParams, params: SidebarProcessorParams,
): SidebarItemCategoryLink | undefined { ): SidebarItemCategoryLink | undefined {
if (category.link?.type === 'generated-index') { if (category.link?.type === 'generated-index') {
// default slug logic can be improved // Default slug logic can be improved
const getDefaultSlug = () => const getDefaultSlug = () =>
`/category/${params.categoryLabelSlugger.slug(category.label)}`; `/category/${params.categoryLabelSlugger.slug(category.label)}`;
const slug = category.link.slug ?? getDefaultSlug(); const slug = category.link.slug ?? getDefaultSlug();

View file

@ -180,7 +180,6 @@ export type PropSidebarItemCategory = Expand<
} }
>; >;
// we may want to use a union type in props instead of this generic link?
export type PropSidebarItemLink = SidebarItemLink & { export type PropSidebarItemLink = SidebarItemLink & {
docId?: string; docId?: string;
}; };
@ -245,7 +244,7 @@ export type SidebarItemsGeneratorArgs = {
/** The default category index matcher which you can override. */ /** The default category index matcher which you can override. */
isCategoryIndex: CategoryIndexMatcher; isCategoryIndex: CategoryIndexMatcher;
/** /**
* key is the path relative to the doc content directory, value is the * Key is the path relative to the doc content directory, value is the
* category metadata file's content. * category metadata file's content.
*/ */
categoriesMetadata: {[filePath: string]: CategoryMetadataFile}; categoriesMetadata: {[filePath: string]: CategoryMetadataFile};

View file

@ -53,50 +53,6 @@ function getNormalizedSidebarName({
return rest.join('/'); return rest.join('/');
} }
/*
// Do we need to translate doc metadata?
// It seems translating front matter labels is good enough
function getDocTranslations(doc: DocMetadata): TranslationFileContent {
return {
[`${doc.unversionedId}.title`]: {
message: doc.title,
description: `The title for doc with id=${doc.unversionedId}`,
},
...(doc.sidebar_label
? {
[`${doc.unversionedId}.sidebar_label`]: {
message: doc.sidebar_label,
description:
`The sidebar label for doc with id=${doc.unversionedId}`,
},
}
: undefined),
};
}
function translateDoc(
doc: DocMetadata,
docsTranslations: TranslationFileContent,
): DocMetadata {
return {
...doc,
title: docsTranslations[`${doc.unversionedId}.title`]?.message ?? doc.title,
sidebar_label:
docsTranslations[`${doc.unversionedId}.sidebar_label`]?.message ??
doc.sidebar_label,
};
}
function getDocsTranslations(version: LoadedVersion): TranslationFileContent {
return mergeTranslations(version.docs.map(getDocTranslations));
}
function translateDocs(
docs: DocMetadata[],
docsTranslations: TranslationFileContent,
): DocMetadata[] {
return docs.map((doc) => translateDoc(doc, docsTranslations));
}
*/
function getSidebarTranslationFileContent( function getSidebarTranslationFileContent(
sidebar: Sidebar, sidebar: Sidebar,
sidebarName: string, sidebarName: string,
@ -252,17 +208,10 @@ function getVersionTranslationFiles(version: LoadedVersion): TranslationFile[] {
const sidebarsTranslations: TranslationFileContent = const sidebarsTranslations: TranslationFileContent =
getSidebarsTranslations(version); getSidebarsTranslations(version);
// const docsTranslations: TranslationFileContent =
// getDocsTranslations(version);
return [ return [
{ {
path: getVersionFileName(version.versionName), path: getVersionFileName(version.versionName),
content: mergeTranslations([ content: mergeTranslations([versionTranslations, sidebarsTranslations]),
versionTranslations,
sidebarsTranslations,
// docsTranslations,
]),
}, },
]; ];
} }
@ -276,7 +225,6 @@ function translateVersion(
...version, ...version,
label: versionTranslations['version.label']?.message ?? version.label, label: versionTranslations['version.label']?.message ?? version.label,
sidebars: translateSidebars(version, versionTranslations), sidebars: translateSidebars(version, versionTranslations),
// docs: translateDocs(version.docs, versionTranslations),
}; };
} }

View file

@ -30,7 +30,7 @@ export type SourceToPermalink = {
}; };
export type VersionTag = Tag & { export type VersionTag = Tag & {
/** all doc ids having this tag. */ /** All doc ids having this tag. */
docIds: string[]; docIds: string[];
}; };
export type VersionTags = { export type VersionTags = {

View file

@ -38,7 +38,7 @@ function PluginContent({
<h3>{pluginName}</h3> <h3>{pluginName}</h3>
<div> <div>
{Object.entries(pluginContent) {Object.entries(pluginContent)
// filter plugin instances with no content // Filter plugin instances with no content
.filter(([, pluginInstanceContent]) => !!pluginInstanceContent) .filter(([, pluginInstanceContent]) => !!pluginInstanceContent)
.map(([pluginId, pluginInstanceContent]) => ( .map(([pluginId, pluginInstanceContent]) => (
<PluginInstanceContent <PluginInstanceContent
@ -58,7 +58,7 @@ export default function DebugContent({allContent}: Props): JSX.Element {
<h2>Plugin content</h2> <h2>Plugin content</h2>
<div> <div>
{Object.entries(allContent) {Object.entries(allContent)
// filter plugins with no content // Filter plugins with no content
.filter(([, pluginContent]) => .filter(([, pluginContent]) =>
Object.values(pluginContent).some( Object.values(pluginContent).some(
(instanceContent) => !!instanceContent, (instanceContent) => !!instanceContent,

View file

@ -10,7 +10,7 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
import type {Props} from '@theme/DebugJsonView'; import type {Props} from '@theme/DebugJsonView';
import type {ReactJsonViewProps} from 'react-json-view'; import type {ReactJsonViewProps} from 'react-json-view';
// avoids "react-json-view" to display "root" // Avoids "react-json-view" to display "root"
const RootName = null; const RootName = null;
// Seems ReactJson does not work with SSR // Seems ReactJson does not work with SSR

View file

@ -59,7 +59,8 @@ export default function pluginIdealImage(
{ {
loader: require.resolve('@docusaurus/responsive-loader'), loader: require.resolve('@docusaurus/responsive-loader'),
options: { options: {
emitFile: !isServer, // don't emit for server-side rendering // Don't emit for server-side rendering
emitFile: !isServer,
// eslint-disable-next-line global-require // eslint-disable-next-line global-require
adapter: require('@docusaurus/responsive-loader/sharp'), adapter: require('@docusaurus/responsive-loader/sharp'),
name: 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]', name: 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]',

View file

@ -40,7 +40,7 @@ function getMessage(icon: IconKey, state: State) {
description: 'When the full-scale image is loading', description: 'When the full-scale image is loading',
}); });
case 'load': { case 'load': {
// we can show `alt` here // We can show `alt` here
const {pickedSrc} = state; const {pickedSrc} = state;
const {size} = pickedSrc; const {size} = pickedSrc;
const sizeMessage = size ? ` (${bytesToSize(size)})` : ''; const sizeMessage = size ? ` (${bytesToSize(size)})` : '';

View file

@ -150,7 +150,7 @@ export default function pluginPWA(
optimization: { optimization: {
splitChunks: false, splitChunks: false,
minimize: !debug, minimize: !debug,
// see https://developers.google.com/web/tools/workbox/guides/using-bundlers#webpack // See https://developers.google.com/web/tools/workbox/guides/using-bundlers#webpack
minimizer: debug minimizer: debug
? [] ? []
: [ : [
@ -161,7 +161,8 @@ export default function pluginPWA(
}, },
plugins: [ plugins: [
new webpack.EnvironmentPlugin({ new webpack.EnvironmentPlugin({
PWA_SW_CUSTOM: swCustom || '', // fallback value required with Webpack 5 // Fallback value required with Webpack 5
PWA_SW_CUSTOM: swCustom || '',
}), }),
new LogPlugin({ new LogPlugin({
name: 'Service Worker', name: 'Service Worker',
@ -192,7 +193,7 @@ export default function pluginPWA(
// @ts-expect-error: internal API? // @ts-expect-error: internal API?
...(injectManifest.globPatterns ?? []), ...(injectManifest.globPatterns ?? []),
], ],
// those attributes are not overrideable // Those attributes are not overrideable
swDest, swDest,
swSrc: swDest, swSrc: swDest,
globDirectory: props.outDir, globDirectory: props.outDir,

View file

@ -81,6 +81,8 @@ declare module '@docusaurus/plugin-pwa' {
*/ */
swRegister: string | false; swRegister: string | false;
}; };
export type Options = Partial<PluginOptions>;
} }
declare module '@theme/PwaReloadPopup' { declare module '@theme/PwaReloadPopup' {

View file

@ -16,7 +16,7 @@ const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES =
const PWA_DEBUG = process.env.PWA_DEBUG; const PWA_DEBUG = process.env.PWA_DEBUG;
/* eslint-enable prefer-destructuring */ /* eslint-enable prefer-destructuring */
const debug = PWA_DEBUG; // shortcut const debug = PWA_DEBUG; // Shortcut
const MAX_MOBILE_WIDTH = 940; const MAX_MOBILE_WIDTH = 940;
@ -101,7 +101,7 @@ async function getActiveStrategies() {
return isActive ? strategyName : undefined; return isActive ? strategyName : undefined;
}), }),
); );
return activeStrategies.filter(Boolean); // remove undefined values return activeStrategies.filter(Boolean);
} }
async function isOfflineModeEnabled() { async function isOfflineModeEnabled() {

View file

@ -18,7 +18,7 @@ function parseSwParams() {
return params; return params;
} }
// doc advises against dynamic imports in SW // Doc advises against dynamic imports in SW
// https://developers.google.com/web/tools/workbox/guides/using-bundlers#code_splitting_and_dynamic_imports // https://developers.google.com/web/tools/workbox/guides/using-bundlers#code_splitting_and_dynamic_imports
// https://twitter.com/sebastienlorber/status/1280155204575518720 // https://twitter.com/sebastienlorber/status/1280155204575518720
// but looks it's working fine as it's inlined by webpack, need to double check // but looks it's working fine as it's inlined by webpack, need to double check
@ -73,7 +73,8 @@ function getPossibleURLs(url) {
// eslint-disable-next-line no-underscore-dangle // eslint-disable-next-line no-underscore-dangle
const precacheManifest = self.__WB_MANIFEST; const precacheManifest = self.__WB_MANIFEST;
const controller = new PrecacheController({ const controller = new PrecacheController({
fallbackToNetwork: true, // safer to turn this true? // Safer to turn this true?
fallbackToNetwork: true,
}); });
if (params.offlineMode) { if (params.offlineMode) {

View file

@ -6,7 +6,7 @@
*/ */
import remark from 'remark'; import remark from 'remark';
// import from the transpiled lib because Babel can't transpile `export =` // Import from the transpiled lib because Babel can't transpile `export =`
// TODO change to `../index` after migrating to ESM // TODO change to `../index` after migrating to ESM
import npm2yarn from '../../lib/index'; import npm2yarn from '../../lib/index';
import vfile from 'to-vfile'; import vfile from 'to-vfile';

View file

@ -125,7 +125,7 @@ describe('getTranslationFiles and translateThemeConfig isomorphism', () => {
verifyIsomorphism(ThemeConfigSampleSimpleFooter); verifyIsomorphism(ThemeConfigSampleSimpleFooter);
}); });
// undefined footer should not make the translation code crash // Undefined footer should not make the translation code crash
// See https://github.com/facebook/docusaurus/issues/3936 // See https://github.com/facebook/docusaurus/issues/3936
it('is verified for sample without footer', () => { it('is verified for sample without footer', () => {
verifyIsomorphism({...ThemeConfigSample, footer: undefined}); verifyIsomorphism({...ThemeConfigSample, footer: undefined});

View file

@ -30,7 +30,7 @@ export default function getSwizzleConfig(): SwizzleConfig {
}, },
DocSidebar: { DocSidebar: {
actions: { actions: {
eject: 'unsafe', // too much technical code in sidebar, not very safe atm eject: 'unsafe', // Too much technical code in sidebar, not very safe atm
wrap: 'safe', wrap: 'safe',
}, },
description: 'The sidebar component on docs pages', description: 'The sidebar component on docs pages',
@ -234,7 +234,7 @@ export default function getSwizzleConfig(): SwizzleConfig {
'prism-include-languages': { 'prism-include-languages': {
actions: { actions: {
eject: 'safe', eject: 'safe',
wrap: 'forbidden', // not a component! wrap: 'forbidden', // Not a component!
}, },
description: description:
'The Prism languages to include for code block syntax highlighting. Meant to be ejected.', 'The Prism languages to include for code block syntax highlighting. Meant to be ejected.',

View file

@ -1022,8 +1022,8 @@ declare module '@theme/TOCItems' {
declare module '@theme/TOC' { declare module '@theme/TOC' {
import type {TOCItem} from '@docusaurus/types'; import type {TOCItem} from '@docusaurus/types';
// minHeadingLevel only exists as a per-doc option, and won't have a default // `minHeadingLevel` only comes from doc/post front matter, and won't have a
// set by Joi. See TOC, TOCInline, TOCCollapsible for examples // default set by Joi. See TOC, TOCInline, TOCCollapsible for examples.
export interface Props { export interface Props {
readonly toc: readonly TOCItem[]; readonly toc: readonly TOCItem[];
readonly minHeadingLevel?: number; readonly minHeadingLevel?: number;

View file

@ -111,8 +111,8 @@ export default function DocSidebarItemCategory({
const isCurrentPage = isSamePath(href, activePath); const isCurrentPage = isSamePath(href, activePath);
const {collapsed, setCollapsed} = useCollapsible({ const {collapsed, setCollapsed} = useCollapsible({
// active categories are always initialized as expanded // Active categories are always initialized as expanded. The default
// the default (item.collapsed) is only used for non-active categories // (`item.collapsed`) is only used for non-active categories.
initialState: () => { initialState: () => {
if (!collapsible) { if (!collapsible) {
return false; return false;

View file

@ -17,12 +17,7 @@ function DocSidebarItems({items, ...props}: Props): JSX.Element {
return ( return (
<DocSidebarItemsExpandedStateProvider> <DocSidebarItemsExpandedStateProvider>
{items.map((item, index) => ( {items.map((item, index) => (
<DocSidebarItem <DocSidebarItem key={index} item={item} index={index} {...props} />
key={index} // sidebar is static, the index does not change
item={item}
index={index}
{...props}
/>
))} ))}
</DocSidebarItemsExpandedStateProvider> </DocSidebarItemsExpandedStateProvider>
); );

View file

@ -136,8 +136,8 @@ function DocVersionBannerEnabled({
const {latestDocSuggestion, latestVersionSuggestion} = const {latestDocSuggestion, latestVersionSuggestion} =
useDocVersionSuggestions(pluginId); useDocVersionSuggestions(pluginId);
// try to link to same doc in latest version (not always possible) // Try to link to same doc in latest version (not always possible), falling
// fallback to main doc of latest version // back to main doc of latest version
const latestVersionSuggestedDoc = const latestVersionSuggestedDoc =
latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion); latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion);

View file

@ -13,13 +13,13 @@ import {useThemeConfig} from '@docusaurus/theme-common';
import styles from './styles.module.css'; import styles from './styles.module.css';
function AnchorHeading({as: As, id, ...props}: Props) { export default function Heading({as: As, id, ...props}: Props): JSX.Element {
const { const {
navbar: {hideOnScroll}, navbar: {hideOnScroll},
} = useThemeConfig(); } = useThemeConfig();
// H1 headings do not need an id because they don't appear in the TOC.
if (!id) { if (As === 'h1' || !id) {
return <As {...props} />; return <As {...props} id={undefined} />;
} }
return ( return (
@ -46,17 +46,3 @@ function AnchorHeading({as: As, id, ...props}: Props) {
</As> </As>
); );
} }
export default function Heading({as, ...props}: Props): JSX.Element {
if (as === 'h1') {
return (
<h1
{...props}
id={undefined} // h1 headings do not need an id because they don't appear in the TOC
>
{props.children}
</h1>
);
}
return <AnchorHeading as={as} {...props} />;
}

View file

@ -27,7 +27,7 @@ export default function Layout(props: Props): JSX.Element {
children, children,
noFooter, noFooter,
wrapperClassName, wrapperClassName,
// not really layout-related, but kept for convenience/retro-compatibility // Not really layout-related, but kept for convenience/retro-compatibility
title, title,
description, description,
} = props; } = props;

View file

@ -109,16 +109,16 @@ export default function SiteMetadata(): JSX.Element {
<SearchMetadata tag={DEFAULT_SEARCH_TAG} locale={currentLocale} /> <SearchMetadata tag={DEFAULT_SEARCH_TAG} locale={currentLocale} />
<Head {/*
// it's important to have an additional <Head> element here, It's important to have an additional <Head> element here, as it allows
// as it allows react-helmet to override values set in previous <Head> react-helmet to override default metadata values set in previous <Head>
// ie we can override default metadata such as "twitter:card" like "twitter:card". In same Head, the same meta would appear twice
// In same Head, the same meta would appear twice instead of overriding instead of overriding.
// See react-helmet doc */}
> <Head>
{/* Yes, "metadatum" is the grammatically correct term */} {/* Yes, "metadatum" is the grammatically correct term */}
{metadata.map((metadatum, i) => ( {metadata.map((metadatum, i) => (
<meta key={`metadata_${i}`} {...metadatum} /> <meta key={i} {...metadatum} />
))} ))}
</Head> </Head>
</> </>

View file

@ -100,7 +100,7 @@ const HtmlNavbarItemSchema = Joi.object({
}); });
const itemWithType = (type: string | undefined) => { const itemWithType = (type: string | undefined) => {
// because equal(undefined) is not supported :/ // Because equal(undefined) is not supported :/
const typeSchema = type const typeSchema = type
? Joi.string().required().equal(type) ? Joi.string().required().equal(type)
: Joi.string().forbidden(); : Joi.string().forbidden();
@ -241,7 +241,6 @@ const ColorModeSchema = Joi.object({
}), }),
}).default(DEFAULT_COLOR_MODE_CONFIG); }).default(DEFAULT_COLOR_MODE_CONFIG);
// schema can probably be improved
const HtmlMetadataSchema = Joi.object({ const HtmlMetadataSchema = Joi.object({
id: Joi.string(), id: Joi.string(),
name: Joi.string(), name: Joi.string(),

View file

@ -224,6 +224,8 @@ function CollapsibleBase({
function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) { function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
const [mounted, setMounted] = useState(!collapsed); const [mounted, setMounted] = useState(!collapsed);
// Updated in effect so that first expansion transition can work
const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
useLayoutEffect(() => { useLayoutEffect(() => {
if (!collapsed) { if (!collapsed) {
@ -231,8 +233,6 @@ function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
} }
}, [collapsed]); }, [collapsed]);
// lazyCollapsed updated in effect so that first expansion transition can work
const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
useLayoutEffect(() => { useLayoutEffect(() => {
if (mounted) { if (mounted) {
setLazyCollapsed(collapsed); setLazyCollapsed(collapsed);

View file

@ -87,7 +87,8 @@ export function Details({
setOpen(true); setOpen(true);
} else { } else {
setCollapsed(true); setCollapsed(true);
// setOpen(false); // Don't do this, it breaks close animation! // Don't do this, it breaks close animation!
// setOpen(false);
} }
}}> }}>
{summary} {summary}

View file

@ -72,7 +72,7 @@ function useContextValue(): ContextValue {
let viewedId = IdStorage.get(); let viewedId = IdStorage.get();
// retrocompatibility due to spelling mistake of default id // Retrocompatibility due to spelling mistake of default id
// see https://github.com/facebook/docusaurus/issues/3338 // see https://github.com/facebook/docusaurus/issues/3338
// cSpell:ignore annoucement // cSpell:ignore annoucement
if (viewedId === 'annoucement-bar') { if (viewedId === 'annoucement-bar') {

View file

@ -58,9 +58,9 @@ function useContextValue(): ContextValue {
useHistoryPopHandler(() => { useHistoryPopHandler(() => {
if (shown) { if (shown) {
setShown(false); setShown(false);
// Should we prevent the navigation here? // Prevent pop navigation; seems desirable enough
// See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846 // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846
return false; // prevent pop navigation return false;
} }
return undefined; return undefined;
}); });

View file

@ -81,8 +81,8 @@ function getActiveAnchor(
// https://github.com/facebook/docusaurus/issues/5318 // https://github.com/facebook/docusaurus/issues/5318
return anchors[anchors.indexOf(nextVisibleAnchor) - 1] ?? null; return anchors[anchors.indexOf(nextVisibleAnchor) - 1] ?? null;
} }
// no anchor under viewport top? (ie we are at the bottom of the page) // No anchor under viewport top (i.e. we are at the bottom of the page),
// => highlight the last anchor found // highlight the last anchor found
return anchors[anchors.length - 1] ?? null; return anchors[anchors.length - 1] ?? null;
} }
@ -140,7 +140,7 @@ export function useTOCHighlight(config: TOCHighlightConfig | undefined): void {
useEffect(() => { useEffect(() => {
if (!config) { if (!config) {
// no-op, highlighting is disabled // No-op, highlighting is disabled
return () => {}; return () => {};
} }

View file

@ -30,14 +30,14 @@ const magicCommentDirectives = [
]; ];
function getCommentPattern(languages: CommentType[]) { function getCommentPattern(languages: CommentType[]) {
// to be more reliable, the opening and closing comment must match // To be more reliable, the opening and closing comment must match
const commentPattern = languages const commentPattern = languages
.map((lang) => { .map((lang) => {
const {start, end} = commentPatterns[lang]; const {start, end} = commentPatterns[lang];
return `(?:${start}\\s*(${magicCommentDirectives.join('|')})\\s*${end})`; return `(?:${start}\\s*(${magicCommentDirectives.join('|')})\\s*${end})`;
}) })
.join('|'); .join('|');
// white space is allowed, but otherwise it should be on it's own line // White space is allowed, but otherwise it should be on it's own line
return new RegExp(`^\\s*(?:${commentPattern})\\s*$`); return new RegExp(`^\\s*(?:${commentPattern})\\s*$`);
} }
@ -70,7 +70,7 @@ function getAllMagicCommentDirectiveStyles(lang: string) {
return getCommentPattern(['html', 'jsx', 'bash']); return getCommentPattern(['html', 'jsx', 'bash']);
default: default:
// all comment types // All comment types
return getCommentPattern(Object.keys(commentPatterns) as CommentType[]); return getCommentPattern(Object.keys(commentPatterns) as CommentType[]);
} }
} }
@ -139,16 +139,15 @@ export function parseLines(
return {highlightLines: [], code}; return {highlightLines: [], code};
} }
const directiveRegex = getAllMagicCommentDirectiveStyles(language); const directiveRegex = getAllMagicCommentDirectiveStyles(language);
// go through line by line // Go through line by line
const lines = code.split('\n'); const lines = code.split('\n');
let highlightBlockStart: number; let highlightBlockStart: number;
let highlightRange = ''; let highlightRange = '';
// loop through lines
for (let lineNumber = 0; lineNumber < lines.length; ) { for (let lineNumber = 0; lineNumber < lines.length; ) {
const line = lines[lineNumber]!; const line = lines[lineNumber]!;
const match = line.match(directiveRegex); const match = line.match(directiveRegex);
if (!match) { if (!match) {
// lines without directives are unchanged // Lines without directives are unchanged
lineNumber += 1; lineNumber += 1;
continue; continue;
} }

View file

@ -92,13 +92,8 @@ export function findFirstCategoryLink(
if (categoryLink) { if (categoryLink) {
return categoryLink; return categoryLink;
} }
} else if (subItem.type === 'html') {
// skip
} else {
throw new Error(
`Unexpected category item type for ${JSON.stringify(subItem)}`,
);
} }
// Could be "html" items
} }
return undefined; return undefined;
} }
@ -271,7 +266,7 @@ export function useLayoutDoc(
const isDraft = versions const isDraft = versions
.flatMap((version) => version.draftIds) .flatMap((version) => version.draftIds)
.includes(docId); .includes(docId);
// drafts should be silently filtered instead of throwing // Drafts should be silently filtered instead of throwing
if (isDraft) { if (isDraft) {
return null; return null;
} }

View file

@ -30,11 +30,11 @@ function treeifyTOC(flatTOC: readonly TOCItem[]): TOCTreeNode[] {
const prevIndexForLevel = Array(7).fill(-1); const prevIndexForLevel = Array(7).fill(-1);
headings.forEach((curr, currIndex) => { headings.forEach((curr, currIndex) => {
// take the last seen index for each ancestor level. the highest // Take the last seen index for each ancestor level. the highest index will
// index will be the direct ancestor of the current heading. // be the direct ancestor of the current heading.
const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level); const ancestorLevelIndexes = prevIndexForLevel.slice(2, curr.level);
curr.parentIndex = Math.max(...ancestorLevelIndexes); curr.parentIndex = Math.max(...ancestorLevelIndexes);
// mark that curr.level was last seen at the current index // Mark that curr.level was last seen at the current index.
prevIndexForLevel[curr.level] = currIndex; prevIndexForLevel[curr.level] = currIndex;
}); });

View file

@ -11,7 +11,7 @@ import {useContextualSearchFilters} from '@docusaurus/theme-common';
export function useAlgoliaContextualFacetFilters(): [string, string[]] { export function useAlgoliaContextualFacetFilters(): [string, string[]] {
const {locale, tags} = useContextualSearchFilters(); const {locale, tags} = useContextualSearchFilters();
// seems safe to convert locale->language, see AlgoliaSearchMetadata comment // Seems safe to convert locale->language, see AlgoliaSearchMetadata comment
const languageFilter = `language:${locale}`; const languageFilter = `language:${locale}`;
const tagsFilter = tags.map((tag) => `docusaurus_tag:${tag}`); const tagsFilter = tags.map((tag) => `docusaurus_tag:${tag}`);

View file

@ -99,7 +99,7 @@ function DocSearch({
: // ... or use config facetFilters : // ... or use config facetFilters
configFacetFilters; configFacetFilters;
// we let user override default searchParameters if he wants to // We let user override default searchParameters if she wants to
const searchParameters: DocSearchProps['searchParameters'] = { const searchParameters: DocSearchProps['searchParameters'] = {
...props.searchParameters, ...props.searchParameters,
facetFilters, facetFilters,

View file

@ -12,7 +12,7 @@ import type {
} from '@docusaurus/types'; } from '@docusaurus/types';
export const DEFAULT_CONFIG = { export const DEFAULT_CONFIG = {
// enabled by default, as it makes sense in most cases // Enabled by default, as it makes sense in most cases
// see also https://github.com/facebook/docusaurus/issues/5880 // see also https://github.com/facebook/docusaurus/issues/5880
contextualSearch: true, contextualSearch: true,

View file

@ -16,18 +16,19 @@ function getDefaultLocalesDirPath(): string {
// Return an ordered list of locales we should try // Return an ordered list of locales we should try
export function codeTranslationLocalesToTry(locale: string): string[] { export function codeTranslationLocalesToTry(locale: string): string[] {
const intlLocale = new Intl.Locale(locale); const intlLocale = new Intl.Locale(locale);
// if locale is just a simple language like "pt", we want to fallback to pt-BR // If locale is just a simple language like "pt", we want to fallback to
// (not pt-PT!) See https://github.com/facebook/docusaurus/pull/4536#issuecomment-810088783 // "pt-BR" (not "pt-PT"!)
const maximizedLocale = intlLocale.maximize(); // pt-Latn-BR // See https://github.com/facebook/docusaurus/pull/4536#issuecomment-810088783
const maximizedLocale = intlLocale.maximize(); // "pt-Latn-BR"
return [ return [
// May be "zh", "zh-CN", "zh-Hans", "zh-cn", or anything: very likely to be // May be "zh", "zh-CN", "zh-Hans", "zh-cn", or anything: very likely to be
// unresolved except for simply locales // unresolved except for simply locales
locale, locale,
// zh-CN / pt-BR // "zh-CN" / "pt-BR"
`${maximizedLocale.language}-${maximizedLocale.region}`, `${maximizedLocale.language}-${maximizedLocale.region}`,
// zh-Hans / pt-Latn // "zh-Hans" / "pt-Latn"
`${maximizedLocale.language}-${maximizedLocale.script}`, `${maximizedLocale.language}-${maximizedLocale.script}`,
// zh / pt // "zh" / "pt"
maximizedLocale.language!, maximizedLocale.language!,
]; ];
} }

View file

@ -313,9 +313,9 @@ export type Plugin<Content = unknown> = {
name: string; name: string;
loadContent?: () => Promise<Content> | Content; loadContent?: () => Promise<Content> | Content;
contentLoaded?: (args: { contentLoaded?: (args: {
/** the content loaded by this plugin instance */ /** The content loaded by this plugin instance */
content: Content; // content: Content; //
/** content loaded by ALL the plugins */ /** Content loaded by ALL the plugins */
allContent: AllContent; allContent: AllContent;
actions: PluginContentLoadedActions; actions: PluginContentLoadedActions;
}) => Promise<void> | void; }) => Promise<void> | void;

View file

@ -156,7 +156,6 @@ describe('localizePath', () => {
currentLocale: 'en', currentLocale: 'en',
localeConfigs: {}, localeConfigs: {},
}, },
// options: {localizePath: true},
}), }),
).toBe('/baseUrl/'); ).toBe('/baseUrl/');
}); });
@ -172,7 +171,6 @@ describe('localizePath', () => {
currentLocale: 'en', currentLocale: 'en',
localeConfigs: {}, localeConfigs: {},
}, },
// options: {localizePath: true},
}), }),
).toBe('/baseUrl/'); ).toBe('/baseUrl/');
}); });

View file

@ -38,7 +38,7 @@ describe('createExcerpt', () => {
Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis.
`), `),
).toBe( ).toBe(
// h1 title is skipped on purpose, because we don't want the page to have // H1 title is skipped on purpose, because we don't want the page to have
// SEO metadata title === description // SEO metadata title === description
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.',
); );
@ -56,7 +56,7 @@ describe('createExcerpt', () => {
Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis. Nunc porttitor libero nec vulputate venenatis. Nam nec rhoncus mauris. Morbi tempus est et nibh maximus, tempus venenatis arcu lobortis.
`), `),
).toBe( ).toBe(
// h1 title is skipped on purpose, because we don't want the page to have // H1 title is skipped on purpose, because we don't want the page to have
// SEO metadata title === description // SEO metadata title === description
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ex urna, molestie et sagittis ut, varius ac justo.',
); );
@ -377,7 +377,7 @@ Lorem Ipsum
`; `;
// remove the useless line breaks? Does not matter too much // Remove the useless line breaks? Does not matter too much
expect(parseMarkdownContentTitle(markdown)).toEqual({ expect(parseMarkdownContentTitle(markdown)).toEqual({
content: markdown, content: markdown,
contentTitle: 'Markdown Title', contentTitle: 'Markdown Title',

View file

@ -112,7 +112,7 @@ export function getFileCommitDate(
const result = shell.exec( const result = shell.exec(
`git log ${extraArgs} ${formatArg} -- "${path.basename(file)}"`, `git log ${extraArgs} ${formatArg} -- "${path.basename(file)}"`,
{ {
// cwd is important, see: https://github.com/facebook/docusaurus/pull/5048 // Setting cwd is important, see: https://github.com/facebook/docusaurus/pull/5048
cwd: path.dirname(file), cwd: path.dirname(file),
silent: true, silent: true,
}, },

View file

@ -61,7 +61,7 @@ export function getPluginI18nPath({
return path.join( return path.join(
siteDir, siteDir,
I18N_DIR_NAME, I18N_DIR_NAME,
// namespace first by locale: convenient to work in a single folder for a // Namespace first by locale: convenient to work in a single folder for a
// translator // translator
locale, locale,
// Make it convenient to use for single-instance // Make it convenient to use for single-instance

View file

@ -21,8 +21,10 @@ const isWindows = () => process.platform === 'win32';
export const isNameTooLong = (str: string): boolean => export const isNameTooLong = (str: string): boolean =>
// Not entirely correct: we can't assume FS from OS. But good enough? // Not entirely correct: we can't assume FS from OS. But good enough?
isMacOs() || isWindows() isMacOs() || isWindows()
? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // macOS (APFS) and Windows (NTFS) filename length limit (255 chars) ? // Windows (NTFS) and macOS (APFS) filename length limit (255 chars)
: Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES; // Other (255 bytes) str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS
: // Other (255 bytes)
Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES;
export function shortName(str: string): string { export function shortName(str: string): string {
if (isMacOs() || isWindows()) { if (isMacOs() || isWindows()) {

View file

@ -24,7 +24,7 @@ function normalizeFrontMatterTag(
// TODO maybe make ensure the permalink is valid url path? // TODO maybe make ensure the permalink is valid url path?
function normalizeTagPermalink(permalink: string): string { function normalizeTagPermalink(permalink: string): string {
// note: we always apply tagsPath on purpose. For versioned docs, v1/doc.md // Note: we always apply tagsPath on purpose. For versioned docs, v1/doc.md
// and v2/doc.md tags with custom permalinks don't lead to the same created // and v2/doc.md tags with custom permalinks don't lead to the same created
// page. tagsPath is different for each doc version // page. tagsPath is different for each doc version
return normalizeUrl([tagsPath, permalink]); return normalizeUrl([tagsPath, permalink]);

View file

@ -158,7 +158,6 @@ export function isValidPathname(str: string): boolean {
return false; return false;
} }
try { try {
// weird, but is there a better way?
const parsedPathname = new URL(str, 'https://domain.com').pathname; const parsedPathname = new URL(str, 'https://domain.com').pathname;
return parsedPathname === str || parsedPathname === encodeURI(str); return parsedPathname === str || parsedPathname === encodeURI(str);
} catch { } catch {

View file

@ -37,11 +37,10 @@ type FileLoaderUtils = {
* Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 * Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447
*/ */
export function getFileLoaderUtils(): FileLoaderUtils { export function getFileLoaderUtils(): FileLoaderUtils {
// files/images < urlLoaderLimit will be inlined as base64 strings directly in // Files/images < urlLoaderLimit will be inlined as base64 strings directly in
// the html // the html
const urlLoaderLimit = WEBPACK_URL_LOADER_LIMIT; const urlLoaderLimit = WEBPACK_URL_LOADER_LIMIT;
// defines the path/pattern of the assets handled by webpack
const fileLoaderFileName = (folder: AssetFolder) => const fileLoaderFileName = (folder: AssetFolder) =>
path.posix.join( path.posix.join(
OUTPUT_STATIC_ASSETS_DIR_NAME, OUTPUT_STATIC_ASSETS_DIR_NAME,

View file

@ -45,7 +45,6 @@ export default async function beforeCli() {
// Check is in background so it's fine to use a small value like 1h // Check is in background so it's fine to use a small value like 1h
// Use 0 for debugging // Use 0 for debugging
updateCheckInterval: 1000 * 60 * 60, updateCheckInterval: 1000 * 60 * 60,
// updateCheckInterval: 0
}); });
// Hacky way to ensure we check for updates on first run // Hacky way to ensure we check for updates on first run
@ -124,7 +123,7 @@ export default async function beforeCli() {
console.log(docusaurusUpdateMessage); console.log(docusaurusUpdateMessage);
} }
// notify user if node version needs to be updated // Notify user if node version needs to be updated
if (!semver.satisfies(process.version, requiredVersion)) { if (!semver.satisfies(process.version, requiredVersion)) {
logger.error('Minimum Node.js version not met :('); logger.error('Minimum Node.js version not met :(');
logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`; logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`;

View file

@ -11,12 +11,11 @@ module.exports = {
'error', 'error',
{ {
patterns: [ patterns: [
// prevent importing lodash in client bundle // Prevent importing lodash in client bundle for bundle size
// prefer shipping vanilla JS
'lodash', 'lodash',
'lodash.**', 'lodash.**',
'lodash/**', 'lodash/**',
// prevent importing server code in client bundle // Prevent importing server code in client bundle
'**/../babel/**', '**/../babel/**',
'**/../server/**', '**/../server/**',
'**/../commands/**', '**/../commands/**',

View file

@ -41,7 +41,7 @@ function createInlineHtmlBanner(baseUrl: string) {
`; `;
} }
// fn needs to work for older browsers! // Needs to work for older browsers!
function createInlineScript(baseUrl: string) { function createInlineScript(baseUrl: string) {
return ` return `
window['${InsertBannerWindowAttribute}'] = true; window['${InsertBannerWindowAttribute}'] = true;
@ -119,7 +119,6 @@ export default function MaybeBaseUrlIssueBanner(): JSX.Element | null {
siteConfig: {baseUrl, baseUrlIssueBanner}, siteConfig: {baseUrl, baseUrlIssueBanner},
} = useDocusaurusContext(); } = useDocusaurusContext();
const {pathname} = useLocation(); const {pathname} = useLocation();
// returns true for the homepage during SSR
const isHomePage = pathname === baseUrl; const isHomePage = pathname === baseUrl;
const enabled = baseUrlIssueBanner && isHomePage; const enabled = baseUrlIssueBanner && isHomePage;
return enabled ? <BaseUrlIssueBanner /> : null; return enabled ? <BaseUrlIssueBanner /> : null;

View file

@ -28,8 +28,7 @@ export const createStatefulLinksCollector = (): StatefulLinksCollector => {
const Context = React.createContext<LinksCollector>({ const Context = React.createContext<LinksCollector>({
collectLink: () => { collectLink: () => {
// noop by default for client // No-op for client. We only use the broken links checker server-side.
// we only use the broken links checker server-side
}, },
}); });

View file

@ -174,7 +174,7 @@ function Link(
onMouseEnter={onMouseEnter} onMouseEnter={onMouseEnter}
innerRef={handleRef} innerRef={handleRef}
to={targetLink} to={targetLink}
// avoid "React does not recognize the `activeClassName` prop on a DOM // Avoid "React does not recognize the `activeClassName` prop on a DOM
// element" // element"
{...(isNavLink && {isActive, activeClassName})} {...(isNavLink && {isActive, activeClassName})}
/> />

View file

@ -15,17 +15,9 @@ function addBaseUrl(
url: string, url: string,
{forcePrependBaseUrl = false, absolute = false}: BaseUrlOptions = {}, {forcePrependBaseUrl = false, absolute = false}: BaseUrlOptions = {},
): string { ): string {
if (!url) { // It never makes sense to add base url to a local anchor url, or one with a
return url; // protocol
} if (!url || url.startsWith('#') || hasProtocol(url)) {
// it never makes sense to add a base url to a local anchor url
if (url.startsWith('#')) {
return url;
}
// it never makes sense to add a base url to an url with a protocol
if (hasProtocol(url)) {
return url; return url;
} }

View file

@ -32,7 +32,7 @@ function mergeContexts({
const data = {...parent.data, ...value?.data}; const data = {...parent.data, ...value?.data};
return { return {
// nested routes are not supposed to override plugin attribute // Nested routes are not supposed to override plugin attribute
plugin: parent.plugin, plugin: parent.plugin,
data, data,
}; };

View file

@ -113,8 +113,9 @@ This behavior can have SEO impacts and create relative link issues.
shell.exit(0); shell.exit(0);
} }
// github.io indicates organization repos that deploy via default branch. // github.io indicates organization repos that deploy via default branch. All
// All others use gh-pages. Organization deploys looks like: // others use gh-pages (either case can be configured actually, but we can
// make educated guesses). Organization deploys look like:
// - Git repo: https://github.com/<organization>/<organization>.github.io // - Git repo: https://github.com/<organization>/<organization>.github.io
// - Site url: https://<organization>.github.io // - Site url: https://<organization>.github.io
const isGitHubPagesOrganizationDeploy = projectName.includes('.github.io'); const isGitHubPagesOrganizationDeploy = projectName.includes('.github.io');

View file

@ -41,7 +41,7 @@ export async function start(
siteDir, siteDir,
customConfigFilePath: cliOptions.config, customConfigFilePath: cliOptions.config,
locale: cliOptions.locale, locale: cliOptions.locale,
localizePath: undefined, // should this be configurable? localizePath: undefined, // Should this be configurable?
}); });
} }

View file

@ -13,7 +13,7 @@ import tree from 'tree-node-cli';
import {eject, wrap} from '../actions'; import {eject, wrap} from '../actions';
import {posixPath} from '@docusaurus/utils'; import {posixPath} from '@docusaurus/utils';
// use relative paths and sort files for tests // Use relative paths and sort files for tests
function stableCreatedFiles( function stableCreatedFiles(
siteThemePath: string, siteThemePath: string,
createdFiles: string[], createdFiles: string[],

View file

@ -53,7 +53,7 @@ export async function eject({
const fromPath = path.join(themePath, componentName); const fromPath = path.join(themePath, componentName);
const isDirectory = await isDir(fromPath); const isDirectory = await isDir(fromPath);
const globPattern = isDirectory const globPattern = isDirectory
? // do we really want to copy all components? ? // Do we really want to copy all components?
path.join(fromPath, '*') path.join(fromPath, '*')
: `${fromPath}.*`; : `${fromPath}.*`;

View file

@ -51,13 +51,13 @@ describe('handleBrokenLinks', () => {
const linkToEmptyFolder2 = '/emptyFolder/'; const linkToEmptyFolder2 = '/emptyFolder/';
const allCollectedLinks = { const allCollectedLinks = {
'/docs/good doc with space': [ '/docs/good doc with space': [
// good - valid file with spaces in name // Good - valid file with spaces in name
'./another%20good%20doc%20with%20space', './another%20good%20doc%20with%20space',
// good - valid file with percent-20 in its name // Good - valid file with percent-20 in its name
'./weird%20but%20good', './weird%20but%20good',
// bad - non-existent file with spaces in name // Bad - non-existent file with spaces in name
'./some%20other%20non-existent%20doc1', './some%20other%20non-existent%20doc1',
// evil - trying to use ../../ but '/' won't get decoded // Evil - trying to use ../../ but '/' won't get decoded
// cSpell:ignore Fout // cSpell:ignore Fout
'./break%2F..%2F..%2Fout2', './break%2F..%2F..%2Fout2',
], ],
@ -91,11 +91,11 @@ describe('handleBrokenLinks', () => {
linkToHtmlFile2, linkToHtmlFile2,
linkToJavadoc3, linkToJavadoc3,
linkToJavadoc4, linkToJavadoc4,
linkToEmptyFolder1, // not filtered! linkToEmptyFolder1, // Not filtered!
], ],
'/page2': [ '/page2': [
link2, link2,
linkToEmptyFolder2, // not filtered! linkToEmptyFolder2, // Not filtered!
linkToJavadoc2, linkToJavadoc2,
link3, link3,
linkToJavadoc3, linkToJavadoc3,

View file

@ -287,15 +287,14 @@ describe('normalizeConfig', () => {
}); });
it('throws error for required fields', () => { it('throws error for required fields', () => {
expect( expect(() =>
() => validateConfig({
validateConfig({ invalidField: true,
invalidField: true, presets: {},
presets: {}, stylesheets: {},
stylesheets: {}, themes: {},
themes: {}, scripts: {},
scripts: {}, }),
} as unknown as DocusaurusConfig), // to fields not in the type
).toThrowErrorMatchingSnapshot(); ).toThrowErrorMatchingSnapshot();
}); });
}); });

View file

@ -84,7 +84,6 @@ function getAllBrokenLinks({
getPageBrokenLinks({pageLinks, pagePath, routes: filteredRoutes}), getPageBrokenLinks({pageLinks, pagePath, routes: filteredRoutes}),
); );
// remove pages without any broken link
return _.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0); return _.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0);
} }

View file

@ -5,58 +5,38 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import {execSync} from 'child_process'; import {execSync, type ExecSyncOptionsWithStringEncoding} from 'child_process';
import detect from 'detect-port'; import detect from 'detect-port';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import prompts from 'prompts'; import prompts from 'prompts';
const execOptions = { const execOptions: ExecSyncOptionsWithStringEncoding = {
encoding: 'utf8' as const, encoding: 'utf8',
stdio: [ stdio: [/* stdin */ 'pipe', /* stdout */ 'pipe', /* stderr */ 'ignore'],
'pipe' as const, // stdin (default)
'pipe' as const, // stdout (default)
'ignore' as const, // stderr
],
}; };
// Clears console
function clearConsole(): void { function clearConsole(): void {
process.stdout.write( process.stdout.write(
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H', process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H',
); );
} }
// Gets process id of what is on port
function getProcessIdOnPort(port: number): string {
return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
.split('\n')[0]!
.trim();
}
// Gets process command
function getProcessCommand(processId: string): string {
const command = execSync(
`ps -o command -p ${processId} | sed -n 2p`,
execOptions,
);
return command.replace(/\n$/, '');
}
// Gets directory of a process from its process id
function getDirectoryOfProcessById(processId: string): string {
return execSync(
`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`,
execOptions,
).trim();
}
// Gets process on port
function getProcessForPort(port: number): string | null { function getProcessForPort(port: number): string | null {
try { try {
const processId = getProcessIdOnPort(port); const processId = execSync(
const directory = getDirectoryOfProcessById(processId); `lsof -i:${port} -P -t -sTCP:LISTEN`,
const command = getProcessCommand(processId); execOptions,
)
.split('\n')[0]!
.trim();
const directory = execSync(
`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`,
execOptions,
).trim();
const command = execSync(
`ps -o command -p ${processId} | sed -n 2p`,
execOptions,
).replace(/\n$/, '');
return logger.interpolate`code=${command} subdue=${`(pid ${processId})`} in path=${directory}`; return logger.interpolate`code=${command} subdue=${`(pid ${processId})`} in path=${directory}`;
} catch { } catch {
return null; return null;

View file

@ -166,8 +166,8 @@ export default ${JSON.stringify(siteConfig, null, 2)};
'client-modules.js', 'client-modules.js',
`export default [ `export default [
${clientModules ${clientModules
// import() is async so we use require() because client modules can have // Use `require()` because `import()` is async but client modules can have CSS
// CSS and the order matters for loading CSS. // and the order matters for loading CSS.
.map((clientModule) => ` require('${escapePath(clientModule)}'),`) .map((clientModule) => ` require('${escapePath(clientModule)}'),`)
.join('\n')} .join('\n')}
]; ];

View file

@ -98,7 +98,7 @@ export async function loadPlugins(context: LoadContext): Promise<{
return; return;
} }
const pluginId = plugin.options.id; const pluginId = plugin.options.id;
// plugins data files are namespaced by pluginName/pluginId // Plugins data files are namespaced by pluginName/pluginId
const dataDir = path.join( const dataDir = path.join(
context.generatedFilesDir, context.generatedFilesDir,
plugin.name, plugin.name,

View file

@ -28,7 +28,7 @@ function getOptionValidationFunction(
normalizedPluginConfig: NormalizedPluginConfig, normalizedPluginConfig: NormalizedPluginConfig,
): PluginModule['validateOptions'] { ): PluginModule['validateOptions'] {
if (normalizedPluginConfig.pluginModule) { if (normalizedPluginConfig.pluginModule) {
// support both commonjs and ES modules // Support both CommonJS and ES modules
return ( return (
normalizedPluginConfig.pluginModule.module?.default?.validateOptions ?? normalizedPluginConfig.pluginModule.module?.default?.validateOptions ??
normalizedPluginConfig.pluginModule.module?.validateOptions normalizedPluginConfig.pluginModule.module?.validateOptions
@ -41,7 +41,7 @@ function getThemeValidationFunction(
normalizedPluginConfig: NormalizedPluginConfig, normalizedPluginConfig: NormalizedPluginConfig,
): PluginModule['validateThemeConfig'] { ): PluginModule['validateThemeConfig'] {
if (normalizedPluginConfig.pluginModule) { if (normalizedPluginConfig.pluginModule) {
// support both commonjs and ES modules // Support both CommonJS and ES modules
return ( return (
normalizedPluginConfig.pluginModule.module.default?.validateThemeConfig ?? normalizedPluginConfig.pluginModule.module.default?.validateThemeConfig ??
normalizedPluginConfig.pluginModule.module.validateThemeConfig normalizedPluginConfig.pluginModule.module.validateThemeConfig
@ -65,7 +65,6 @@ export async function initPlugins(
async function doGetPluginVersion( async function doGetPluginVersion(
normalizedPluginConfig: NormalizedPluginConfig, normalizedPluginConfig: NormalizedPluginConfig,
): Promise<PluginVersionInformation> { ): Promise<PluginVersionInformation> {
// get plugin version
if (normalizedPluginConfig.pluginModule?.path) { if (normalizedPluginConfig.pluginModule?.path) {
const pluginPath = pluginRequire.resolve( const pluginPath = pluginRequire.resolve(
normalizedPluginConfig.pluginModule?.path, normalizedPluginConfig.pluginModule?.path,

View file

@ -94,7 +94,7 @@ function mergeTranslationFileContent({
message: options.override message: options.override
? message ? message
: existingContent[key]?.message ?? message, : existingContent[key]?.message ?? message,
description, // description description,
}; };
}, },
); );
@ -143,7 +143,7 @@ Maybe you should remove them? ${unknownKeys}`;
} }
} }
// should we make this configurable? // Should we make this configurable?
export function getTranslationsLocaleDirPath( export function getTranslationsLocaleDirPath(
context: TranslationContext, context: TranslationContext,
): string { ): string {
@ -248,7 +248,7 @@ export async function localizePluginTranslationFile({
const localizedContent = await readTranslationFileContent(filePath); const localizedContent = await readTranslationFileContent(filePath);
if (localizedContent) { if (localizedContent) {
// localized messages "override" default unlocalized messages // Localized messages "override" default unlocalized messages
return { return {
path: translationFile.path, path: translationFile.path,
content: { content: {

View file

@ -52,7 +52,7 @@ describe('customize JS loader', () => {
describe('extending generated webpack config', () => { describe('extending generated webpack config', () => {
it('direct mutation on generated webpack config object', async () => { it('direct mutation on generated webpack config object', async () => {
// fake generated webpack config // Fake generated webpack config
let config: Configuration = { let config: Configuration = {
output: { output: {
path: __dirname, path: __dirname,

View file

@ -24,7 +24,7 @@ const CSS_MODULE_REGEX = /\.module\.css$/i;
export const clientDir = path.join(__dirname, '..', 'client'); export const clientDir = path.join(__dirname, '..', 'client');
const LibrariesToTranspile = [ const LibrariesToTranspile = [
'copy-text-to-clipboard', // contains optional catch binding, incompatible with recent versions of Edge 'copy-text-to-clipboard', // Contains optional catch binding, incompatible with recent versions of Edge
]; ];
const LibrariesToTranspileRegex = new RegExp( const LibrariesToTranspileRegex = new RegExp(
@ -32,7 +32,7 @@ const LibrariesToTranspileRegex = new RegExp(
); );
export function excludeJS(modulePath: string): boolean { export function excludeJS(modulePath: string): boolean {
// always transpile client dir // Always transpile client dir
if (modulePath.startsWith(clientDir)) { if (modulePath.startsWith(clientDir)) {
return false; return false;
} }
@ -118,9 +118,9 @@ export async function createBaseConfig(
}, },
devtool: isProd ? undefined : 'eval-cheap-module-source-map', devtool: isProd ? undefined : 'eval-cheap-module-source-map',
resolve: { resolve: {
unsafeCache: false, // not enabled, does not seem to improve perf much unsafeCache: false, // Not enabled, does not seem to improve perf much
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'], extensions: ['.wasm', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
symlinks: true, // see https://github.com/facebook/docusaurus/issues/3272 symlinks: true, // See https://github.com/facebook/docusaurus/issues/3272
roots: [ roots: [
// Allow resolution of url("/fonts/xyz.ttf") by webpack // Allow resolution of url("/fonts/xyz.ttf") by webpack
// See https://webpack.js.org/configuration/resolve/#resolveroots // See https://webpack.js.org/configuration/resolve/#resolveroots
@ -167,7 +167,7 @@ export async function createBaseConfig(
// include [name] in the filenames // include [name] in the filenames
name: false, name: false,
cacheGroups: { cacheGroups: {
// disable the built-in cacheGroups // Disable the built-in cacheGroups
default: false, default: false,
common: { common: {
name: 'common', name: 'common',
@ -238,7 +238,7 @@ export async function createBaseConfig(
chunkFilename: isProd chunkFilename: isProd
? 'assets/css/[name].[contenthash:8].css' ? 'assets/css/[name].[contenthash:8].css'
: '[name].css', : '[name].css',
// remove css order warnings if css imports are not sorted // Remove css order warnings if css imports are not sorted
// alphabetically. See https://github.com/webpack-contrib/mini-css-extract-plugin/pull/422 // alphabetically. See https://github.com/webpack-contrib/mini-css-extract-plugin/pull/422
// for more reasoning // for more reasoning
ignoreOrder: true, ignoreOrder: true,

View file

@ -23,7 +23,7 @@ export default async function createClientConfig(
const config = await createBaseConfig(props, false, minify); const config = await createBaseConfig(props, false, minify);
const clientConfig = merge(config, { const clientConfig = merge(config, {
// useless, disabled on purpose (errors on existing sites with no // Useless, disabled on purpose (errors on existing sites with no
// browserslist config) // browserslist config)
// target: 'browserslist', // target: 'browserslist',
entry: path.resolve(__dirname, '../client/clientEntry.js'), entry: path.resolve(__dirname, '../client/clientEntry.js'),

View file

@ -204,7 +204,7 @@ export function applyConfigurePostCss(
options: {postcssOptions: PostCssOptions}; options: {postcssOptions: PostCssOptions};
}; };
// not ideal heuristic but good enough for our use-case? // Not ideal heuristic but good enough for our use-case?
function isPostCssLoader(loader: unknown): loader is LocalPostCSSLoader { function isPostCssLoader(loader: unknown): loader is LocalPostCSSLoader {
return !!(loader as LocalPostCSSLoader)?.options?.postcssOptions; return !!(loader as LocalPostCSSLoader)?.options?.postcssOptions;
} }
@ -249,7 +249,7 @@ export function compile(config: Configuration[]): Promise<void> {
} }
reject(err); reject(err);
} }
// let plugins consume all the stats // Let plugins consume all the stats
const errorsWarnings = stats?.toJson('errors-warnings'); const errorsWarnings = stats?.toJson('errors-warnings');
if (stats?.hasErrors()) { if (stats?.hasErrors()) {
reject(new Error('Failed to compile with errors.')); reject(new Error('Failed to compile with errors.'));
@ -363,7 +363,7 @@ export function getMinimizer(
parallel: getTerserParallel(), parallel: getTerserParallel(),
terserOptions: { terserOptions: {
parse: { parse: {
// we want uglify-js to parse ecma 8 code. However, we don't want it // We want uglify-js to parse ecma 8 code. However, we don't want it
// to apply any minification steps that turns valid ecma 5 code // to apply any minification steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output' // into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe // sections only apply transformations that are ecma 5 safe

View file

@ -21,8 +21,8 @@ const SUPPORTED_MIMES: {[ext: string]: string} = {
}; };
/** /**
* it returns a Base64 image string with required formatting * It returns a Base64 image string with required formatting to work on the web
* to work on the web (<img src=".." /> or in CSS url('..')) * (<img src=".." /> or in CSS url('..'))
*/ */
const toBase64 = (extMimeType: string, data: Buffer): string => const toBase64 = (extMimeType: string, data: Buffer): string =>
`data:${extMimeType};base64,${data.toString('base64')}`; `data:${extMimeType};base64,${data.toString('base64')}`;

View file

@ -21,6 +21,7 @@ backticks
bartosz bartosz
beforeinstallprompt beforeinstallprompt
bhatt bhatt
blocklist
blockquotes blockquotes
browserslist browserslist
browserstack browserstack

View file

@ -87,7 +87,7 @@ const sidebars = {
collapsed: false, collapsed: false,
collapsible: false, collapsible: false,
items: [ items: [
// title // Title
{ {
type: 'html', type: 'html',
value: 'Some Text', value: 'Some Text',

View file

@ -22,7 +22,7 @@ exports.dogfoodingThemeInstances = dogfoodingThemeInstances;
/** @type {import('@docusaurus/types').PluginConfig[]} */ /** @type {import('@docusaurus/types').PluginConfig[]} */
const dogfoodingPluginInstances = [ const dogfoodingPluginInstances = [
[ [
'content-docs', // dogfood shorthand 'content-docs', // Shorthand
/** @type {import('@docusaurus/plugin-content-docs').Options} */ /** @type {import('@docusaurus/plugin-content-docs').Options} */
({ ({
id: 'docs-tests', id: 'docs-tests',
@ -52,7 +52,7 @@ const dogfoodingPluginInstances = [
], ],
[ [
'@docusaurus/plugin-content-blog', // dogfood longhand '@docusaurus/plugin-content-blog', // Longhand
/** @type {import('@docusaurus/plugin-content-blog').Options} */ /** @type {import('@docusaurus/plugin-content-blog').Options} */
({ ({
id: 'blog-tests', id: 'blog-tests',
@ -75,7 +75,7 @@ const dogfoodingPluginInstances = [
], ],
[ [
require.resolve('@docusaurus/plugin-content-pages'), // dogfood longhand resolve require.resolve('@docusaurus/plugin-content-pages'), // Full path
/** @type {import('@docusaurus/plugin-content-pages').Options} */ /** @type {import('@docusaurus/plugin-content-pages').Options} */
({ ({
id: 'pages-tests', id: 'pages-tests',

View file

@ -68,16 +68,16 @@ Please double-check or clean up these components from the config:
// TODO temp workaround: non-comps should be forbidden to wrap // TODO temp workaround: non-comps should be forbidden to wrap
if (action === 'wrap') { if (action === 'wrap') {
const WrapBlacklist = [ const WrapBlocklist = [
'Layout', // due to theme-fallback? 'Layout', // Due to theme-fallback?
]; ];
componentNames = componentNames.filter((componentName) => { componentNames = componentNames.filter((componentName) => {
const blacklisted = WrapBlacklist.includes(componentName); const blocked = WrapBlocklist.includes(componentName);
if (!WrapBlacklist) { if (blocked) {
logger.warn(`${componentName} is blacklisted and will not be wrapped`); logger.warn(`${componentName} is blocked and will not be wrapped`);
} }
return !blacklisted; return !blocked;
}); });
} }

View file

@ -170,8 +170,8 @@ const config = {
({ ({
fromExtensions: ['html'], fromExtensions: ['html'],
createRedirects(routePath) { createRedirects(routePath) {
// redirect to /docs from /docs/introduction, // Redirect to /docs from /docs/introduction, as introduction has been
// as introduction has been made the home doc // made the home doc
if (allDocHomesPaths.includes(routePath)) { if (allDocHomesPaths.includes(routePath)) {
return [`${routePath}/introduction`]; return [`${routePath}/introduction`];
} }
@ -195,13 +195,15 @@ const config = {
], ],
[ [
'ideal-image', 'ideal-image',
{ /** @type {import('@docusaurus/plugin-ideal-image').PluginOptions} */
({
quality: 70, quality: 70,
max: 1030, // max resized image's size. max: 1030,
min: 640, // min resized image's size. if original is lower, use that size. min: 640,
steps: 2, // the max number of images generated between min and max (inclusive) steps: 2,
// disableInDev: false, // Use false to debug, but it incurs huge perf costs
}, disableInDev: true,
}),
], ],
[ [
'pwa', 'pwa',
@ -413,7 +415,7 @@ const config = {
label: 'Tests', label: 'Tests',
docsPluginId: 'docs-tests', docsPluginId: 'docs-tests',
}, },
// right // Right
{ {
type: 'docsVersionDropdown', type: 'docsVersionDropdown',
position: 'right', position: 'right',

View file

@ -47,7 +47,7 @@ const EXPECTED_CSS_MARKERS = [
'.test-marker-theme-layout', '.test-marker-theme-layout',
'.test-marker-site-index-page', '.test-marker-site-index-page',
// lazy loaded lib // Lazy-loaded lib
'.DocSearch-Modal', '.DocSearch-Modal',
]; ];

View file

@ -24,7 +24,7 @@ const pollInterval = 5000;
const timeout = 5 * 60 * 1000; const timeout = 5 * 60 * 1000;
const projectId = 428890; const projectId = 428890;
const token = process.env.CROWDIN_PERSONAL_TOKEN; // set on Netlify const token = process.env.CROWDIN_PERSONAL_TOKEN; // Set on Netlify
const translations = new Translations({token}); const translations = new Translations({token});