mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-11 08:07:26 +02:00
refactor(types): move non-core, non-public types out of the types package (#7293)
This commit is contained in:
parent
c7a5af7c4d
commit
b49ae67521
25 changed files with 397 additions and 404 deletions
|
@ -3,7 +3,7 @@
|
||||||
"version": "2.0.0-beta.18",
|
"version": "2.0.0-beta.18",
|
||||||
"description": "Docusaurus Loader for MDX",
|
"description": "Docusaurus Loader for MDX",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "src/mdx-loader.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
|
9
packages/docusaurus-mdx-loader/src/deps.d.ts
vendored
9
packages/docusaurus-mdx-loader/src/deps.d.ts
vendored
|
@ -7,10 +7,13 @@
|
||||||
|
|
||||||
// TODO Types provided by MDX 2.0 https://github.com/mdx-js/mdx/blob/main/packages/mdx/types/index.d.ts
|
// TODO Types provided by MDX 2.0 https://github.com/mdx-js/mdx/blob/main/packages/mdx/types/index.d.ts
|
||||||
declare module '@mdx-js/mdx' {
|
declare module '@mdx-js/mdx' {
|
||||||
import type {Processor} from 'unified';
|
import type {Processor, Plugin} from 'unified';
|
||||||
import type {MDXPlugin} from '@docusaurus/mdx-loader';
|
|
||||||
|
|
||||||
export type Options = {
|
type MDXPlugin =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
[Plugin<any[]>, any] | Plugin<any[]>;
|
||||||
|
|
||||||
|
type Options = {
|
||||||
filepath?: string;
|
filepath?: string;
|
||||||
skipExport?: boolean;
|
skipExport?: boolean;
|
||||||
wrapExport?: string;
|
wrapExport?: string;
|
||||||
|
|
|
@ -5,240 +5,31 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import {mdxLoader} from './loader';
|
||||||
import {createCompiler} from '@mdx-js/mdx';
|
|
||||||
import logger from '@docusaurus/logger';
|
|
||||||
import emoji from 'remark-emoji';
|
|
||||||
import {
|
|
||||||
parseFrontMatter,
|
|
||||||
parseMarkdownContentTitle,
|
|
||||||
escapePath,
|
|
||||||
getFileLoaderUtils,
|
|
||||||
} from '@docusaurus/utils';
|
|
||||||
import stringifyObject from 'stringify-object';
|
|
||||||
import headings from './remark/headings';
|
|
||||||
import toc from './remark/toc';
|
|
||||||
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
|
||||||
import transformImage from './remark/transformImage';
|
|
||||||
import transformLinks from './remark/transformLinks';
|
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
|
||||||
import type {LoaderContext} from 'webpack';
|
|
||||||
import type {Processor} from 'unified';
|
|
||||||
|
|
||||||
const {
|
export default mdxLoader;
|
||||||
loaders: {inlineMarkdownImageFileLoader},
|
|
||||||
} = getFileLoaderUtils();
|
|
||||||
|
|
||||||
const pragma = `
|
export type TOCItem = {
|
||||||
/* @jsxRuntime classic */
|
readonly value: string;
|
||||||
/* @jsx mdx */
|
readonly id: string;
|
||||||
/* @jsxFrag mdx.Fragment */
|
readonly level: number;
|
||||||
`;
|
|
||||||
|
|
||||||
const DEFAULT_OPTIONS: MDXOptions = {
|
|
||||||
rehypePlugins: [],
|
|
||||||
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
|
|
||||||
beforeDefaultRemarkPlugins: [],
|
|
||||||
beforeDefaultRehypePlugins: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const compilerCache = new Map<string | Options, [Processor, Options]>();
|
export type LoadedMDXContent<FrontMatter, Metadata, Assets = undefined> = {
|
||||||
|
/** As verbatim declared in the MDX document. */
|
||||||
type Options = MDXOptions & {
|
readonly frontMatter: FrontMatter;
|
||||||
staticDirs: string[];
|
/** As provided by the content plugin. */
|
||||||
siteDir: string;
|
readonly metadata: Metadata;
|
||||||
isMDXPartial?: (filePath: string) => boolean;
|
/** A list of TOC items (headings). */
|
||||||
isMDXPartialFrontMatterWarningDisabled?: boolean;
|
readonly toc: readonly TOCItem[];
|
||||||
removeContentTitle?: boolean;
|
/** First h1 title before any content. */
|
||||||
metadataPath?: string | ((filePath: string) => string);
|
readonly contentTitle: string | undefined;
|
||||||
createAssets?: (metadata: {
|
/**
|
||||||
frontMatter: {[key: string]: unknown};
|
* Usually image assets that may be collocated like `./img/thumbnail.png`.
|
||||||
metadata: {[key: string]: unknown};
|
* The loader would also bundle these assets and the client should use these
|
||||||
}) => {[key: string]: unknown};
|
* in priority.
|
||||||
filepath: string;
|
*/
|
||||||
|
readonly assets: Assets;
|
||||||
|
(): JSX.Element;
|
||||||
};
|
};
|
||||||
|
export type {Options, MDXPlugin, MDXOptions} from './loader';
|
||||||
/**
|
|
||||||
* When this throws, it generally means that there's no metadata file associated
|
|
||||||
* with this MDX document. It can happen when using MDX partials (usually
|
|
||||||
* starting with _). That's why it's important to provide the `isMDXPartial`
|
|
||||||
* function in config
|
|
||||||
*/
|
|
||||||
async function readMetadataPath(metadataPath: string) {
|
|
||||||
try {
|
|
||||||
return await fs.readFile(metadataPath, 'utf8');
|
|
||||||
} catch (err) {
|
|
||||||
logger.error`MDX loader can't read MDX metadata file path=${metadataPath}. Maybe the isMDXPartial option function was not provided?`;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts assets an object with Webpack require calls code.
|
|
||||||
* This is useful for mdx files to reference co-located assets using relative
|
|
||||||
* paths. Those assets should enter the Webpack assets pipeline and be hashed.
|
|
||||||
* For now, we only handle that for images and paths starting with `./`:
|
|
||||||
*
|
|
||||||
* `{image: "./myImage.png"}` => `{image: require("./myImage.png")}`
|
|
||||||
*/
|
|
||||||
function createAssetsExportCode(assets: {[key: string]: unknown}) {
|
|
||||||
if (Object.keys(assets).length === 0) {
|
|
||||||
return 'undefined';
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO implementation can be completed/enhanced
|
|
||||||
function createAssetValueCode(assetValue: unknown): string | undefined {
|
|
||||||
if (Array.isArray(assetValue)) {
|
|
||||||
const arrayItemCodes = assetValue.map(
|
|
||||||
(item) => createAssetValueCode(item) ?? 'undefined',
|
|
||||||
);
|
|
||||||
return `[${arrayItemCodes.join(', ')}]`;
|
|
||||||
}
|
|
||||||
// Only process string values starting with ./
|
|
||||||
// We could enhance this logic and check if file exists on disc?
|
|
||||||
if (typeof assetValue === 'string' && assetValue.startsWith('./')) {
|
|
||||||
// TODO do we have other use-cases than image assets?
|
|
||||||
// Probably not worth adding more support, as we want to move to Webpack 5 new asset system (https://github.com/facebook/docusaurus/pull/4708)
|
|
||||||
const inlineLoader = inlineMarkdownImageFileLoader;
|
|
||||||
return `require("${inlineLoader}${escapePath(assetValue)}").default`;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const assetEntries = Object.entries(assets);
|
|
||||||
|
|
||||||
const codeLines = assetEntries
|
|
||||||
.map(([key, value]) => {
|
|
||||||
const assetRequireCode = createAssetValueCode(value);
|
|
||||||
return assetRequireCode ? `"${key}": ${assetRequireCode},` : undefined;
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
return `{\n${codeLines.join('\n')}\n}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function mdxLoader(
|
|
||||||
this: LoaderContext<Options>,
|
|
||||||
fileString: string,
|
|
||||||
): Promise<void> {
|
|
||||||
const callback = this.async();
|
|
||||||
const filePath = this.resourcePath;
|
|
||||||
const reqOptions = this.getOptions() ?? {};
|
|
||||||
|
|
||||||
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
|
||||||
|
|
||||||
const {content, contentTitle} = parseMarkdownContentTitle(contentWithTitle, {
|
|
||||||
removeContentTitle: reqOptions.removeContentTitle,
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasFrontMatter = Object.keys(frontMatter).length > 0;
|
|
||||||
|
|
||||||
if (!compilerCache.has(this.query)) {
|
|
||||||
const options: Options = {
|
|
||||||
...reqOptions,
|
|
||||||
remarkPlugins: [
|
|
||||||
...(reqOptions.beforeDefaultRemarkPlugins ?? []),
|
|
||||||
...DEFAULT_OPTIONS.remarkPlugins,
|
|
||||||
[
|
|
||||||
transformImage,
|
|
||||||
{
|
|
||||||
staticDirs: reqOptions.staticDirs,
|
|
||||||
siteDir: reqOptions.siteDir,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
transformLinks,
|
|
||||||
{
|
|
||||||
staticDirs: reqOptions.staticDirs,
|
|
||||||
siteDir: reqOptions.siteDir,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
...(reqOptions.remarkPlugins ?? []),
|
|
||||||
],
|
|
||||||
rehypePlugins: [
|
|
||||||
...(reqOptions.beforeDefaultRehypePlugins ?? []),
|
|
||||||
...DEFAULT_OPTIONS.rehypePlugins,
|
|
||||||
...(reqOptions.rehypePlugins ?? []),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
compilerCache.set(this.query, [createCompiler(options), options]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [compiler, options] = compilerCache.get(this.query)!;
|
|
||||||
|
|
||||||
let result: string;
|
|
||||||
try {
|
|
||||||
result = await compiler
|
|
||||||
.process({
|
|
||||||
contents: content,
|
|
||||||
path: this.resourcePath,
|
|
||||||
})
|
|
||||||
.then((res) => res.toString());
|
|
||||||
} catch (err) {
|
|
||||||
return callback(err as Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MDX partials are MDX files starting with _ or in a folder starting with _
|
|
||||||
// Partial are not expected to have associated metadata files or front matter
|
|
||||||
const isMDXPartial = options.isMDXPartial?.(filePath);
|
|
||||||
if (isMDXPartial && hasFrontMatter) {
|
|
||||||
const errorMessage = `Docusaurus MDX partial files should not contain front matter.
|
|
||||||
Those partial files use the _ prefix as a convention by default, but this is configurable.
|
|
||||||
File at ${filePath} contains front matter that will be ignored:
|
|
||||||
${JSON.stringify(frontMatter, null, 2)}`;
|
|
||||||
|
|
||||||
if (!options.isMDXPartialFrontMatterWarningDisabled) {
|
|
||||||
const shouldError = process.env.NODE_ENV === 'test' || process.env.CI;
|
|
||||||
if (shouldError) {
|
|
||||||
return callback(new Error(errorMessage));
|
|
||||||
}
|
|
||||||
logger.warn(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMetadataPath(): string | undefined {
|
|
||||||
if (!isMDXPartial) {
|
|
||||||
// Read metadata for this MDX and export it.
|
|
||||||
if (options.metadataPath && typeof options.metadataPath === 'function') {
|
|
||||||
return options.metadataPath(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadataPath = getMetadataPath();
|
|
||||||
if (metadataPath) {
|
|
||||||
this.addDependency(metadataPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadataJsonString = metadataPath
|
|
||||||
? await readMetadataPath(metadataPath)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const metadata = metadataJsonString
|
|
||||||
? JSON.parse(metadataJsonString)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const assets =
|
|
||||||
reqOptions.createAssets && metadata
|
|
||||||
? reqOptions.createAssets({frontMatter, metadata})
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const exportsCode = `
|
|
||||||
export const frontMatter = ${stringifyObject(frontMatter)};
|
|
||||||
export const contentTitle = ${stringifyObject(contentTitle)};
|
|
||||||
${metadataJsonString ? `export const metadata = ${metadataJsonString};` : ''}
|
|
||||||
${assets ? `export const assets = ${createAssetsExportCode(assets)};` : ''}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const code = `
|
|
||||||
${pragma}
|
|
||||||
import React from 'react';
|
|
||||||
import { mdx } from '@mdx-js/react';
|
|
||||||
|
|
||||||
${exportsCode}
|
|
||||||
${result}
|
|
||||||
`;
|
|
||||||
|
|
||||||
return callback(null, code);
|
|
||||||
}
|
|
||||||
|
|
253
packages/docusaurus-mdx-loader/src/loader.ts
Normal file
253
packages/docusaurus-mdx-loader/src/loader.ts
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import {createCompiler} from '@mdx-js/mdx';
|
||||||
|
import logger from '@docusaurus/logger';
|
||||||
|
import emoji from 'remark-emoji';
|
||||||
|
import {
|
||||||
|
parseFrontMatter,
|
||||||
|
parseMarkdownContentTitle,
|
||||||
|
escapePath,
|
||||||
|
getFileLoaderUtils,
|
||||||
|
} from '@docusaurus/utils';
|
||||||
|
import stringifyObject from 'stringify-object';
|
||||||
|
import headings from './remark/headings';
|
||||||
|
import toc from './remark/toc';
|
||||||
|
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
|
||||||
|
import transformImage from './remark/transformImage';
|
||||||
|
import transformLinks from './remark/transformLinks';
|
||||||
|
import type {LoaderContext} from 'webpack';
|
||||||
|
import type {Processor, Plugin} from 'unified';
|
||||||
|
|
||||||
|
const {
|
||||||
|
loaders: {inlineMarkdownImageFileLoader},
|
||||||
|
} = getFileLoaderUtils();
|
||||||
|
|
||||||
|
const pragma = `
|
||||||
|
/* @jsxRuntime classic */
|
||||||
|
/* @jsx mdx */
|
||||||
|
/* @jsxFrag mdx.Fragment */
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DEFAULT_OPTIONS: MDXOptions = {
|
||||||
|
rehypePlugins: [],
|
||||||
|
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
|
||||||
|
beforeDefaultRemarkPlugins: [],
|
||||||
|
beforeDefaultRehypePlugins: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const compilerCache = new Map<string | Options, [Processor, Options]>();
|
||||||
|
|
||||||
|
export type MDXPlugin =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
[Plugin<any[]>, any] | Plugin<any[]>;
|
||||||
|
export type MDXOptions = {
|
||||||
|
remarkPlugins: MDXPlugin[];
|
||||||
|
rehypePlugins: MDXPlugin[];
|
||||||
|
beforeDefaultRemarkPlugins: MDXPlugin[];
|
||||||
|
beforeDefaultRehypePlugins: MDXPlugin[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Options = MDXOptions & {
|
||||||
|
staticDirs: string[];
|
||||||
|
siteDir: string;
|
||||||
|
isMDXPartial?: (filePath: string) => boolean;
|
||||||
|
isMDXPartialFrontMatterWarningDisabled?: boolean;
|
||||||
|
removeContentTitle?: boolean;
|
||||||
|
metadataPath?: string | ((filePath: string) => string);
|
||||||
|
createAssets?: (metadata: {
|
||||||
|
frontMatter: {[key: string]: unknown};
|
||||||
|
metadata: {[key: string]: unknown};
|
||||||
|
}) => {[key: string]: unknown};
|
||||||
|
filepath: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this throws, it generally means that there's no metadata file associated
|
||||||
|
* with this MDX document. It can happen when using MDX partials (usually
|
||||||
|
* starting with _). That's why it's important to provide the `isMDXPartial`
|
||||||
|
* function in config
|
||||||
|
*/
|
||||||
|
async function readMetadataPath(metadataPath: string) {
|
||||||
|
try {
|
||||||
|
return await fs.readFile(metadataPath, 'utf8');
|
||||||
|
} catch (err) {
|
||||||
|
logger.error`MDX loader can't read MDX metadata file path=${metadataPath}. Maybe the isMDXPartial option function was not provided?`;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts assets an object with Webpack require calls code.
|
||||||
|
* This is useful for mdx files to reference co-located assets using relative
|
||||||
|
* paths. Those assets should enter the Webpack assets pipeline and be hashed.
|
||||||
|
* For now, we only handle that for images and paths starting with `./`:
|
||||||
|
*
|
||||||
|
* `{image: "./myImage.png"}` => `{image: require("./myImage.png")}`
|
||||||
|
*/
|
||||||
|
function createAssetsExportCode(assets: {[key: string]: unknown}) {
|
||||||
|
if (Object.keys(assets).length === 0) {
|
||||||
|
return 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implementation can be completed/enhanced
|
||||||
|
function createAssetValueCode(assetValue: unknown): string | undefined {
|
||||||
|
if (Array.isArray(assetValue)) {
|
||||||
|
const arrayItemCodes = assetValue.map(
|
||||||
|
(item) => createAssetValueCode(item) ?? 'undefined',
|
||||||
|
);
|
||||||
|
return `[${arrayItemCodes.join(', ')}]`;
|
||||||
|
}
|
||||||
|
// Only process string values starting with ./
|
||||||
|
// We could enhance this logic and check if file exists on disc?
|
||||||
|
if (typeof assetValue === 'string' && assetValue.startsWith('./')) {
|
||||||
|
// TODO do we have other use-cases than image assets?
|
||||||
|
// Probably not worth adding more support, as we want to move to Webpack 5 new asset system (https://github.com/facebook/docusaurus/pull/4708)
|
||||||
|
const inlineLoader = inlineMarkdownImageFileLoader;
|
||||||
|
return `require("${inlineLoader}${escapePath(assetValue)}").default`;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const assetEntries = Object.entries(assets);
|
||||||
|
|
||||||
|
const codeLines = assetEntries
|
||||||
|
.map(([key, value]) => {
|
||||||
|
const assetRequireCode = createAssetValueCode(value);
|
||||||
|
return assetRequireCode ? `"${key}": ${assetRequireCode},` : undefined;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
return `{\n${codeLines.join('\n')}\n}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mdxLoader(
|
||||||
|
this: LoaderContext<Options>,
|
||||||
|
fileString: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const callback = this.async();
|
||||||
|
const filePath = this.resourcePath;
|
||||||
|
const reqOptions = this.getOptions() ?? {};
|
||||||
|
|
||||||
|
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
||||||
|
|
||||||
|
const {content, contentTitle} = parseMarkdownContentTitle(contentWithTitle, {
|
||||||
|
removeContentTitle: reqOptions.removeContentTitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasFrontMatter = Object.keys(frontMatter).length > 0;
|
||||||
|
|
||||||
|
if (!compilerCache.has(this.query)) {
|
||||||
|
const options: Options = {
|
||||||
|
...reqOptions,
|
||||||
|
remarkPlugins: [
|
||||||
|
...(reqOptions.beforeDefaultRemarkPlugins ?? []),
|
||||||
|
...DEFAULT_OPTIONS.remarkPlugins,
|
||||||
|
[
|
||||||
|
transformImage,
|
||||||
|
{
|
||||||
|
staticDirs: reqOptions.staticDirs,
|
||||||
|
siteDir: reqOptions.siteDir,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
transformLinks,
|
||||||
|
{
|
||||||
|
staticDirs: reqOptions.staticDirs,
|
||||||
|
siteDir: reqOptions.siteDir,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
...(reqOptions.remarkPlugins ?? []),
|
||||||
|
],
|
||||||
|
rehypePlugins: [
|
||||||
|
...(reqOptions.beforeDefaultRehypePlugins ?? []),
|
||||||
|
...DEFAULT_OPTIONS.rehypePlugins,
|
||||||
|
...(reqOptions.rehypePlugins ?? []),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
compilerCache.set(this.query, [createCompiler(options), options]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [compiler, options] = compilerCache.get(this.query)!;
|
||||||
|
|
||||||
|
let result: string;
|
||||||
|
try {
|
||||||
|
result = await compiler
|
||||||
|
.process({
|
||||||
|
contents: content,
|
||||||
|
path: this.resourcePath,
|
||||||
|
})
|
||||||
|
.then((res) => res.toString());
|
||||||
|
} catch (err) {
|
||||||
|
return callback(err as Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MDX partials are MDX files starting with _ or in a folder starting with _
|
||||||
|
// Partial are not expected to have associated metadata files or front matter
|
||||||
|
const isMDXPartial = options.isMDXPartial?.(filePath);
|
||||||
|
if (isMDXPartial && hasFrontMatter) {
|
||||||
|
const errorMessage = `Docusaurus MDX partial files should not contain front matter.
|
||||||
|
Those partial files use the _ prefix as a convention by default, but this is configurable.
|
||||||
|
File at ${filePath} contains front matter that will be ignored:
|
||||||
|
${JSON.stringify(frontMatter, null, 2)}`;
|
||||||
|
|
||||||
|
if (!options.isMDXPartialFrontMatterWarningDisabled) {
|
||||||
|
const shouldError = process.env.NODE_ENV === 'test' || process.env.CI;
|
||||||
|
if (shouldError) {
|
||||||
|
return callback(new Error(errorMessage));
|
||||||
|
}
|
||||||
|
logger.warn(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMetadataPath(): string | undefined {
|
||||||
|
if (!isMDXPartial) {
|
||||||
|
// Read metadata for this MDX and export it.
|
||||||
|
if (options.metadataPath && typeof options.metadataPath === 'function') {
|
||||||
|
return options.metadataPath(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadataPath = getMetadataPath();
|
||||||
|
if (metadataPath) {
|
||||||
|
this.addDependency(metadataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadataJsonString = metadataPath
|
||||||
|
? await readMetadataPath(metadataPath)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const metadata = metadataJsonString
|
||||||
|
? JSON.parse(metadataJsonString)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const assets =
|
||||||
|
reqOptions.createAssets && metadata
|
||||||
|
? reqOptions.createAssets({frontMatter, metadata})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const exportsCode = `
|
||||||
|
export const frontMatter = ${stringifyObject(frontMatter)};
|
||||||
|
export const contentTitle = ${stringifyObject(contentTitle)};
|
||||||
|
${metadataJsonString ? `export const metadata = ${metadataJsonString};` : ''}
|
||||||
|
${assets ? `export const assets = ${createAssetsExportCode(assets)};` : ''}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const code = `
|
||||||
|
${pragma}
|
||||||
|
import React from 'react';
|
||||||
|
import { mdx } from '@mdx-js/react';
|
||||||
|
|
||||||
|
${exportsCode}
|
||||||
|
${result}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return callback(null, code);
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type {Plugin} from 'unified';
|
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
|
||||||
|
|
||||||
export type MDXPlugin =
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
[Plugin<any[]>, any] | Plugin<any[]>;
|
|
||||||
export type MDXOptions = {
|
|
||||||
remarkPlugins: MDXPlugin[];
|
|
||||||
rehypePlugins: MDXPlugin[];
|
|
||||||
beforeDefaultRemarkPlugins: MDXPlugin[];
|
|
||||||
beforeDefaultRehypePlugins: MDXPlugin[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LoadedMDXContent<FrontMatter, Metadata, Assets = undefined> = {
|
|
||||||
/** As verbatim declared in the MDX document. */
|
|
||||||
readonly frontMatter: FrontMatter;
|
|
||||||
/** As provided by the content plugin. */
|
|
||||||
readonly metadata: Metadata;
|
|
||||||
/** A list of TOC items (headings). */
|
|
||||||
readonly toc: readonly TOCItem[];
|
|
||||||
/** First h1 title before any content. */
|
|
||||||
readonly contentTitle: string | undefined;
|
|
||||||
/**
|
|
||||||
* Usually image assets that may be collocated like `./img/thumbnail.png`.
|
|
||||||
* The loader would also bundle these assets and the client should use these
|
|
||||||
* in priority.
|
|
||||||
*/
|
|
||||||
readonly assets: Assets;
|
|
||||||
(): JSX.Element;
|
|
||||||
};
|
|
|
@ -13,7 +13,7 @@ import toString from 'mdast-util-to-string';
|
||||||
import visit from 'unist-util-visit';
|
import visit from 'unist-util-visit';
|
||||||
import {toValue} from '../utils';
|
import {toValue} from '../utils';
|
||||||
|
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '../..';
|
||||||
import type {Node, Parent} from 'unist';
|
import type {Node, Parent} from 'unist';
|
||||||
import type {Heading, Literal} from 'mdast';
|
import type {Heading, Literal} from 'mdast';
|
||||||
import type {Transformer} from 'unified';
|
import type {Transformer} from 'unified';
|
||||||
|
|
|
@ -7,5 +7,6 @@
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "lib"
|
"outDir": "lib"
|
||||||
}
|
},
|
||||||
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import {
|
||||||
getContentPathList,
|
getContentPathList,
|
||||||
getDataFilePath,
|
getDataFilePath,
|
||||||
DEFAULT_PLUGIN_ID,
|
DEFAULT_PLUGIN_ID,
|
||||||
|
type TagsListItem,
|
||||||
|
type TagModule,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import {translateContent, getTranslationFiles} from './translations';
|
import {translateContent, getTranslationFiles} from './translations';
|
||||||
|
|
||||||
|
@ -31,13 +33,7 @@ import type {
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
} from './types';
|
} from './types';
|
||||||
import type {
|
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
||||||
LoadContext,
|
|
||||||
Plugin,
|
|
||||||
HtmlTags,
|
|
||||||
TagsListItem,
|
|
||||||
TagModule,
|
|
||||||
} from '@docusaurus/types';
|
|
||||||
import {
|
import {
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
getSourceToPermalink,
|
getSourceToPermalink,
|
||||||
|
|
|
@ -7,9 +7,8 @@
|
||||||
|
|
||||||
declare module '@docusaurus/plugin-content-blog' {
|
declare module '@docusaurus/plugin-content-blog' {
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||||
import type {FrontMatterTag} from '@docusaurus/utils';
|
import type {FrontMatterTag, Tag} from '@docusaurus/utils';
|
||||||
import type {Overwrite} from 'utility-types';
|
import type {Overwrite} from 'utility-types';
|
||||||
import type {Tag} from '@docusaurus/types';
|
|
||||||
|
|
||||||
export type Assets = {
|
export type Assets = {
|
||||||
/**
|
/**
|
||||||
|
@ -487,7 +486,7 @@ declare module '@theme/BlogListPage' {
|
||||||
|
|
||||||
declare module '@theme/BlogTagsListPage' {
|
declare module '@theme/BlogTagsListPage' {
|
||||||
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
import type {TagsListItem} from '@docusaurus/types';
|
import type {TagsListItem} from '@docusaurus/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
/** Blog sidebar. */
|
/** Blog sidebar. */
|
||||||
|
@ -503,7 +502,7 @@ declare module '@theme/BlogTagsPostsPage' {
|
||||||
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
import type {Metadata} from '@theme/BlogListPage';
|
import type {Metadata} from '@theme/BlogListPage';
|
||||||
import type {TagModule} from '@docusaurus/types';
|
import type {TagModule} from '@docusaurus/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
/** Blog sidebar. */
|
/** Blog sidebar. */
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
|
import type {BrokenMarkdownLink, ContentPaths, Tag} from '@docusaurus/utils';
|
||||||
import type {Tag} from '@docusaurus/types';
|
|
||||||
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,13 @@
|
||||||
|
|
||||||
declare module '@docusaurus/plugin-content-docs' {
|
declare module '@docusaurus/plugin-content-docs' {
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||||
import type {ContentPaths, FrontMatterTag} from '@docusaurus/utils';
|
import type {
|
||||||
import type {TagsListItem, TagModule, Tag} from '@docusaurus/types';
|
ContentPaths,
|
||||||
|
FrontMatterTag,
|
||||||
|
TagsListItem,
|
||||||
|
TagModule,
|
||||||
|
Tag,
|
||||||
|
} from '@docusaurus/utils';
|
||||||
import type {Required} from 'utility-types';
|
import type {Required} from 'utility-types';
|
||||||
|
|
||||||
export type Assets = {
|
export type Assets = {
|
||||||
|
|
|
@ -8,14 +8,13 @@
|
||||||
/// <reference types="@docusaurus/module-type-aliases" />
|
/// <reference types="@docusaurus/module-type-aliases" />
|
||||||
|
|
||||||
import type {Sidebars} from './sidebars/types';
|
import type {Sidebars} from './sidebars/types';
|
||||||
import type {BrokenMarkdownLink} from '@docusaurus/utils';
|
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
|
||||||
import type {
|
import type {
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
LastUpdateData,
|
LastUpdateData,
|
||||||
DocMetadata,
|
DocMetadata,
|
||||||
CategoryGeneratedIndexMetadata,
|
CategoryGeneratedIndexMetadata,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import type {Tag} from '@docusaurus/types';
|
|
||||||
import type {SidebarsUtils} from './sidebars/utils';
|
import type {SidebarsUtils} from './sidebars/utils';
|
||||||
|
|
||||||
export type DocFile = {
|
export type DocFile = {
|
||||||
|
|
|
@ -1057,7 +1057,7 @@ declare module '@theme/Details' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TOCItems' {
|
declare module '@theme/TOCItems' {
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly toc: readonly TOCItem[];
|
readonly toc: readonly TOCItem[];
|
||||||
|
@ -1085,7 +1085,7 @@ declare module '@theme/TOCItems/Tree' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TOC' {
|
declare module '@theme/TOC' {
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||||
|
|
||||||
// `minHeadingLevel` only comes from doc/post front matter, and won't have a
|
// `minHeadingLevel` only comes from doc/post front matter, and won't have a
|
||||||
// default set by Joi. See TOC, TOCInline, TOCCollapsible for examples.
|
// default set by Joi. See TOC, TOCInline, TOCCollapsible for examples.
|
||||||
|
@ -1100,7 +1100,7 @@ declare module '@theme/TOC' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TOCInline' {
|
declare module '@theme/TOCInline' {
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly toc: readonly TOCItem[];
|
readonly toc: readonly TOCItem[];
|
||||||
|
@ -1112,7 +1112,7 @@ declare module '@theme/TOCInline' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TOCCollapsible' {
|
declare module '@theme/TOCCollapsible' {
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
|
@ -1236,7 +1236,7 @@ declare module '@theme/IconExternalLink' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TagsListByLetter' {
|
declare module '@theme/TagsListByLetter' {
|
||||||
import type {TagsListItem} from '@docusaurus/types';
|
import type {TagsListItem} from '@docusaurus/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly tags: readonly TagsListItem[];
|
readonly tags: readonly TagsListItem[];
|
||||||
|
@ -1245,7 +1245,7 @@ declare module '@theme/TagsListByLetter' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TagsListInline' {
|
declare module '@theme/TagsListInline' {
|
||||||
import type {Tag} from '@docusaurus/types';
|
import type {Tag} from '@docusaurus/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly tags: readonly Tag[];
|
readonly tags: readonly Tag[];
|
||||||
|
@ -1254,7 +1254,7 @@ declare module '@theme/TagsListInline' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/Tag' {
|
declare module '@theme/Tag' {
|
||||||
import type {TagsListItem} from '@docusaurus/types';
|
import type {TagsListItem} from '@docusaurus/utils';
|
||||||
import type {Optional} from 'utility-types';
|
import type {Optional} from 'utility-types';
|
||||||
|
|
||||||
export interface Props extends Optional<TagsListItem, 'count'> {}
|
export interface Props extends Optional<TagsListItem, 'count'> {}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
import type {TagsListItem} from '@docusaurus/types';
|
import type {TagsListItem} from '@docusaurus/utils';
|
||||||
|
|
||||||
export const translateTagsPageTitle = (): string =>
|
export const translateTagsPageTitle = (): string =>
|
||||||
translate({
|
translate({
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useMemo} from 'react';
|
import {useMemo} from 'react';
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||||
|
|
||||||
export type TOCTreeNode = {
|
export type TOCTreeNode = {
|
||||||
readonly value: string;
|
readonly value: string;
|
||||||
|
|
101
packages/docusaurus-types/src/index.d.ts
vendored
101
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -427,13 +427,13 @@ export type LoadContext = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Props = LoadContext & {
|
export type Props = LoadContext & {
|
||||||
readonly headTags: string;
|
headTags: string;
|
||||||
readonly preBodyTags: string;
|
preBodyTags: string;
|
||||||
readonly postBodyTags: string;
|
postBodyTags: string;
|
||||||
readonly siteMetadata: SiteMetadata;
|
siteMetadata: SiteMetadata;
|
||||||
readonly routes: RouteConfig[];
|
routes: RouteConfig[];
|
||||||
readonly routesPaths: string[];
|
routesPaths: string[];
|
||||||
readonly plugins: LoadedPlugin[];
|
plugins: LoadedPlugin[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Plugin ===
|
// === Plugin ===
|
||||||
|
@ -447,9 +447,7 @@ export type PluginContentLoadedActions = {
|
||||||
export type ConfigureWebpackUtils = {
|
export type ConfigureWebpackUtils = {
|
||||||
getStyleLoaders: (
|
getStyleLoaders: (
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
cssOptions: {
|
cssOptions: {[key: string]: unknown},
|
||||||
[key: string]: unknown;
|
|
||||||
},
|
|
||||||
) => RuleSetRule[];
|
) => RuleSetRule[];
|
||||||
getJSLoader: (options: {
|
getJSLoader: (options: {
|
||||||
isServer: boolean;
|
isServer: boolean;
|
||||||
|
@ -464,7 +462,7 @@ export type AllContent = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO improve type (not exposed by postcss-loader)
|
// TODO improve type (not exposed by postcss-loader)
|
||||||
export type PostCssOptions = {[key: string]: unknown} & {plugins: unknown[]};
|
export type PostCssOptions = {plugins: unknown[]; [key: string]: unknown};
|
||||||
|
|
||||||
type HtmlTagObject = {
|
type HtmlTagObject = {
|
||||||
/**
|
/**
|
||||||
|
@ -557,40 +555,6 @@ export type Plugin<Content = unknown> = {
|
||||||
}) => ThemeConfig;
|
}) => ThemeConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NormalizedPluginConfig = {
|
|
||||||
/**
|
|
||||||
* The default export of the plugin module, or alternatively, what's provided
|
|
||||||
* in the config file as inline plugins. Note that if a file is like:
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* export default plugin() {...}
|
|
||||||
* export validateOptions() {...}
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then the static methods may not exist here. `pluginModule.module` will
|
|
||||||
* always take priority.
|
|
||||||
*/
|
|
||||||
plugin: PluginModule;
|
|
||||||
/** Options as they are provided in the config, not validated yet. */
|
|
||||||
options: PluginOptions;
|
|
||||||
/** Only available when a string is provided in config. */
|
|
||||||
pluginModule?: {
|
|
||||||
/**
|
|
||||||
* Raw module name as provided in the config. Shorthands have been resolved,
|
|
||||||
* so at least it's directly `require.resolve`able.
|
|
||||||
*/
|
|
||||||
path: string;
|
|
||||||
/** Whatever gets imported with `require`. */
|
|
||||||
module: ImportedPluginModule;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Different from `pluginModule.path`, this one is always an absolute path,
|
|
||||||
* used to resolve relative paths returned from lifecycles. If it's an inline
|
|
||||||
* plugin, it will be path to the config file.
|
|
||||||
*/
|
|
||||||
entryPath: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type InitializedPlugin = Plugin & {
|
export type InitializedPlugin = Plugin & {
|
||||||
readonly options: Required<PluginOptions>;
|
readonly options: Required<PluginOptions>;
|
||||||
readonly version: PluginVersionInformation;
|
readonly version: PluginVersionInformation;
|
||||||
|
@ -612,9 +576,8 @@ export type SwizzleComponentConfig = {
|
||||||
|
|
||||||
export type SwizzleConfig = {
|
export type SwizzleConfig = {
|
||||||
components: {[componentName: string]: SwizzleComponentConfig};
|
components: {[componentName: string]: SwizzleComponentConfig};
|
||||||
// Other settings could be added here,
|
// Other settings could be added here, like the ability to declare the config
|
||||||
// For example: the ability to declare the config as exhaustive
|
// as exhaustive so that we can emit errors
|
||||||
// so that we can emit errors
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginModule = {
|
export type PluginModule = {
|
||||||
|
@ -626,21 +589,13 @@ export type PluginModule = {
|
||||||
getSwizzleConfig?: () => SwizzleConfig | undefined;
|
getSwizzleConfig?: () => SwizzleConfig | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ImportedPluginModule = PluginModule & {
|
|
||||||
default?: PluginModule;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Preset = {
|
export type Preset = {
|
||||||
plugins?: PluginConfig[];
|
plugins?: PluginConfig[];
|
||||||
themes?: PluginConfig[];
|
themes?: PluginConfig[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PresetModule = {
|
export type PresetModule = {
|
||||||
<T>(context: LoadContext, presetOptions: T): Preset;
|
(context: LoadContext, presetOptions: unknown): Preset;
|
||||||
};
|
|
||||||
|
|
||||||
export type ImportedPresetModule = PresetModule & {
|
|
||||||
default?: PresetModule;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Route registry ===
|
// === Route registry ===
|
||||||
|
@ -775,19 +730,6 @@ export type Registry = {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Aliases used for Webpack resolution (useful for implementing swizzling)
|
|
||||||
*/
|
|
||||||
export type ThemeAliases = {
|
|
||||||
[alias: string]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TOCItem = {
|
|
||||||
readonly value: string;
|
|
||||||
readonly id: string;
|
|
||||||
readonly level: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ClientModule = {
|
export type ClientModule = {
|
||||||
onRouteDidUpdate?: (args: {
|
onRouteDidUpdate?: (args: {
|
||||||
previousLocation: Location | null;
|
previousLocation: Location | null;
|
||||||
|
@ -799,25 +741,6 @@ export type ClientModule = {
|
||||||
}) => (() => void) | void;
|
}) => (() => void) | void;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** What the user configures. */
|
|
||||||
export type Tag = {
|
|
||||||
label: string;
|
|
||||||
/** Permalink to this tag's page, without the `/tags/` base path. */
|
|
||||||
permalink: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** What the tags list page should know about each tag. */
|
|
||||||
export type TagsListItem = Tag & {
|
|
||||||
/** Number of posts/docs with this tag. */
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** What the tag's own page should know about the tag. */
|
|
||||||
export type TagModule = TagsListItem & {
|
|
||||||
/** The tags list page's permalink. */
|
|
||||||
allTagsPath: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UseDataOptions = {
|
export type UseDataOptions = {
|
||||||
/**
|
/**
|
||||||
* Throw an error, or simply return undefined if the data cannot be found. Use
|
* Throw an error, or simply return undefined if the data cannot be found. Use
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Joi from './Joi';
|
import Joi from './Joi';
|
||||||
import {isValidPathname, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
import {isValidPathname, DEFAULT_PLUGIN_ID, type Tag} from '@docusaurus/utils';
|
||||||
import type {Tag} from '@docusaurus/types';
|
|
||||||
import {JoiFrontMatter} from './JoiFrontMatter';
|
import {JoiFrontMatter} from './JoiFrontMatter';
|
||||||
|
|
||||||
export const PluginIdSchema = Joi.string()
|
export const PluginIdSchema = Joi.string()
|
||||||
|
|
|
@ -57,6 +57,9 @@ export {
|
||||||
buildSshUrl,
|
buildSshUrl,
|
||||||
} from './urlUtils';
|
} from './urlUtils';
|
||||||
export {
|
export {
|
||||||
|
type Tag,
|
||||||
|
type TagsListItem,
|
||||||
|
type TagModule,
|
||||||
type FrontMatterTag,
|
type FrontMatterTag,
|
||||||
normalizeFrontMatterTags,
|
normalizeFrontMatterTags,
|
||||||
groupTaggedItems,
|
groupTaggedItems,
|
||||||
|
|
|
@ -7,7 +7,25 @@
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {normalizeUrl} from './urlUtils';
|
import {normalizeUrl} from './urlUtils';
|
||||||
import type {Tag} from '@docusaurus/types';
|
|
||||||
|
/** What the user configures. */
|
||||||
|
export type Tag = {
|
||||||
|
label: string;
|
||||||
|
/** Permalink to this tag's page, without the `/tags/` base path. */
|
||||||
|
permalink: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** What the tags list page should know about each tag. */
|
||||||
|
export type TagsListItem = Tag & {
|
||||||
|
/** Number of posts/docs with this tag. */
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** What the tag's own page should know about the tag. */
|
||||||
|
export type TagModule = TagsListItem & {
|
||||||
|
/** The tags list page's permalink. */
|
||||||
|
allTagsPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type FrontMatterTag = string | Tag;
|
export type FrontMatterTag = string | Tag;
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
import leven from 'leven';
|
import leven from 'leven';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import logger from '@docusaurus/logger';
|
import logger from '@docusaurus/logger';
|
||||||
|
import type {NormalizedPluginConfig} from '../../server/plugins/configs';
|
||||||
import type {
|
import type {
|
||||||
InitializedPlugin,
|
InitializedPlugin,
|
||||||
SwizzleAction,
|
SwizzleAction,
|
||||||
SwizzleActionStatus,
|
SwizzleActionStatus,
|
||||||
NormalizedPluginConfig,
|
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
|
|
||||||
export const SwizzleActions: SwizzleAction[] = ['wrap', 'eject'];
|
export const SwizzleActions: SwizzleAction[] = ['wrap', 'eject'];
|
||||||
|
|
|
@ -12,10 +12,46 @@ import {resolveModuleName} from './moduleShorthand';
|
||||||
import type {
|
import type {
|
||||||
LoadContext,
|
LoadContext,
|
||||||
PluginConfig,
|
PluginConfig,
|
||||||
ImportedPluginModule,
|
PluginModule,
|
||||||
NormalizedPluginConfig,
|
PluginOptions,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
|
|
||||||
|
type ImportedPluginModule = PluginModule & {default?: PluginModule};
|
||||||
|
|
||||||
|
export type NormalizedPluginConfig = {
|
||||||
|
/**
|
||||||
|
* The default export of the plugin module, or alternatively, what's provided
|
||||||
|
* in the config file as inline plugins. Note that if a file is like:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* export default plugin() {...}
|
||||||
|
* export validateOptions() {...}
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then the static methods may not exist here. `pluginModule.module` will
|
||||||
|
* always take priority.
|
||||||
|
*/
|
||||||
|
plugin: PluginModule;
|
||||||
|
/** Options as they are provided in the config, not validated yet. */
|
||||||
|
options: PluginOptions;
|
||||||
|
/** Only available when a string is provided in config. */
|
||||||
|
pluginModule?: {
|
||||||
|
/**
|
||||||
|
* Raw module name as provided in the config. Shorthands have been resolved,
|
||||||
|
* so at least it's directly `require.resolve`able.
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/** Whatever gets imported with `require`. */
|
||||||
|
module: ImportedPluginModule;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Different from `pluginModule.path`, this one is always an absolute path,
|
||||||
|
* used to resolve relative paths returned from lifecycles. If it's an inline
|
||||||
|
* plugin, it will be path to the config file.
|
||||||
|
*/
|
||||||
|
entryPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
async function normalizePluginConfig(
|
async function normalizePluginConfig(
|
||||||
pluginConfig: Exclude<PluginConfig, false | null>,
|
pluginConfig: Exclude<PluginConfig, false | null>,
|
||||||
configPath: string,
|
configPath: string,
|
||||||
|
|
|
@ -13,7 +13,6 @@ import type {
|
||||||
PluginModule,
|
PluginModule,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
InitializedPlugin,
|
InitializedPlugin,
|
||||||
NormalizedPluginConfig,
|
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
import {getPluginVersion} from '../siteMetadata';
|
import {getPluginVersion} from '../siteMetadata';
|
||||||
|
@ -22,7 +21,7 @@ import {
|
||||||
normalizePluginOptions,
|
normalizePluginOptions,
|
||||||
normalizeThemeConfig,
|
normalizeThemeConfig,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {loadPluginConfigs} from './configs';
|
import {loadPluginConfigs, type NormalizedPluginConfig} from './configs';
|
||||||
|
|
||||||
function getOptionValidationFunction(
|
function getOptionValidationFunction(
|
||||||
normalizedPluginConfig: NormalizedPluginConfig,
|
normalizedPluginConfig: NormalizedPluginConfig,
|
||||||
|
|
|
@ -10,11 +10,13 @@ import importFresh from 'import-fresh';
|
||||||
import type {
|
import type {
|
||||||
LoadContext,
|
LoadContext,
|
||||||
PluginConfig,
|
PluginConfig,
|
||||||
ImportedPresetModule,
|
PresetModule,
|
||||||
DocusaurusConfig,
|
DocusaurusConfig,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {resolveModuleName} from './moduleShorthand';
|
import {resolveModuleName} from './moduleShorthand';
|
||||||
|
|
||||||
|
type ImportedPresetModule = PresetModule & {default?: PresetModule};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls preset functions, aggregates each of their return values, and returns
|
* Calls preset functions, aggregates each of their return values, and returns
|
||||||
* the plugin and theme configs.
|
* the plugin and theme configs.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {excludeJS, clientDir, createBaseConfig} from '../base';
|
||||||
import * as utils from '@docusaurus/utils/lib/webpackUtils';
|
import * as utils from '@docusaurus/utils/lib/webpackUtils';
|
||||||
import {posixPath} from '@docusaurus/utils';
|
import {posixPath} from '@docusaurus/utils';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import type {Props, ThemeAliases} from '@docusaurus/types';
|
import type {Props} from '@docusaurus/types';
|
||||||
|
|
||||||
describe('babel transpilation exclude logic', () => {
|
describe('babel transpilation exclude logic', () => {
|
||||||
it('always transpiles client dir files', () => {
|
it('always transpiles client dir files', () => {
|
||||||
|
@ -106,9 +106,8 @@ describe('base webpack config', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates webpack aliases', async () => {
|
it('creates webpack aliases', async () => {
|
||||||
// @ts-expect-error: Docusaurus webpack alias is always an object
|
const aliases = ((await createBaseConfig(props, true)).resolve?.alias ??
|
||||||
const aliases: ThemeAliases =
|
{}) as {[alias: string]: string};
|
||||||
(await createBaseConfig(props, true)).resolve?.alias ?? {};
|
|
||||||
// Make aliases relative so that test work on all computers
|
// Make aliases relative so that test work on all computers
|
||||||
const relativeAliases = _.mapValues(aliases, (a) =>
|
const relativeAliases = _.mapValues(aliases, (a) =>
|
||||||
posixPath(path.relative(props.siteDir, a)),
|
posixPath(path.relative(props.siteDir, a)),
|
||||||
|
|
|
@ -15,7 +15,12 @@ import {
|
||||||
Globby,
|
Globby,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import type {ThemeAliases, LoadedPlugin} from '@docusaurus/types';
|
import type {LoadedPlugin} from '@docusaurus/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases used for Webpack resolution (useful for implementing swizzling)
|
||||||
|
*/
|
||||||
|
type ThemeAliases = {[alias: string]: string};
|
||||||
|
|
||||||
const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback');
|
const ThemeFallbackDir = path.join(__dirname, '../../client/theme-fallback');
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue