mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-28 09:47:48 +02:00
refactor: fix a lot of errors in type-aware linting (#7477)
This commit is contained in:
parent
222bf3c091
commit
bf1513a3e3
120 changed files with 407 additions and 364 deletions
|
@ -70,17 +70,15 @@ describe('packages', () => {
|
|||
packageJsonFile.content.name?.startsWith('@'),
|
||||
)
|
||||
.forEach((packageJsonFile) => {
|
||||
if (packageJsonFile) {
|
||||
// Unfortunately jest custom message do not exist in loops,
|
||||
// so using an exception instead to show failing package file
|
||||
// (see https://github.com/facebook/jest/issues/3293)
|
||||
// expect(packageJsonFile.content.publishConfig?.access)
|
||||
// .toEqual('public');
|
||||
if (packageJsonFile.content.publishConfig?.access !== 'public') {
|
||||
throw new Error(
|
||||
`Package ${packageJsonFile.file} does not have publishConfig.access: 'public'`,
|
||||
);
|
||||
}
|
||||
// Unfortunately jest custom message do not exist in loops,
|
||||
// so using an exception instead to show failing package file
|
||||
// (see https://github.com/facebook/jest/issues/3293)
|
||||
// expect(packageJsonFile.content.publishConfig?.access)
|
||||
// .toEqual('public');
|
||||
if (packageJsonFile.content.publishConfig?.access !== 'public') {
|
||||
throw new Error(
|
||||
`Package ${packageJsonFile.file} does not have publishConfig.access: 'public'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,5 @@
|
|||
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||
import type {Handler} from '@netlify/functions';
|
||||
|
||||
export const handler: Handler = async function handler() {
|
||||
return createPlaygroundResponse('codesandbox');
|
||||
};
|
||||
export const handler: Handler = () =>
|
||||
Promise.resolve(createPlaygroundResponse('codesandbox'));
|
||||
|
|
|
@ -8,6 +8,5 @@
|
|||
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||
import type {Handler} from '@netlify/functions';
|
||||
|
||||
export const handler: Handler = async function handler() {
|
||||
return createPlaygroundResponse('stackblitz');
|
||||
};
|
||||
export const handler: Handler = () =>
|
||||
Promise.resolve(createPlaygroundResponse('stackblitz'));
|
||||
|
|
|
@ -65,20 +65,22 @@ async function askForPackageManagerChoice(): Promise<PackageManager> {
|
|||
.map((p) => ({title: p, value: p}));
|
||||
|
||||
return (
|
||||
(await prompts(
|
||||
{
|
||||
type: 'select',
|
||||
name: 'packageManager',
|
||||
message: 'Select a package manager...',
|
||||
choices,
|
||||
},
|
||||
{
|
||||
onCancel() {
|
||||
logger.info`Falling back to name=${defaultPackageManager}`;
|
||||
(
|
||||
(await prompts(
|
||||
{
|
||||
type: 'select',
|
||||
name: 'packageManager',
|
||||
message: 'Select a package manager...',
|
||||
choices,
|
||||
},
|
||||
},
|
||||
)) as {packageManager: PackageManager}
|
||||
).packageManager;
|
||||
{
|
||||
onCancel() {
|
||||
logger.info`Falling back to name=${defaultPackageManager}`;
|
||||
},
|
||||
},
|
||||
)) as {packageManager: PackageManager}
|
||||
).packageManager ?? defaultPackageManager
|
||||
);
|
||||
}
|
||||
|
||||
async function getPackageManager(
|
||||
|
@ -101,8 +103,7 @@ async function getPackageManager(
|
|||
(await findPackageManagerFromLockFile('.')) ??
|
||||
findPackageManagerFromUserAgent() ??
|
||||
// This only happens if the user has a global installation in PATH
|
||||
(skipInstall ? defaultPackageManager : askForPackageManagerChoice()) ??
|
||||
defaultPackageManager
|
||||
(skipInstall ? defaultPackageManager : askForPackageManagerChoice())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -215,7 +216,7 @@ async function getGitCommand(gitStrategy: GitStrategy): Promise<string> {
|
|||
logger.info`Falling back to code=${'git clone'}`;
|
||||
},
|
||||
},
|
||||
)) as {command: string};
|
||||
)) as {command?: string};
|
||||
return command ?? 'git clone';
|
||||
}
|
||||
case 'deep':
|
||||
|
@ -362,7 +363,7 @@ async function getSource(
|
|||
)) as {gitRepoUrl: string};
|
||||
let strategy = cliOptions.gitStrategy;
|
||||
if (!strategy) {
|
||||
({strategy} = await prompts(
|
||||
({strategy} = (await prompts(
|
||||
{
|
||||
type: 'select',
|
||||
name: 'strategy',
|
||||
|
@ -385,7 +386,7 @@ async function getSource(
|
|||
logger.info`Falling back to name=${'deep'}`;
|
||||
},
|
||||
},
|
||||
));
|
||||
)) as {strategy?: GitStrategy});
|
||||
}
|
||||
return {
|
||||
type: 'git',
|
||||
|
@ -426,13 +427,13 @@ async function getSource(
|
|||
}
|
||||
let useTS = cliOptions.typescript;
|
||||
if (!useTS && template.tsVariantPath) {
|
||||
({useTS} = await prompts({
|
||||
({useTS} = (await prompts({
|
||||
type: 'confirm',
|
||||
name: 'useTS',
|
||||
message:
|
||||
'This template is available in TypeScript. Do you want to use the TS variant?',
|
||||
initial: false,
|
||||
}));
|
||||
})) as {useTS?: boolean});
|
||||
}
|
||||
return {
|
||||
type: 'template',
|
||||
|
|
|
@ -9,10 +9,10 @@ import chalk from 'chalk';
|
|||
|
||||
type InterpolatableValue = string | number | (string | number)[];
|
||||
|
||||
const path = (msg: unknown): string => chalk.cyan.underline(`"${msg}"`);
|
||||
const path = (msg: unknown): string => chalk.cyan.underline(`"${String(msg)}"`);
|
||||
const url = (msg: unknown): string => chalk.cyan.underline(msg);
|
||||
const name = (msg: unknown): string => chalk.blue.bold(msg);
|
||||
const code = (msg: unknown): string => chalk.cyan(`\`${msg}\``);
|
||||
const code = (msg: unknown): string => chalk.cyan(`\`${String(msg)}\``);
|
||||
const subdue = (msg: unknown): string => chalk.gray(msg);
|
||||
const num = (msg: unknown): string => chalk.yellow(msg);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export type LoadedMDXContent<FrontMatter, Metadata, Assets = undefined> = {
|
|||
/** As provided by the content plugin. */
|
||||
readonly metadata: Metadata;
|
||||
/** A list of TOC items (headings). */
|
||||
readonly toc: readonly TOCItem[];
|
||||
readonly toc?: readonly TOCItem[];
|
||||
/** First h1 title before any content. */
|
||||
readonly contentTitle: string | undefined;
|
||||
/**
|
||||
|
|
|
@ -55,7 +55,7 @@ export type MDXOptions = {
|
|||
beforeDefaultRehypePlugins: MDXPlugin[];
|
||||
};
|
||||
|
||||
export type Options = MDXOptions & {
|
||||
export type Options = Partial<MDXOptions> & {
|
||||
staticDirs: string[];
|
||||
siteDir: string;
|
||||
isMDXPartial?: (filePath: string) => boolean;
|
||||
|
@ -138,7 +138,7 @@ export async function mdxLoader(
|
|||
): Promise<void> {
|
||||
const callback = this.async();
|
||||
const filePath = this.resourcePath;
|
||||
const reqOptions = this.getOptions() ?? {};
|
||||
const reqOptions = this.getOptions();
|
||||
|
||||
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export default function plugin(): Transformer {
|
|||
return (root) => {
|
||||
const slugs = createSlugger();
|
||||
visit(root, 'heading', (headingNode: Heading) => {
|
||||
const data = headingNode.data || (headingNode.data = {});
|
||||
const data = headingNode.data ?? (headingNode.data = {});
|
||||
const properties = (data.hProperties || (data.hProperties = {})) as {
|
||||
id: string;
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ export default function plugin(): Transformer {
|
|||
// Support explicit heading IDs
|
||||
const parsedHeading = parseMarkdownHeadingId(heading);
|
||||
|
||||
id = parsedHeading.id || slugs.slug(heading);
|
||||
id = parsedHeading.id ?? slugs.slug(heading);
|
||||
|
||||
if (parsedHeading.id) {
|
||||
// When there's an id, it is always in the last child node
|
||||
|
|
|
@ -110,8 +110,9 @@ async function processLinkNode(node: Link, context: Context) {
|
|||
if (!node.url) {
|
||||
// Try to improve error feedback
|
||||
// see https://github.com/facebook/docusaurus/issues/3309#issuecomment-690371675
|
||||
const title = node.title || (node.children[0] as Literal)?.value || '?';
|
||||
const line = node?.position?.start?.line || '?';
|
||||
const title =
|
||||
node.title ?? (node.children[0] as Literal | undefined)?.value ?? '?';
|
||||
const line = node.position?.start.line ?? '?';
|
||||
throw new Error(
|
||||
`Markdown link URL is mandatory in "${toMessageRelativeFilePath(
|
||||
context.filePath,
|
||||
|
|
|
@ -15,7 +15,7 @@ export function stringifyContent(node: Parent): string {
|
|||
}
|
||||
|
||||
export function toValue(node: PhrasingContent | Heading): string {
|
||||
switch (node?.type) {
|
||||
switch (node.type) {
|
||||
case 'text':
|
||||
return escapeHtml(node.value);
|
||||
case 'heading':
|
||||
|
|
|
@ -19,22 +19,22 @@ async function testMigration(siteDir: string, newDir: string) {
|
|||
await migrateDocusaurusProject(siteDir, newDir, true, true);
|
||||
expect(
|
||||
writeMock.mock.calls.sort((a, b) =>
|
||||
posixPath(a[0] as string).localeCompare(posixPath(b[0] as string)),
|
||||
posixPath(a[0]).localeCompare(posixPath(b[0])),
|
||||
),
|
||||
).toMatchSnapshot('write');
|
||||
expect(
|
||||
mkdirpMock.mock.calls.sort((a, b) =>
|
||||
posixPath(a[0] as string).localeCompare(posixPath(b[0] as string)),
|
||||
posixPath(a[0]).localeCompare(posixPath(b[0])),
|
||||
),
|
||||
).toMatchSnapshot('mkdirp');
|
||||
expect(
|
||||
mkdirsMock.mock.calls.sort((a, b) =>
|
||||
posixPath(a[0] as string).localeCompare(posixPath(b[0] as string)),
|
||||
posixPath(a[0]).localeCompare(posixPath(b[0])),
|
||||
),
|
||||
).toMatchSnapshot('mkdirs');
|
||||
expect(
|
||||
copyMock.mock.calls.sort((a, b) =>
|
||||
posixPath(a[0] as string).localeCompare(posixPath(b[0] as string)),
|
||||
posixPath(a[0]).localeCompare(posixPath(b[0])),
|
||||
),
|
||||
).toMatchSnapshot('copy');
|
||||
writeMock.mockRestore();
|
||||
|
|
|
@ -40,12 +40,7 @@ export default function extractMetadata(content: string): Data {
|
|||
lines.slice(0, -1).forEach((line) => {
|
||||
const keyValue = line.split(':') as [string, ...string[]];
|
||||
const key = keyValue[0].trim();
|
||||
let value = keyValue.slice(1).join(':').trim();
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (err) {
|
||||
// Ignore the error as it means it's not a JSON value.
|
||||
}
|
||||
const value = keyValue.slice(1).join(':').trim();
|
||||
metadata[key] = value;
|
||||
});
|
||||
return {metadata, rawContent: both.content};
|
||||
|
|
|
@ -474,7 +474,7 @@ async function migrateVersionedDocs(
|
|||
versions.reverse().map(async (version, index) => {
|
||||
if (index === 0) {
|
||||
await fs.copy(
|
||||
path.join(siteDir, '..', context.v1Config.customDocsPath || 'docs'),
|
||||
path.join(siteDir, '..', context.v1Config.customDocsPath ?? 'docs'),
|
||||
path.join(newDir, 'versioned_docs', `version-${version}`),
|
||||
);
|
||||
await fs.copy(
|
||||
|
@ -551,7 +551,9 @@ async function migrateVersionedSidebar(
|
|||
const newSidebar = Object.entries(sidebarEntries).reduce(
|
||||
(topLevel: SidebarEntries, value) => {
|
||||
const key = value[0].replace(versionRegex, '');
|
||||
topLevel[key] = Object.entries(value[1]).reduce((acc, val) => {
|
||||
topLevel[key] = Object.entries(value[1]).reduce<{
|
||||
[key: string]: Array<string | {[key: string]: unknown}>;
|
||||
}>((acc, val) => {
|
||||
acc[val[0].replace(versionRegex, '')] = (
|
||||
val[1] as SidebarEntry[]
|
||||
).map((item) => {
|
||||
|
@ -565,7 +567,7 @@ async function migrateVersionedSidebar(
|
|||
};
|
||||
});
|
||||
return acc;
|
||||
}, {} as {[key: string]: Array<string | {[key: string]: unknown}>});
|
||||
}, {});
|
||||
return topLevel;
|
||||
},
|
||||
{},
|
||||
|
@ -574,33 +576,32 @@ async function migrateVersionedSidebar(
|
|||
}
|
||||
await Promise.all(
|
||||
sidebars.map(async (sidebar) => {
|
||||
const newSidebar = Object.entries(sidebar.entries).reduce(
|
||||
(acc, val) => {
|
||||
const key = `version-${sidebar.version}/${val[0]}`;
|
||||
acc[key] = Object.entries(val[1]).map((value) => ({
|
||||
type: 'category',
|
||||
label: value[0],
|
||||
items: (value[1] as SidebarEntry[]).map((sidebarItem) => {
|
||||
if (typeof sidebarItem === 'string') {
|
||||
return {
|
||||
type: 'doc',
|
||||
id: `version-${sidebar.version}/${sidebarItem}`,
|
||||
};
|
||||
}
|
||||
const newSidebar = Object.entries(
|
||||
sidebar.entries,
|
||||
).reduce<SidebarEntries>((acc, val) => {
|
||||
const key = `version-${sidebar.version}/${val[0]}`;
|
||||
acc[key] = Object.entries(val[1]).map((value) => ({
|
||||
type: 'category',
|
||||
label: value[0],
|
||||
items: (value[1] as SidebarEntry[]).map((sidebarItem) => {
|
||||
if (typeof sidebarItem === 'string') {
|
||||
return {
|
||||
type: 'category',
|
||||
label: sidebarItem.label,
|
||||
items: sidebarItem.ids.map((id) => ({
|
||||
type: 'doc',
|
||||
id: `version-${sidebar.version}/${id}`,
|
||||
})),
|
||||
type: 'doc',
|
||||
id: `version-${sidebar.version}/${sidebarItem}`,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
return acc;
|
||||
},
|
||||
{} as SidebarEntries,
|
||||
);
|
||||
}
|
||||
return {
|
||||
type: 'category',
|
||||
label: sidebarItem.label,
|
||||
items: sidebarItem.ids.map((id) => ({
|
||||
type: 'doc',
|
||||
id: `version-${sidebar.version}/${id}`,
|
||||
})),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
return acc;
|
||||
}, {});
|
||||
await fs.outputFile(
|
||||
path.join(
|
||||
newDir,
|
||||
|
@ -702,12 +703,12 @@ async function migrateLatestDocs(context: MigrationContext) {
|
|||
|
||||
async function migratePackageFile(context: MigrationContext): Promise<void> {
|
||||
const {deps, siteDir, newDir} = context;
|
||||
const packageFile = importFresh(`${siteDir}/package.json`) as {
|
||||
const packageFile = importFresh<{
|
||||
scripts?: {[key: string]: string};
|
||||
dependencies?: {[key: string]: string};
|
||||
devDependencies?: {[key: string]: string};
|
||||
[otherKey: string]: unknown;
|
||||
};
|
||||
}>(`${siteDir}/package.json`);
|
||||
packageFile.scripts = {
|
||||
...packageFile.scripts,
|
||||
start: 'docusaurus start',
|
||||
|
|
|
@ -37,7 +37,7 @@ export default function sanitizeMD(code: string): string {
|
|||
const htmlTree = unified().use(parse).parse(markdownString);
|
||||
|
||||
visit(htmlTree, 'element', (node: Element) => {
|
||||
if (!tags[node.tagName as string]) {
|
||||
if (!tags[node.tagName]) {
|
||||
(node as Element | Text).type = 'text';
|
||||
(node as Element & Partial<Omit<Text, 'type'>>).value =
|
||||
node.tagName + toText(node);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
declare module '@generated/client-modules' {
|
||||
import type {ClientModule} from '@docusaurus/types';
|
||||
|
||||
const clientModules: readonly (ClientModule & {default: ClientModule})[];
|
||||
const clientModules: readonly (ClientModule & {default?: ClientModule})[];
|
||||
export default clientModules;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import writeRedirectFiles, {
|
|||
// - https://github.com/facebook/docusaurus/issues/3886
|
||||
// - https://github.com/facebook/docusaurus/issues/3925
|
||||
describe('createToUrl', () => {
|
||||
it('creates appropriate redirect urls', async () => {
|
||||
it('creates appropriate redirect urls', () => {
|
||||
expect(createToUrl('/', '/docs/something/else')).toBe(
|
||||
'/docs/something/else',
|
||||
);
|
||||
|
@ -29,7 +29,7 @@ describe('createToUrl', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates appropriate redirect urls with baseUrl', async () => {
|
||||
it('creates appropriate redirect urls with baseUrl', () => {
|
||||
expect(createToUrl('/baseUrl/', '/docs/something/else')).toBe(
|
||||
'/baseUrl/docs/something/else',
|
||||
);
|
||||
|
@ -43,7 +43,7 @@ describe('createToUrl', () => {
|
|||
});
|
||||
|
||||
describe('toRedirectFilesMetadata', () => {
|
||||
it('creates appropriate metadata trailingSlash=undefined', async () => {
|
||||
it('creates appropriate metadata trailingSlash=undefined', () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: 'https://docusaurus.io',
|
||||
|
@ -70,7 +70,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates appropriate metadata trailingSlash=true', async () => {
|
||||
it('creates appropriate metadata trailingSlash=true', () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: 'https://docusaurus.io',
|
||||
|
@ -97,7 +97,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates appropriate metadata trailingSlash=false', async () => {
|
||||
it('creates appropriate metadata trailingSlash=false', () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: 'https://docusaurus.io',
|
||||
|
@ -127,7 +127,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates appropriate metadata for root baseUrl', async () => {
|
||||
it('creates appropriate metadata for root baseUrl', () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: '/',
|
||||
|
@ -142,7 +142,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('creates appropriate metadata for empty baseUrl', async () => {
|
||||
it('creates appropriate metadata for empty baseUrl', () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: '',
|
||||
|
|
|
@ -18,7 +18,7 @@ import type {PluginOptions, Options} from './options';
|
|||
export default function pluginClientRedirectsPages(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Plugin<unknown> {
|
||||
): Plugin<void> {
|
||||
const {trailingSlash} = context.siteConfig;
|
||||
|
||||
return {
|
||||
|
|
|
@ -89,6 +89,7 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
|
|||
},
|
||||
readingTime: ({content, defaultReadingTime}) =>
|
||||
defaultReadingTime({content}),
|
||||
truncateMarker: /<!--\s*truncate\s*-->/,
|
||||
} as PluginOptions,
|
||||
);
|
||||
|
||||
|
@ -128,6 +129,7 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
|
|||
},
|
||||
readingTime: ({content, defaultReadingTime}) =>
|
||||
defaultReadingTime({content}),
|
||||
truncateMarker: /<!--\s*truncate\s*-->/,
|
||||
} as PluginOptions,
|
||||
);
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ const getPlugin = async (
|
|||
editUrl: BaseEditUrl,
|
||||
...pluginOptions,
|
||||
},
|
||||
}) as PluginOptions,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ function getSampleTranslationFilesTranslated() {
|
|||
}
|
||||
|
||||
describe('getContentTranslationFiles', () => {
|
||||
it('returns translation files matching snapshot', async () => {
|
||||
it('returns translation files matching snapshot', () => {
|
||||
expect(getSampleTranslationFiles()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -44,7 +44,11 @@ const AuthorsMapSchema = Joi.object<AuthorsMap>()
|
|||
});
|
||||
|
||||
export function validateAuthorsMap(content: unknown): AuthorsMap {
|
||||
return Joi.attempt(content, AuthorsMapSchema);
|
||||
const {error, value} = AuthorsMapSchema.validate(content);
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export async function getAuthorsMap(params: {
|
||||
|
|
|
@ -264,7 +264,7 @@ async function processBlogSourceFile(
|
|||
const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
|
||||
const description = frontMatter.description ?? excerpt ?? '';
|
||||
|
||||
const slug = frontMatter.slug || parsedBlogFileName.slug;
|
||||
const slug = frontMatter.slug ?? parsedBlogFileName.slug;
|
||||
|
||||
const permalink = normalizeUrl([baseUrl, routeBasePath, slug]);
|
||||
|
||||
|
@ -323,7 +323,7 @@ async function processBlogSourceFile(
|
|||
defaultReadingTime,
|
||||
})
|
||||
: undefined,
|
||||
truncated: truncateMarker?.test(content) || false,
|
||||
truncated: truncateMarker.test(content),
|
||||
authors,
|
||||
frontMatter,
|
||||
},
|
||||
|
|
|
@ -176,10 +176,6 @@ export default async function pluginContentBlog(
|
|||
},
|
||||
|
||||
async contentLoaded({content: blogContents, actions}) {
|
||||
if (!blogContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
blogListComponent,
|
||||
blogPostComponent,
|
||||
|
@ -500,11 +496,7 @@ export default async function pluginContentBlog(
|
|||
},
|
||||
|
||||
injectHtmlTags({content}) {
|
||||
if (!content.blogPosts.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!options.feedOptions?.type) {
|
||||
if (!content.blogPosts.length || !options.feedOptions.type) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -34,5 +34,5 @@ export default function markdownLoader(
|
|||
finalContent = truncate(finalContent, markdownLoaderOptions.truncateMarker);
|
||||
}
|
||||
|
||||
return callback?.(null, finalContent);
|
||||
return callback(null, finalContent);
|
||||
}
|
||||
|
|
|
@ -136,9 +136,6 @@ export function validateOptions({
|
|||
validate,
|
||||
options,
|
||||
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
||||
const validatedOptions = validate(
|
||||
PluginOptionSchema,
|
||||
options,
|
||||
) as PluginOptions;
|
||||
const validatedOptions = validate(PluginOptionSchema, options);
|
||||
return validatedOptions;
|
||||
}
|
||||
|
|
|
@ -90,13 +90,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc1 title",
|
||||
},
|
||||
"id": "doc1",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
|
@ -106,13 +108,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc2 title",
|
||||
},
|
||||
"id": "doc2",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
|
@ -122,13 +126,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc3 title",
|
||||
},
|
||||
"id": "doc3",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
|
@ -138,13 +144,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc4 title",
|
||||
},
|
||||
"id": "doc4",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
|
@ -154,13 +162,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc5 title",
|
||||
},
|
||||
"id": "doc5",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
|
@ -232,13 +242,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc1 title",
|
||||
},
|
||||
"id": "doc1",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
|
@ -248,13 +260,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc2 title",
|
||||
},
|
||||
"id": "doc2",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
|
@ -264,13 +278,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc3 title",
|
||||
},
|
||||
"id": "doc3",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
|
@ -280,13 +296,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc4 title",
|
||||
},
|
||||
"id": "doc4",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
|
@ -296,13 +314,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc5 title",
|
||||
},
|
||||
"id": "doc5",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
|
@ -374,13 +394,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc1 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc1 title",
|
||||
},
|
||||
"id": "doc1",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc1 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc1 title",
|
||||
|
@ -390,13 +412,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc2 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc2 title",
|
||||
},
|
||||
"id": "doc2",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc2 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc2 title",
|
||||
|
@ -406,13 +430,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc3 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc3 title",
|
||||
},
|
||||
"id": "doc3",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc3 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc3 title",
|
||||
|
@ -422,13 +448,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc4 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc4 title",
|
||||
},
|
||||
"id": "doc4",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc4 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc4 title",
|
||||
|
@ -438,13 +466,15 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
|
|||
{
|
||||
"description": "doc5 description",
|
||||
"editUrl": "any",
|
||||
"frontMatter": {
|
||||
"sidebar_label": "doc5 title",
|
||||
},
|
||||
"id": "doc5",
|
||||
"lastUpdatedAt": 0,
|
||||
"lastUpdatedBy": "any",
|
||||
"next": undefined,
|
||||
"permalink": "any",
|
||||
"previous": undefined,
|
||||
"sidebar_label": "doc5 title",
|
||||
"slug": "any",
|
||||
"source": "any",
|
||||
"title": "doc5 title",
|
||||
|
|
Binary file not shown.
|
@ -119,7 +119,7 @@ function createTestUtils({
|
|||
|
||||
async function testSlug(docFileSource: string, expectedPermalink: string) {
|
||||
const docFile = await readDoc(docFileSource);
|
||||
const metadata = await processDocMetadata({
|
||||
const metadata = processDocMetadata({
|
||||
docFile,
|
||||
versionMetadata,
|
||||
context,
|
||||
|
|
|
@ -54,9 +54,9 @@ const createFakeActions = (contentDir: string) => {
|
|||
addRoute: (config: RouteConfig) => {
|
||||
routeConfigs.push(config);
|
||||
},
|
||||
createData: async (name: string, content: unknown) => {
|
||||
createData: (name: string, content: unknown) => {
|
||||
dataContainer[name] = content;
|
||||
return path.join(contentDir, name);
|
||||
return Promise.resolve(path.join(contentDir, name));
|
||||
},
|
||||
setGlobalData: (data: unknown) => {
|
||||
globalDataContainer.pluginName = {pluginId: data};
|
||||
|
|
|
@ -31,11 +31,11 @@ const defaultOptions = {
|
|||
};
|
||||
|
||||
describe('normalizeDocsPluginOptions', () => {
|
||||
it('returns default options for undefined user options', async () => {
|
||||
it('returns default options for undefined user options', () => {
|
||||
expect(testValidate({})).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
it('accepts correctly defined user options', async () => {
|
||||
it('accepts correctly defined user options', () => {
|
||||
const userOptions = {
|
||||
path: 'my-docs', // Path to data on filesystem, relative to site dir.
|
||||
routeBasePath: 'my-docs', // URL Route.
|
||||
|
@ -83,7 +83,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('accepts correctly defined remark and rehype plugin options', async () => {
|
||||
it('accepts correctly defined remark and rehype plugin options', () => {
|
||||
const userOptions = {
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
|
||||
|
@ -100,7 +100,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('accepts admonitions false', async () => {
|
||||
it('accepts admonitions false', () => {
|
||||
const admonitionsFalse = {
|
||||
admonitions: false,
|
||||
};
|
||||
|
@ -110,7 +110,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('rejects admonitions true', async () => {
|
||||
it('rejects admonitions true', () => {
|
||||
const admonitionsTrue = {
|
||||
admonitions: true,
|
||||
};
|
||||
|
|
|
@ -30,7 +30,9 @@ function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
|
|||
unversionedId: 'any',
|
||||
version: 'any',
|
||||
title: `${doc.id} title`,
|
||||
sidebar_label: `${doc.id} title`,
|
||||
frontMatter: {
|
||||
sidebar_label: `${doc.id} title`,
|
||||
},
|
||||
description: `${doc.id} description`,
|
||||
...doc,
|
||||
};
|
||||
|
@ -136,7 +138,7 @@ function getSampleTranslationFilesTranslated() {
|
|||
}
|
||||
|
||||
describe('getLoadedContentTranslationFiles', () => {
|
||||
it('returns translation files', async () => {
|
||||
it('returns translation files', () => {
|
||||
expect(getSampleTranslationFiles()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -126,6 +126,6 @@ export function getDocVersionSuggestions(
|
|||
const latestVersion = getLatestVersion(data);
|
||||
const activeDocContext = getActiveDocContext(data, pathname);
|
||||
const latestDocSuggestion: GlobalDoc | undefined =
|
||||
activeDocContext?.alternateDocVersions[latestVersion.name];
|
||||
activeDocContext.alternateDocVersions[latestVersion.name];
|
||||
return {latestDocSuggestion, latestVersionSuggestion: latestVersion};
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ const StableEmptyObject = {};
|
|||
// In blog-only mode, docs hooks are still used by the theme. We need a fail-
|
||||
// safe fallback when the docs plugin is not in use
|
||||
export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} =>
|
||||
(useAllPluginInstancesData('docusaurus-plugin-content-docs') as {
|
||||
[pluginId: string]: GlobalPluginData;
|
||||
}) ?? StableEmptyObject;
|
||||
(useAllPluginInstancesData('docusaurus-plugin-content-docs') as
|
||||
| {
|
||||
[pluginId: string]: GlobalPluginData;
|
||||
}
|
||||
| undefined) ?? StableEmptyObject;
|
||||
|
||||
export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
|
||||
usePluginData('docusaurus-plugin-content-docs', pluginId, {
|
||||
|
|
|
@ -143,7 +143,7 @@ export default async function pluginContentDocs(
|
|||
)}".`,
|
||||
);
|
||||
}
|
||||
async function processVersionDoc(docFile: DocFile) {
|
||||
function processVersionDoc(docFile: DocFile) {
|
||||
return processDocMetadata({
|
||||
docFile,
|
||||
versionMetadata,
|
||||
|
|
|
@ -16,5 +16,5 @@ export default function markdownLoader(
|
|||
const fileString = source;
|
||||
const callback = this.async();
|
||||
const options = this.getOptions();
|
||||
return callback?.(null, linkify(fileString, this.resourcePath, options));
|
||||
return callback(null, linkify(fileString, this.resourcePath, options));
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ export function validateOptions({
|
|||
}
|
||||
}
|
||||
|
||||
const normalizedOptions = validate(OptionsSchema, options) as PluginOptions;
|
||||
const normalizedOptions = validate(OptionsSchema, options);
|
||||
|
||||
if (normalizedOptions.admonitions) {
|
||||
normalizedOptions.remarkPlugins = normalizedOptions.remarkPlugins.concat([
|
||||
|
|
|
@ -51,7 +51,7 @@ Available document ids are:
|
|||
} = docMetadata;
|
||||
return {
|
||||
type: 'link',
|
||||
label: sidebarLabel || item.label || title,
|
||||
label: sidebarLabel ?? item.label ?? title,
|
||||
href: permalink,
|
||||
className: item.className,
|
||||
customProps:
|
||||
|
|
|
@ -463,7 +463,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
expect(sidebarSlice).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('throws for unknown index link', async () => {
|
||||
it('throws for unknown index link', () => {
|
||||
const generateSidebar = () =>
|
||||
DefaultSidebarItemsGenerator({
|
||||
numberPrefixParser: DefaultNumberPrefixParser,
|
||||
|
@ -499,7 +499,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
await expect(generateSidebar).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||
expect(() => generateSidebar()).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Can't find any doc with ID foo.
|
||||
Available doc IDs:
|
||||
- intro"
|
||||
|
|
|
@ -26,7 +26,7 @@ describe('processSidebars', () => {
|
|||
function createStaticSidebarItemGenerator(
|
||||
sidebarSlice: SidebarItem[],
|
||||
): SidebarItemsGenerator {
|
||||
return jest.fn(async () => sidebarSlice);
|
||||
return jest.fn(() => sidebarSlice);
|
||||
}
|
||||
|
||||
const StaticGeneratedSidebarSlice: NormalizedSidebar = [
|
||||
|
@ -40,7 +40,7 @@ describe('processSidebars', () => {
|
|||
// @ts-expect-error: good enough for this test
|
||||
const version: VersionMetadata = {
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/docs/1.0.0',
|
||||
path: '/docs/1.0.0',
|
||||
};
|
||||
|
||||
const params: SidebarProcessorParams = {
|
||||
|
|
|
@ -134,11 +134,11 @@ describe('createSidebarsUtils', () => {
|
|||
getFirstLink,
|
||||
} = createSidebarsUtils(sidebars);
|
||||
|
||||
it('getFirstDocIdOfFirstSidebar', async () => {
|
||||
it('getFirstDocIdOfFirstSidebar', () => {
|
||||
expect(getFirstDocIdOfFirstSidebar()).toBe('doc1');
|
||||
});
|
||||
|
||||
it('getSidebarNameByDocId', async () => {
|
||||
it('getSidebarNameByDocId', () => {
|
||||
expect(getSidebarNameByDocId('doc1')).toBe('sidebar1');
|
||||
expect(getSidebarNameByDocId('doc2')).toBe('sidebar1');
|
||||
expect(getSidebarNameByDocId('doc3')).toBe('sidebar2');
|
||||
|
@ -149,7 +149,7 @@ describe('createSidebarsUtils', () => {
|
|||
expect(getSidebarNameByDocId('unknown_id')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('getDocNavigation', async () => {
|
||||
it('getDocNavigation', () => {
|
||||
expect(getDocNavigation('doc1', 'doc1', undefined)).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previous: undefined,
|
||||
|
@ -229,7 +229,7 @@ describe('createSidebarsUtils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('getCategoryGeneratedIndexNavigation', async () => {
|
||||
it('getCategoryGeneratedIndexNavigation', () => {
|
||||
expect(
|
||||
getCategoryGeneratedIndexNavigation('/s3-subcategory-index-permalink'),
|
||||
).toMatchObject({
|
||||
|
@ -259,7 +259,7 @@ describe('createSidebarsUtils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('getCategoryGeneratedIndexList', async () => {
|
||||
it('getCategoryGeneratedIndexList', () => {
|
||||
expect(getCategoryGeneratedIndexList()).toMatchObject([
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -301,7 +301,7 @@ describe('createSidebarsUtils', () => {
|
|||
});
|
||||
|
||||
describe('collectSidebarDocItems', () => {
|
||||
it('can collect docs', async () => {
|
||||
it('can collect docs', () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -357,7 +357,7 @@ describe('collectSidebarDocItems', () => {
|
|||
});
|
||||
|
||||
describe('collectSidebarCategories', () => {
|
||||
it('can collect categories', async () => {
|
||||
it('can collect categories', () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -415,7 +415,7 @@ describe('collectSidebarCategories', () => {
|
|||
});
|
||||
|
||||
describe('collectSidebarLinks', () => {
|
||||
it('can collect links', async () => {
|
||||
it('can collect links', () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -453,7 +453,7 @@ describe('collectSidebarLinks', () => {
|
|||
});
|
||||
|
||||
describe('collectSidebarsDocIds', () => {
|
||||
it('can collect sidebars doc items', async () => {
|
||||
it('can collect sidebars doc items', () => {
|
||||
const sidebar1: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
@ -499,7 +499,7 @@ describe('collectSidebarsDocIds', () => {
|
|||
});
|
||||
|
||||
describe('transformSidebarItems', () => {
|
||||
it('can transform sidebar items', async () => {
|
||||
it('can transform sidebar items', () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
|
|
|
@ -9,7 +9,7 @@ import {validateSidebars, validateCategoryMetadataFile} from '../validation';
|
|||
import type {SidebarsConfig, CategoryMetadataFile} from '../types';
|
||||
|
||||
describe('validateSidebars', () => {
|
||||
it('throw for bad value', async () => {
|
||||
it('throw for bad value', () => {
|
||||
expect(() => validateSidebars({sidebar: [{type: 42}]}))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
|
@ -21,12 +21,12 @@ describe('validateSidebars', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('accept empty object', async () => {
|
||||
it('accept empty object', () => {
|
||||
const sidebars: SidebarsConfig = {};
|
||||
validateSidebars(sidebars);
|
||||
});
|
||||
|
||||
it('accept valid values', async () => {
|
||||
it('accept valid values', () => {
|
||||
const sidebars: SidebarsConfig = {
|
||||
sidebar1: [
|
||||
{type: 'doc', id: 'doc1'},
|
||||
|
@ -207,7 +207,7 @@ describe('validateSidebars', () => {
|
|||
).toThrowErrorMatchingInlineSnapshot(`"sidebar.forEach is not a function"`);
|
||||
});
|
||||
|
||||
it('sidebars item doc but id is not a string', async () => {
|
||||
it('sidebars item doc but id is not a string', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
|
@ -267,18 +267,18 @@ describe('validateSidebars', () => {
|
|||
describe('validateCategoryMetadataFile', () => {
|
||||
// TODO add more tests
|
||||
|
||||
it('throw for bad value', async () => {
|
||||
it('throw for bad value', () => {
|
||||
expect(() =>
|
||||
validateCategoryMetadataFile(42),
|
||||
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
|
||||
});
|
||||
|
||||
it('accept empty object', async () => {
|
||||
it('accept empty object', () => {
|
||||
const content: CategoryMetadataFile = {};
|
||||
expect(validateCategoryMetadataFile(content)).toEqual(content);
|
||||
});
|
||||
|
||||
it('accept valid values', async () => {
|
||||
it('accept valid values', () => {
|
||||
const content: CategoryMetadataFile = {
|
||||
className: 'className',
|
||||
label: 'Category Label',
|
||||
|
@ -295,7 +295,7 @@ describe('validateCategoryMetadataFile', () => {
|
|||
expect(validateCategoryMetadataFile(content)).toEqual(content);
|
||||
});
|
||||
|
||||
it('rejects permalink', async () => {
|
||||
it('rejects permalink', () => {
|
||||
const content: CategoryMetadataFile = {
|
||||
className: 'className',
|
||||
label: 'Category Label',
|
||||
|
|
|
@ -46,7 +46,7 @@ type Dir = {
|
|||
};
|
||||
|
||||
// Comment for this feature: https://github.com/facebook/docusaurus/issues/3464#issuecomment-818670449
|
||||
export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
||||
export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = ({
|
||||
numberPrefixParser,
|
||||
isCategoryIndex,
|
||||
docs: allDocs,
|
||||
|
|
|
@ -84,7 +84,7 @@ function postProcessSidebarItem(
|
|||
};
|
||||
}
|
||||
// A non-collapsible category can't be collapsed!
|
||||
if (category.collapsible === false) {
|
||||
if (!category.collapsible) {
|
||||
category.collapsed = false;
|
||||
}
|
||||
return category;
|
||||
|
|
|
@ -251,7 +251,7 @@ export type SidebarItemsGeneratorArgs = {
|
|||
};
|
||||
export type SidebarItemsGenerator = (
|
||||
generatorArgs: SidebarItemsGeneratorArgs,
|
||||
) => Promise<NormalizedSidebar>;
|
||||
) => NormalizedSidebar | Promise<NormalizedSidebar>;
|
||||
|
||||
export type SidebarItemsGeneratorOption = (
|
||||
generatorArgs: {
|
||||
|
@ -262,7 +262,7 @@ export type SidebarItemsGeneratorOption = (
|
|||
*/
|
||||
defaultSidebarItemsGenerator: SidebarItemsGenerator;
|
||||
} & SidebarItemsGeneratorArgs,
|
||||
) => Promise<NormalizedSidebarItem[]>;
|
||||
) => NormalizedSidebar | Promise<NormalizedSidebar>;
|
||||
|
||||
export type SidebarProcessorParams = {
|
||||
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
||||
|
|
|
@ -257,7 +257,7 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils {
|
|||
): boolean {
|
||||
return (
|
||||
item.type === 'category' &&
|
||||
item.link?.type === 'generated-index' &&
|
||||
item.link.type === 'generated-index' &&
|
||||
item.link.permalink === categoryGeneratedIndexPermalink
|
||||
);
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ function validateSidebarItem(
|
|||
// manually
|
||||
Joi.assert(item, sidebarItemSchema);
|
||||
|
||||
if ((item as NormalizedSidebarItemCategory).type === 'category') {
|
||||
if ((item as NormalizedSidebarItem).type === 'category') {
|
||||
(item as NormalizedSidebarItemCategory).items.forEach(validateSidebarItem);
|
||||
}
|
||||
}
|
||||
|
@ -170,5 +170,9 @@ const categoryMetadataFileSchema = Joi.object<CategoryMetadataFile>({
|
|||
export function validateCategoryMetadataFile(
|
||||
unsafeContent: unknown,
|
||||
): CategoryMetadataFile {
|
||||
return Joi.attempt(unsafeContent, categoryMetadataFileSchema);
|
||||
const {error, value} = categoryMetadataFileSchema.validate(unsafeContent);
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ export default function getSlug({
|
|||
) {
|
||||
return dirNameSlug;
|
||||
}
|
||||
const baseSlug = frontMatterSlug || baseID;
|
||||
const baseSlug = frontMatterSlug ?? baseID;
|
||||
return resolvePathname(baseSlug, getDirNameSlug());
|
||||
}
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ describe('readVersionsMetadata', () => {
|
|||
context: defaultContext,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Versions should be strings. Found type "number" for version "1.1"."`,
|
||||
`"Versions should be strings. Found type "number" for version 1.1."`,
|
||||
);
|
||||
jsonMock.mockImplementationOnce(() => [' ']);
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ import type {VersionsOptions} from '@docusaurus/plugin-content-docs';
|
|||
export function validateVersionName(name: unknown): asserts name is string {
|
||||
if (typeof name !== 'string') {
|
||||
throw new Error(
|
||||
`Versions should be strings. Found type "${typeof name}" for version "${name}".`,
|
||||
`Versions should be strings. Found type "${typeof name}" for version ${JSON.stringify(
|
||||
name,
|
||||
)}.`,
|
||||
);
|
||||
}
|
||||
if (!name.trim()) {
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('docusaurus-plugin-content-pages', () => {
|
|||
it('loads simple pages', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentPages(
|
||||
const plugin = pluginContentPages(
|
||||
context,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
|
@ -33,7 +33,7 @@ describe('docusaurus-plugin-content-pages', () => {
|
|||
it('loads simple pages with french translations', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentPages(
|
||||
const plugin = pluginContentPages(
|
||||
{
|
||||
...context,
|
||||
i18n: {
|
||||
|
|
|
@ -39,10 +39,10 @@ export function getContentPathList(contentPaths: PagesContentPaths): string[] {
|
|||
const isMarkdownSource = (source: string) =>
|
||||
source.endsWith('.md') || source.endsWith('.mdx');
|
||||
|
||||
export default async function pluginContentPages(
|
||||
export default function pluginContentPages(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Promise<Plugin<LoadedContent | null>> {
|
||||
): Plugin<LoadedContent | null> {
|
||||
if (options.admonitions) {
|
||||
options.remarkPlugins = options.remarkPlugins.concat([
|
||||
[admonitions, options.admonitions],
|
||||
|
|
|
@ -18,5 +18,5 @@ export default function markdownLoader(
|
|||
// TODO provide additional md processing here? like interlinking pages?
|
||||
// fileString = linkify(fileString)
|
||||
|
||||
return callback?.(null, fileString);
|
||||
return callback(null, fileString);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
admonitions: {},
|
||||
};
|
||||
|
||||
const PluginOptionSchema = Joi.object({
|
||||
const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
routeBasePath: Joi.string().default(DEFAULT_OPTIONS.routeBasePath),
|
||||
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
||||
|
|
|
@ -20,7 +20,7 @@ export default function DebugMetadata(): JSX.Element {
|
|||
</div>
|
||||
<div>
|
||||
Site Version:{' '}
|
||||
<code>{siteMetadata.siteVersion || 'No version specified'}</code>
|
||||
<code>{siteMetadata.siteVersion ?? 'No version specified'}</code>
|
||||
</div>
|
||||
<h3 className={styles.sectionTitle}>Plugins and themes</h3>
|
||||
<ul className="clean-list">
|
||||
|
|
|
@ -25,7 +25,7 @@ export default function pluginGoogleGtag(
|
|||
return {
|
||||
name: 'docusaurus-plugin-google-gtag',
|
||||
|
||||
async contentLoaded({actions}) {
|
||||
contentLoaded({actions}) {
|
||||
actions.setGlobalData(options);
|
||||
},
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ export function validateOptions({
|
|||
validate,
|
||||
options,
|
||||
}: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions {
|
||||
const pluginOptionsSchema = Joi.object({
|
||||
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
||||
disableInDev: Joi.boolean().default(true),
|
||||
}).unknown();
|
||||
return validate(pluginOptionsSchema, options);
|
||||
|
|
|
@ -22,9 +22,9 @@ function bytesToSize(bytes: number) {
|
|||
}
|
||||
const scale = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
if (scale === 0) {
|
||||
return `${bytes} ${sizes[scale]}`;
|
||||
return `${bytes} ${sizes[scale]!}`;
|
||||
}
|
||||
return `${(bytes / 1024 ** scale).toFixed(1)} ${sizes[scale]}`;
|
||||
return `${(bytes / 1024 ** scale).toFixed(1)} ${sizes[scale]!}`;
|
||||
}
|
||||
|
||||
// Adopted from https://github.com/endiliey/react-ideal-image/blob/master/src/components/IdealImage/index.js#L43-L75
|
||||
|
@ -100,8 +100,8 @@ export default function IdealImage(props: Props): JSX.Element {
|
|||
{...props}
|
||||
alt={alt}
|
||||
className={className}
|
||||
height={img.src.height || 100}
|
||||
width={img.src.width || 100}
|
||||
height={img.src.height ?? 100}
|
||||
width={img.src.width ?? 100}
|
||||
placeholder={{lqip: img.preSrc}}
|
||||
src={img.src.src}
|
||||
srcSet={img.src.images.map((image) => ({
|
||||
|
|
|
@ -89,7 +89,7 @@ export default function pluginPWA(
|
|||
new webpack.EnvironmentPlugin({
|
||||
PWA_DEBUG: debug,
|
||||
PWA_SERVICE_WORKER_URL: path.posix.resolve(
|
||||
`${config.output?.publicPath || '/'}`,
|
||||
`${(config.output?.publicPath as string) || '/'}`,
|
||||
'sw.js',
|
||||
),
|
||||
PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES:
|
||||
|
@ -102,7 +102,7 @@ export default function pluginPWA(
|
|||
|
||||
injectHtmlTags() {
|
||||
const headTags: HtmlTags = [];
|
||||
if (isProd && pwaHead) {
|
||||
if (isProd) {
|
||||
pwaHead.forEach(({tagName, ...attributes}) => {
|
||||
(['href', 'content'] as const).forEach((attribute) => {
|
||||
const attributeValue = attributes[attribute];
|
||||
|
@ -160,7 +160,7 @@ export default function pluginPWA(
|
|||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
// Fallback value required with Webpack 5
|
||||
PWA_SW_CUSTOM: swCustom || '',
|
||||
PWA_SW_CUSTOM: swCustom ?? '',
|
||||
}),
|
||||
new LogPlugin({
|
||||
name: 'Service Worker',
|
||||
|
@ -189,7 +189,7 @@ export default function pluginPWA(
|
|||
'**/*.{png,jpg,jpeg,gif,svg,ico}',
|
||||
'**/*.{woff,woff2,eot,ttf,otf}',
|
||||
// @ts-expect-error: internal API?
|
||||
...(injectManifest.globPatterns ?? []),
|
||||
...((injectManifest.globPatterns as string[] | undefined) ?? []),
|
||||
],
|
||||
// Those attributes are not overrideable
|
||||
swDest,
|
||||
|
|
|
@ -23,7 +23,7 @@ const DEFAULT_OPTIONS = {
|
|||
reloadPopup: '@theme/PwaReloadPopup',
|
||||
};
|
||||
|
||||
const Schema = Joi.object({
|
||||
const optionsSchema = Joi.object<PluginOptions>({
|
||||
debug: Joi.bool().default(DEFAULT_OPTIONS.debug),
|
||||
offlineModeActivationStrategies: Joi.array()
|
||||
.items(
|
||||
|
@ -58,5 +58,5 @@ export function validateOptions({
|
|||
validate,
|
||||
options,
|
||||
}: OptionValidationContext<PluginOptions, PluginOptions>): PluginOptions {
|
||||
return validate(Schema, options);
|
||||
return validate(optionsSchema, options);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import {createStorageSlot} from '@docusaurus/theme-common';
|
|||
|
||||
// First: read the env variables (provided by Webpack)
|
||||
/* eslint-disable prefer-destructuring */
|
||||
const PWA_SERVICE_WORKER_URL = process.env.PWA_SERVICE_WORKER_URL;
|
||||
const PWA_SERVICE_WORKER_URL = process.env.PWA_SERVICE_WORKER_URL!;
|
||||
const PWA_RELOAD_POPUP = process.env.PWA_RELOAD_POPUP;
|
||||
const PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES = process.env
|
||||
.PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES as unknown as (keyof typeof OfflineModeActivationStrategiesImplementations)[];
|
||||
|
@ -34,7 +34,7 @@ async function clearRegistrations() {
|
|||
}
|
||||
await Promise.all(
|
||||
registrations.map(async (registration) => {
|
||||
const result = await registration?.unregister();
|
||||
const result = await registration.unregister();
|
||||
if (debug) {
|
||||
console.log(
|
||||
`[Docusaurus-PWA][registerSw]: unregister() service worker registration`,
|
||||
|
@ -69,7 +69,7 @@ async function isAppInstalledEventFired() {
|
|||
declare global {
|
||||
interface Navigator {
|
||||
getInstalledRelatedApps: () => Promise<{platform: string}[]>;
|
||||
connection: {effectiveType: string; saveData: boolean};
|
||||
connection?: {effectiveType: string; saveData: boolean};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
ignorePatterns: [],
|
||||
};
|
||||
|
||||
const PluginOptionSchema = Joi.object({
|
||||
const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
// @ts-expect-error: forbidden
|
||||
cacheTime: Joi.forbidden().messages({
|
||||
'any.unknown':
|
||||
'Option `cacheTime` in sitemap config is deprecated. Please remove it.',
|
||||
|
|
|
@ -62,8 +62,8 @@ const nodeForImport: Literal = {
|
|||
const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
|
||||
const {sync = false} = options;
|
||||
return (root) => {
|
||||
let transformed = false;
|
||||
let alreadyImported = false;
|
||||
let transformed = false as boolean;
|
||||
let alreadyImported = false as boolean;
|
||||
visit(root, (node: Node) => {
|
||||
if (isImport(node) && node.value.includes('@theme/Tabs')) {
|
||||
alreadyImported = true;
|
||||
|
|
|
@ -177,7 +177,7 @@ export default function themeClassic(
|
|||
const plugin: PostCssPlugin = {
|
||||
postcssPlugin: 'RtlCssPlugin',
|
||||
prepare: (result) => {
|
||||
const file = result.root?.source?.input?.file;
|
||||
const file = result.root.source?.input.file;
|
||||
// Skip Infima as we are using the its RTL version.
|
||||
if (file === resolvedInfimaFile) {
|
||||
return {};
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
// in their tsconfig.
|
||||
|
||||
declare module '@docusaurus/theme-classic' {
|
||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||
import type {LoadContext, Plugin, PluginModule} from '@docusaurus/types';
|
||||
|
||||
export type Options = {
|
||||
customCss?: string | string[];
|
||||
};
|
||||
|
||||
export const getSwizzleConfig: PluginModule['getSwizzleConfig'];
|
||||
|
||||
export default function themeClassic(
|
||||
context: LoadContext,
|
||||
options: Options,
|
||||
|
|
|
@ -52,7 +52,7 @@ export default function CodeBlockString({
|
|||
magicComments,
|
||||
});
|
||||
const showLineNumbers =
|
||||
showLineNumbersProp || containsLineNumbers(metastring);
|
||||
showLineNumbersProp ?? containsLineNumbers(metastring);
|
||||
|
||||
return (
|
||||
<Container
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function DocSidebarItemHtml({
|
|||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemLink,
|
||||
ThemeClassNames.docs.docSidebarItemLinkLevel(level),
|
||||
defaultStyle && `${styles.menuHtmlItem} menu__list-item`,
|
||||
defaultStyle && [styles.menuHtmlItem, 'menu__list-item'],
|
||||
className,
|
||||
)}
|
||||
key={index}
|
||||
|
|
|
@ -21,7 +21,7 @@ function ColumnLinkItem({item}: {item: ColumnItemType}) {
|
|||
dangerouslySetInnerHTML={{__html: item.html}}
|
||||
/>
|
||||
) : (
|
||||
<li key={item.href || item.to} className="footer__item">
|
||||
<li key={item.href ?? item.to} className="footer__item">
|
||||
<LinkItem item={item} />
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -27,7 +27,7 @@ export function useCollapsible({
|
|||
initialState,
|
||||
}: {
|
||||
/** The initial state. Will be non-collapsed by default. */
|
||||
initialState: boolean | (() => boolean);
|
||||
initialState?: boolean | (() => boolean);
|
||||
}): {
|
||||
collapsed: boolean;
|
||||
setCollapsed: Dispatch<SetStateAction<boolean>>;
|
||||
|
|
|
@ -40,7 +40,7 @@ export function useSkipToContent(): {
|
|||
e.preventDefault();
|
||||
|
||||
const targetElement: HTMLElement | null =
|
||||
document.querySelector('main:first-of-type') ||
|
||||
document.querySelector('main:first-of-type') ??
|
||||
document.querySelector(`.${ThemeClassNames.wrapper.main}`);
|
||||
|
||||
if (targetElement) {
|
||||
|
|
|
@ -38,15 +38,12 @@ function getAnchors({
|
|||
}: {
|
||||
minHeadingLevel: number;
|
||||
maxHeadingLevel: number;
|
||||
}) {
|
||||
}): HTMLElement[] {
|
||||
const selectors = [];
|
||||
for (let i = minHeadingLevel; i <= maxHeadingLevel; i += 1) {
|
||||
selectors.push(`h${i}.anchor`);
|
||||
}
|
||||
|
||||
return Array.from(
|
||||
document.querySelectorAll(selectors.join()),
|
||||
) as HTMLElement[];
|
||||
return Array.from(document.querySelectorAll(selectors.join()));
|
||||
}
|
||||
|
||||
function getActiveAnchor(
|
||||
|
|
|
@ -171,7 +171,7 @@ export function parseLines(
|
|||
const metastringRangeClassName = magicComments[0]!.className;
|
||||
const lines = rangeParser(linesRange)
|
||||
.filter((n) => n > 0)
|
||||
.map((n) => [n - 1, [metastringRangeClassName]]);
|
||||
.map((n) => [n - 1, [metastringRangeClassName]] as [number, string[]]);
|
||||
return {lineClassNames: Object.fromEntries(lines), code};
|
||||
}
|
||||
if (language === undefined) {
|
||||
|
@ -189,7 +189,7 @@ export function parseLines(
|
|||
const lineToClassName: {[comment: string]: string} = Object.fromEntries(
|
||||
magicComments
|
||||
.filter((d) => d.line)
|
||||
.map(({className, line}) => [line, className]),
|
||||
.map(({className, line}) => [line!, className] as [string, string]),
|
||||
);
|
||||
const blockStartToClassName: {[comment: string]: string} = Object.fromEntries(
|
||||
magicComments
|
||||
|
|
|
@ -70,7 +70,7 @@ export class ReactContextError extends Error {
|
|||
this.name = 'ReactContextError';
|
||||
this.message = `Hook ${
|
||||
this.stack?.split('\n')[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups!
|
||||
.name
|
||||
.name ?? ''
|
||||
} is called outside the <${providerName}>. ${additionalInfo || ''}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export function isSamePath(
|
|||
path2: string | undefined,
|
||||
): boolean {
|
||||
const normalize = (pathname: string | undefined) =>
|
||||
(!pathname || pathname?.endsWith('/')
|
||||
(!pathname || pathname.endsWith('/')
|
||||
? pathname
|
||||
: `${pathname}/`
|
||||
)?.toLowerCase();
|
||||
|
|
|
@ -112,11 +112,7 @@ export function useScrollPosition(
|
|||
return;
|
||||
}
|
||||
const currentPosition = getScrollPosition()!;
|
||||
|
||||
if (dynamicEffect) {
|
||||
dynamicEffect(currentPosition, lastPositionRef.current);
|
||||
}
|
||||
|
||||
dynamicEffect(currentPosition, lastPositionRef.current);
|
||||
lastPositionRef.current = currentPosition;
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export function useContextualSearchFilters(): {locale: string; tags: string[]} {
|
|||
// plugin instances.
|
||||
function getDocPluginTags(pluginId: string) {
|
||||
const activeVersion =
|
||||
activePluginAndVersion?.activePlugin?.pluginId === pluginId
|
||||
activePluginAndVersion?.activePlugin.pluginId === pluginId
|
||||
? activePluginAndVersion.activeVersion
|
||||
: undefined;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ function treeifyTOC(flatTOC: readonly TOCItem[]): TOCTreeNode[] {
|
|||
// level <i>. We will modify these indices as we iterate through all headings.
|
||||
// e.g. if an ### H3 was last seen at index 2, then prevIndexForLevel[3] === 2
|
||||
// indices 0 and 1 will remain unused.
|
||||
const prevIndexForLevel = Array(7).fill(-1);
|
||||
const prevIndexForLevel = Array<number>(7).fill(-1);
|
||||
|
||||
headings.forEach((curr, currIndex) => {
|
||||
// Take the last seen index for each ancestor level. the highest index will
|
||||
|
|
|
@ -95,7 +95,11 @@ function selectPluralMessage(
|
|||
}
|
||||
if (parts.length > localePluralForms.pluralForms.length) {
|
||||
console.error(
|
||||
`For locale=${localePluralForms.locale}, a maximum of ${localePluralForms.pluralForms.length} plural forms are expected (${localePluralForms.pluralForms}), but the message contains ${parts.length}: ${pluralMessages}`,
|
||||
`For locale=${localePluralForms.locale}, a maximum of ${
|
||||
localePluralForms.pluralForms.length
|
||||
} plural forms are expected (${localePluralForms.pluralForms.join(
|
||||
',',
|
||||
)}), but the message contains ${parts.length}: ${pluralMessages}`,
|
||||
);
|
||||
}
|
||||
const pluralForm = localePluralForms.select(count);
|
||||
|
|
|
@ -15,7 +15,7 @@ export const DEFAULT_CONFIG = {
|
|||
playgroundPosition: 'bottom',
|
||||
};
|
||||
|
||||
export const Schema = Joi.object({
|
||||
export const Schema = Joi.object<ThemeConfig>({
|
||||
liveCodeBlock: Joi.object({
|
||||
playgroundPosition: Joi.string()
|
||||
.equal('top', 'bottom')
|
||||
|
|
|
@ -60,7 +60,7 @@ export default function themeSearchAlgolia(context: LoadContext): Plugin<void> {
|
|||
});
|
||||
},
|
||||
|
||||
async contentLoaded({actions: {addRoute}}) {
|
||||
contentLoaded({actions: {addRoute}}) {
|
||||
if (searchPagePath) {
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, searchPagePath]),
|
||||
|
|
|
@ -20,7 +20,7 @@ export const DEFAULT_CONFIG = {
|
|||
searchPagePath: 'search',
|
||||
};
|
||||
|
||||
export const Schema = Joi.object({
|
||||
export const Schema = Joi.object<ThemeConfig>({
|
||||
algolia: Joi.object({
|
||||
// Docusaurus attributes
|
||||
contextualSearch: Joi.boolean().default(DEFAULT_CONFIG.contextualSearch),
|
||||
|
|
|
@ -25,9 +25,9 @@ export function codeTranslationLocalesToTry(locale: string): string[] {
|
|||
// unresolved except for simply locales
|
||||
locale,
|
||||
// "zh-CN" / "pt-BR"
|
||||
`${maximizedLocale.language}-${maximizedLocale.region}`,
|
||||
`${maximizedLocale.language!}-${maximizedLocale.region!}`,
|
||||
// "zh-Hans" / "pt-Latn"
|
||||
`${maximizedLocale.language}-${maximizedLocale.script}`,
|
||||
`${maximizedLocale.language!}-${maximizedLocale.script!}`,
|
||||
// "zh" / "pt"
|
||||
maximizedLocale.language!,
|
||||
];
|
||||
|
|
|
@ -28,4 +28,4 @@ const JoiFrontMatterString: Joi.Extension = {
|
|||
* @see https://github.com/facebook/docusaurus/issues/4642
|
||||
* @see https://github.com/sideway/joi/issues/1442#issuecomment-823997884
|
||||
*/
|
||||
export const JoiFrontMatter: typeof Joi = Joi.extend(JoiFrontMatterString);
|
||||
export const JoiFrontMatter = Joi.extend(JoiFrontMatterString) as typeof Joi;
|
||||
|
|
|
@ -56,7 +56,7 @@ export function shortName(str: string): string {
|
|||
* Adopted from https://github.com/sindresorhus/slash/blob/main/index.js
|
||||
*/
|
||||
export function posixPath(str: string): string {
|
||||
const isExtendedLengthPath = /^\\\\\?\\/.test(str);
|
||||
const isExtendedLengthPath = str.startsWith('\\\\?\\');
|
||||
|
||||
// Forward slashes are only valid Windows paths when they don't contain non-
|
||||
// ascii characters.
|
||||
|
|
|
@ -72,11 +72,11 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|||
/^\/+/,
|
||||
// Special case where the first element of rawUrls is empty
|
||||
// ["", "/hello"] => /hello
|
||||
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
||||
component.startsWith('/') && !hasStartingSlash ? '/' : '',
|
||||
);
|
||||
}
|
||||
|
||||
hasEndingSlash = component[component.length - 1] === '/';
|
||||
hasEndingSlash = component.endsWith('/');
|
||||
// Removing the ending slashes for each component but the last. For the
|
||||
// last component we will combine multiple slashes to a single one.
|
||||
component = component.replace(/\/+$/, i < urls.length - 1 ? '' : '/');
|
||||
|
@ -95,7 +95,7 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|||
|
||||
// Replace ? in parameters with &.
|
||||
const parts = str.split('?');
|
||||
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
||||
str = parts.shift()! + (parts.length > 0 ? '?' : '') + parts.join('&');
|
||||
|
||||
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
||||
str = str.replace(/(?<textBefore>[^:/]\/)\/+/g, '$1');
|
||||
|
|
|
@ -19,7 +19,7 @@ declare global {
|
|||
// eslint-disable-next-line camelcase, no-underscore-dangle
|
||||
const __webpack_require__: {gca: (name: string) => string};
|
||||
interface Navigator {
|
||||
connection: {effectiveType: string; saveData: boolean};
|
||||
connection?: {effectiveType: string; saveData: boolean};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {hasProtocol} from './isInternalUrl';
|
|||
import type {BaseUrlOptions, BaseUrlUtils} from '@docusaurus/useBaseUrl';
|
||||
|
||||
function addBaseUrl(
|
||||
siteUrl: string | undefined,
|
||||
siteUrl: string,
|
||||
baseUrl: string,
|
||||
url: string,
|
||||
{forcePrependBaseUrl = false, absolute = false}: BaseUrlOptions = {},
|
||||
|
|
|
@ -66,7 +66,7 @@ export async function serve(
|
|||
|
||||
// Remove baseUrl before calling serveHandler, because /baseUrl/ should
|
||||
// serve /build/index.html, not /build/baseUrl/index.html (does not exist)
|
||||
req.url = req.url?.replace(baseUrl, '/');
|
||||
req.url = req.url.replace(baseUrl, '/');
|
||||
|
||||
serveHandler(req, res, {
|
||||
cleanUrls: true,
|
||||
|
|
|
@ -9,14 +9,14 @@ import {normalizeSwizzleConfig} from '../config';
|
|||
import type {SwizzleConfig} from '@docusaurus/types';
|
||||
|
||||
describe('normalizeSwizzleConfig', () => {
|
||||
it(`validate no components config`, async () => {
|
||||
it(`validate no components config`, () => {
|
||||
const config: SwizzleConfig = {
|
||||
components: {},
|
||||
};
|
||||
expect(normalizeSwizzleConfig(config)).toEqual(config);
|
||||
});
|
||||
|
||||
it(`validate complete config`, async () => {
|
||||
it(`validate complete config`, () => {
|
||||
const config: SwizzleConfig = {
|
||||
components: {
|
||||
SomeComponent: {
|
||||
|
@ -38,7 +38,7 @@ describe('normalizeSwizzleConfig', () => {
|
|||
expect(normalizeSwizzleConfig(config)).toEqual(config);
|
||||
});
|
||||
|
||||
it(`normalize partial config`, async () => {
|
||||
it(`normalize partial config`, () => {
|
||||
const config: SwizzleConfig = {
|
||||
components: {
|
||||
SomeComponent: {
|
||||
|
@ -59,7 +59,7 @@ describe('normalizeSwizzleConfig', () => {
|
|||
expect(normalizeSwizzleConfig(config)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it(`reject missing components`, async () => {
|
||||
it(`reject missing components`, () => {
|
||||
// @ts-expect-error: incomplete actions map
|
||||
const config: SwizzleConfig = {};
|
||||
|
||||
|
@ -70,7 +70,7 @@ describe('normalizeSwizzleConfig', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it(`reject invalid action name`, async () => {
|
||||
it(`reject invalid action name`, () => {
|
||||
const config: SwizzleConfig = {
|
||||
components: {
|
||||
MyComponent: {
|
||||
|
@ -91,7 +91,7 @@ describe('normalizeSwizzleConfig', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it(`reject invalid action status`, async () => {
|
||||
it(`reject invalid action status`, () => {
|
||||
const config: SwizzleConfig = {
|
||||
components: {
|
||||
MyComponent: {
|
||||
|
|
|
@ -109,7 +109,7 @@ export async function wrap({
|
|||
const isDirectory = await isDir(path.join(themePath, themeComponentName));
|
||||
|
||||
// Top/Parent/ComponentName => ComponentName
|
||||
const componentName = _.last(themeComponentName.split('/'));
|
||||
const componentName = _.last(themeComponentName.split('/'))!;
|
||||
const wrapperComponentName = `${componentName}Wrapper`;
|
||||
|
||||
const wrapperFileName = `${themeComponentName}${isDirectory ? '/index' : ''}${
|
||||
|
|
|
@ -16,9 +16,8 @@ function getModuleSwizzleConfig(
|
|||
swizzlePlugin: SwizzlePlugin,
|
||||
): SwizzleConfig | undefined {
|
||||
const getSwizzleConfig =
|
||||
swizzlePlugin.plugin.plugin?.getSwizzleConfig ??
|
||||
swizzlePlugin.plugin.pluginModule?.module.getSwizzleConfig ??
|
||||
swizzlePlugin.plugin.pluginModule?.module?.getSwizzleConfig;
|
||||
swizzlePlugin.plugin.plugin.getSwizzleConfig ??
|
||||
swizzlePlugin.plugin.pluginModule?.module.getSwizzleConfig;
|
||||
|
||||
if (getSwizzleConfig) {
|
||||
return getSwizzleConfig();
|
||||
|
@ -26,9 +25,8 @@ function getModuleSwizzleConfig(
|
|||
|
||||
// TODO deprecate getSwizzleComponentList later
|
||||
const getSwizzleComponentList =
|
||||
swizzlePlugin.plugin.plugin?.getSwizzleComponentList ??
|
||||
swizzlePlugin.plugin.pluginModule?.module.getSwizzleComponentList ??
|
||||
swizzlePlugin.plugin.pluginModule?.module?.getSwizzleComponentList;
|
||||
swizzlePlugin.plugin.plugin.getSwizzleComponentList ??
|
||||
swizzlePlugin.plugin.pluginModule?.module.getSwizzleComponentList;
|
||||
|
||||
if (getSwizzleComponentList) {
|
||||
const safeComponents = getSwizzleComponentList() ?? [];
|
||||
|
|
|
@ -15,7 +15,7 @@ import {findStringIgnoringCase, type SwizzlePlugin} from './common';
|
|||
export function pluginToThemeName(plugin: SwizzlePlugin): string | undefined {
|
||||
if (plugin.instance.getThemePath) {
|
||||
return (
|
||||
(plugin.instance.version as {name: string}).name ?? plugin.instance.name
|
||||
(plugin.instance.version as {name?: string}).name ?? plugin.instance.name
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
|
@ -76,9 +76,7 @@ function handleInvalidThemeName({
|
|||
// TODO recover from short theme-names here: "classic" => "@docusaurus/theme-classic"
|
||||
|
||||
// No recovery value is possible: print error
|
||||
const suggestion = themeNames.find(
|
||||
(name) => leven(name, themeNameParam!) < 4,
|
||||
);
|
||||
const suggestion = themeNames.find((name) => leven(name, themeNameParam) < 4);
|
||||
logger.error`Theme name=${themeNameParam} not found. ${
|
||||
suggestion
|
||||
? logger.interpolate`Did you mean name=${suggestion}?`
|
||||
|
@ -87,13 +85,13 @@ function handleInvalidThemeName({
|
|||
return process.exit(1);
|
||||
}
|
||||
|
||||
async function validateThemeName({
|
||||
function validateThemeName({
|
||||
themeNameParam,
|
||||
themeNames,
|
||||
}: {
|
||||
themeNameParam: string;
|
||||
themeNames: string[];
|
||||
}): Promise<string> {
|
||||
}): string {
|
||||
const isValidName = themeNames.includes(themeNameParam);
|
||||
if (!isValidName) {
|
||||
return handleInvalidThemeName({
|
||||
|
|
|
@ -37,12 +37,12 @@ async function transformMarkdownFile(
|
|||
async function getPathsToWatch(siteDir: string): Promise<string[]> {
|
||||
const context = await loadContext({siteDir});
|
||||
const plugins = await initPlugins(context);
|
||||
return plugins.flatMap((plugin) => plugin?.getPathsToWatch?.() ?? []);
|
||||
return plugins.flatMap((plugin) => plugin.getPathsToWatch?.() ?? []);
|
||||
}
|
||||
|
||||
export async function writeHeadingIds(
|
||||
siteDir: string,
|
||||
files: string[],
|
||||
files: string[] | undefined,
|
||||
options: WriteHeadingIDOptions,
|
||||
): Promise<void> {
|
||||
const markdownFiles = await safeGlobby(
|
||||
|
|
4
packages/docusaurus/src/deps.d.ts
vendored
4
packages/docusaurus/src/deps.d.ts
vendored
|
@ -20,13 +20,13 @@ declare module 'react-loadable-ssr-addon-v5-slorber' {
|
|||
export type Manifest = {
|
||||
entrypoints: string[];
|
||||
origins: {[key: string]: number[]};
|
||||
assets: Array<{[key: string]: Asset[]}>;
|
||||
assets: {[key: string]: Asset[]}[];
|
||||
};
|
||||
|
||||
export function getBundles(
|
||||
manifest: Manifest,
|
||||
modulesToBeLoaded: string[],
|
||||
): {js: Asset[]; css: Asset[]};
|
||||
): {js?: Asset[]; css?: Asset[]};
|
||||
|
||||
export default class ReactLoadableSSRAddon implements WebpackPluginInstance {
|
||||
constructor(props: {filename: string});
|
||||
|
|
|
@ -63,7 +63,7 @@ async function normalizePluginConfig(
|
|||
const pluginPath = pluginRequire.resolve(pluginModuleImport);
|
||||
const pluginModule = importFresh<ImportedPluginModule>(pluginPath);
|
||||
return {
|
||||
plugin: pluginModule?.default ?? pluginModule,
|
||||
plugin: pluginModule.default ?? pluginModule,
|
||||
options: {},
|
||||
pluginModule: {
|
||||
path: pluginModuleImport,
|
||||
|
@ -90,7 +90,7 @@ async function normalizePluginConfig(
|
|||
const pluginPath = pluginRequire.resolve(pluginModuleImport);
|
||||
const pluginModule = importFresh<ImportedPluginModule>(pluginPath);
|
||||
return {
|
||||
plugin: pluginModule?.default ?? pluginModule,
|
||||
plugin: pluginModule.default ?? pluginModule,
|
||||
options: pluginConfig[1],
|
||||
pluginModule: {
|
||||
path: pluginModuleImport,
|
||||
|
|
|
@ -52,7 +52,7 @@ export async function loadPlugins(context: LoadContext): Promise<{
|
|||
plugins.map(async (plugin) => {
|
||||
const content = await plugin.loadContent?.();
|
||||
const rawTranslationFiles =
|
||||
(await plugin?.getTranslationFiles?.({content})) ?? [];
|
||||
(await plugin.getTranslationFiles?.({content})) ?? [];
|
||||
const translationFiles = await Promise.all(
|
||||
rawTranslationFiles.map((translationFile) =>
|
||||
localizePluginTranslationFile({
|
||||
|
|
|
@ -29,8 +29,8 @@ function getOptionValidationFunction(
|
|||
if (normalizedPluginConfig.pluginModule) {
|
||||
// Support both CommonJS and ES modules
|
||||
return (
|
||||
normalizedPluginConfig.pluginModule.module?.default?.validateOptions ??
|
||||
normalizedPluginConfig.pluginModule.module?.validateOptions
|
||||
normalizedPluginConfig.pluginModule.module.default?.validateOptions ??
|
||||
normalizedPluginConfig.pluginModule.module.validateOptions
|
||||
);
|
||||
}
|
||||
return normalizedPluginConfig.plugin.validateOptions;
|
||||
|
@ -66,7 +66,7 @@ export async function initPlugins(
|
|||
): Promise<PluginVersionInformation> {
|
||||
if (normalizedPluginConfig.pluginModule?.path) {
|
||||
const pluginPath = pluginRequire.resolve(
|
||||
normalizedPluginConfig.pluginModule?.path,
|
||||
normalizedPluginConfig.pluginModule.path,
|
||||
);
|
||||
return getPluginVersion(pluginPath, context.siteDir);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ export function getNamePatterns(
|
|||
if (!moduleName.includes('/')) {
|
||||
return [`${moduleName}/docusaurus-${moduleType}`];
|
||||
}
|
||||
const [scope, packageName] = moduleName.split(/\/(?<rest>.*)/);
|
||||
const [scope, packageName] = moduleName.split(/\/(?<rest>.*)/) as [
|
||||
string,
|
||||
string,
|
||||
];
|
||||
return [
|
||||
`${scope}/${packageName}`,
|
||||
`${scope}/docusaurus-${moduleType}-${packageName}`,
|
||||
|
|
|
@ -50,8 +50,8 @@ export function sortConfig(
|
|||
}
|
||||
// Higher priority get placed first.
|
||||
if (a.priority || b.priority) {
|
||||
const priorityA = a.priority || 0;
|
||||
const priorityB = b.priority || 0;
|
||||
const priorityA = a.priority ?? 0;
|
||||
const priorityB = b.priority ?? 0;
|
||||
const score = priorityB - priorityA;
|
||||
|
||||
if (score !== 0) {
|
||||
|
|
|
@ -89,7 +89,7 @@ export function createMDXFallbackPlugin({
|
|||
// processed by content plugins mdx loaders. This works, but a bit
|
||||
// hacky... Not sure there's a way to handle that differently in webpack
|
||||
function getMDXFallbackExcludedPaths(): string[] {
|
||||
const rules: RuleSetRule[] = config?.module?.rules as RuleSetRule[];
|
||||
const rules: RuleSetRule[] = config.module?.rules as RuleSetRule[];
|
||||
return rules.flatMap((rule) => {
|
||||
const isMDXRule =
|
||||
rule.test instanceof RegExp && rule.test.test('x.mdx');
|
||||
|
|
|
@ -152,7 +152,7 @@ const isModule = (value: unknown): value is Module =>
|
|||
typeof value === 'string' ||
|
||||
(typeof value === 'object' &&
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
!!(value as {[key: string]: unknown})?.__import);
|
||||
!!(value as {[key: string]: unknown} | null)?.__import);
|
||||
|
||||
/**
|
||||
* Takes a {@link Module} (which is nothing more than a path plus some metadata
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue