mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +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",
|
||||
"description": "Docusaurus Loader for MDX",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/mdx-loader.d.ts",
|
||||
"types": "lib/index.d.ts",
|
||||
"publishConfig": {
|
||||
"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
|
||||
declare module '@mdx-js/mdx' {
|
||||
import type {Processor} from 'unified';
|
||||
import type {MDXPlugin} from '@docusaurus/mdx-loader';
|
||||
import type {Processor, Plugin} from 'unified';
|
||||
|
||||
export type Options = {
|
||||
type MDXPlugin =
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[Plugin<any[]>, any] | Plugin<any[]>;
|
||||
|
||||
type Options = {
|
||||
filepath?: string;
|
||||
skipExport?: boolean;
|
||||
wrapExport?: string;
|
||||
|
|
|
@ -5,240 +5,31 @@
|
|||
* 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 {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
import type {LoaderContext} from 'webpack';
|
||||
import type {Processor} from 'unified';
|
||||
import {mdxLoader} from './loader';
|
||||
|
||||
const {
|
||||
loaders: {inlineMarkdownImageFileLoader},
|
||||
} = getFileLoaderUtils();
|
||||
export default mdxLoader;
|
||||
|
||||
const pragma = `
|
||||
/* @jsxRuntime classic */
|
||||
/* @jsx mdx */
|
||||
/* @jsxFrag mdx.Fragment */
|
||||
`;
|
||||
|
||||
const DEFAULT_OPTIONS: MDXOptions = {
|
||||
rehypePlugins: [],
|
||||
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
|
||||
beforeDefaultRemarkPlugins: [],
|
||||
beforeDefaultRehypePlugins: [],
|
||||
export type TOCItem = {
|
||||
readonly value: string;
|
||||
readonly id: string;
|
||||
readonly level: number;
|
||||
};
|
||||
|
||||
const compilerCache = new Map<string | Options, [Processor, Options]>();
|
||||
|
||||
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;
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
export type {Options, MDXPlugin, MDXOptions} from './loader';
|
||||
|
|
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 {toValue} from '../utils';
|
||||
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {TOCItem} from '../..';
|
||||
import type {Node, Parent} from 'unist';
|
||||
import type {Heading, Literal} from 'mdast';
|
||||
import type {Transformer} from 'unified';
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
"declarationMap": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import {
|
|||
getContentPathList,
|
||||
getDataFilePath,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
type TagsListItem,
|
||||
type TagModule,
|
||||
} from '@docusaurus/utils';
|
||||
import {translateContent, getTranslationFiles} from './translations';
|
||||
|
||||
|
@ -31,13 +33,7 @@ import type {
|
|||
BlogContentPaths,
|
||||
BlogMarkdownLoaderOptions,
|
||||
} from './types';
|
||||
import type {
|
||||
LoadContext,
|
||||
Plugin,
|
||||
HtmlTags,
|
||||
TagsListItem,
|
||||
TagModule,
|
||||
} from '@docusaurus/types';
|
||||
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
||||
import {
|
||||
generateBlogPosts,
|
||||
getSourceToPermalink,
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
|
||||
declare module '@docusaurus/plugin-content-blog' {
|
||||
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 {Tag} from '@docusaurus/types';
|
||||
|
||||
export type Assets = {
|
||||
/**
|
||||
|
@ -487,7 +486,7 @@ declare module '@theme/BlogListPage' {
|
|||
|
||||
declare module '@theme/BlogTagsListPage' {
|
||||
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||
import type {TagsListItem} from '@docusaurus/types';
|
||||
import type {TagsListItem} from '@docusaurus/utils';
|
||||
|
||||
export interface Props {
|
||||
/** Blog sidebar. */
|
||||
|
@ -503,7 +502,7 @@ declare module '@theme/BlogTagsPostsPage' {
|
|||
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||
import type {Content} from '@theme/BlogPostPage';
|
||||
import type {Metadata} from '@theme/BlogListPage';
|
||||
import type {TagModule} from '@docusaurus/types';
|
||||
import type {TagModule} from '@docusaurus/utils';
|
||||
|
||||
export interface Props {
|
||||
/** Blog sidebar. */
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
|
||||
import type {Tag} from '@docusaurus/types';
|
||||
import type {BrokenMarkdownLink, ContentPaths, Tag} from '@docusaurus/utils';
|
||||
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
||||
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
||||
|
||||
|
|
|
@ -7,8 +7,13 @@
|
|||
|
||||
declare module '@docusaurus/plugin-content-docs' {
|
||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||
import type {ContentPaths, FrontMatterTag} from '@docusaurus/utils';
|
||||
import type {TagsListItem, TagModule, Tag} from '@docusaurus/types';
|
||||
import type {
|
||||
ContentPaths,
|
||||
FrontMatterTag,
|
||||
TagsListItem,
|
||||
TagModule,
|
||||
Tag,
|
||||
} from '@docusaurus/utils';
|
||||
import type {Required} from 'utility-types';
|
||||
|
||||
export type Assets = {
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
/// <reference types="@docusaurus/module-type-aliases" />
|
||||
|
||||
import type {Sidebars} from './sidebars/types';
|
||||
import type {BrokenMarkdownLink} from '@docusaurus/utils';
|
||||
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
|
||||
import type {
|
||||
VersionMetadata,
|
||||
LastUpdateData,
|
||||
DocMetadata,
|
||||
CategoryGeneratedIndexMetadata,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
import type {Tag} from '@docusaurus/types';
|
||||
import type {SidebarsUtils} from './sidebars/utils';
|
||||
|
||||
export type DocFile = {
|
||||
|
|
|
@ -1057,7 +1057,7 @@ declare module '@theme/Details' {
|
|||
}
|
||||
|
||||
declare module '@theme/TOCItems' {
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||
|
||||
export interface Props {
|
||||
readonly toc: readonly TOCItem[];
|
||||
|
@ -1085,7 +1085,7 @@ declare module '@theme/TOCItems/Tree' {
|
|||
}
|
||||
|
||||
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
|
||||
// default set by Joi. See TOC, TOCInline, TOCCollapsible for examples.
|
||||
|
@ -1100,7 +1100,7 @@ declare module '@theme/TOC' {
|
|||
}
|
||||
|
||||
declare module '@theme/TOCInline' {
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||
|
||||
export interface Props {
|
||||
readonly toc: readonly TOCItem[];
|
||||
|
@ -1112,7 +1112,7 @@ declare module '@theme/TOCInline' {
|
|||
}
|
||||
|
||||
declare module '@theme/TOCCollapsible' {
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||
|
||||
export interface Props {
|
||||
readonly className?: string;
|
||||
|
@ -1236,7 +1236,7 @@ declare module '@theme/IconExternalLink' {
|
|||
}
|
||||
|
||||
declare module '@theme/TagsListByLetter' {
|
||||
import type {TagsListItem} from '@docusaurus/types';
|
||||
import type {TagsListItem} from '@docusaurus/utils';
|
||||
|
||||
export interface Props {
|
||||
readonly tags: readonly TagsListItem[];
|
||||
|
@ -1245,7 +1245,7 @@ declare module '@theme/TagsListByLetter' {
|
|||
}
|
||||
|
||||
declare module '@theme/TagsListInline' {
|
||||
import type {Tag} from '@docusaurus/types';
|
||||
import type {Tag} from '@docusaurus/utils';
|
||||
|
||||
export interface Props {
|
||||
readonly tags: readonly Tag[];
|
||||
|
@ -1254,7 +1254,7 @@ declare module '@theme/TagsListInline' {
|
|||
}
|
||||
|
||||
declare module '@theme/Tag' {
|
||||
import type {TagsListItem} from '@docusaurus/types';
|
||||
import type {TagsListItem} from '@docusaurus/utils';
|
||||
import type {Optional} from 'utility-types';
|
||||
|
||||
export interface Props extends Optional<TagsListItem, 'count'> {}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import type {TagsListItem} from '@docusaurus/types';
|
||||
import type {TagsListItem} from '@docusaurus/utils';
|
||||
|
||||
export const translateTagsPageTitle = (): string =>
|
||||
translate({
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import {useMemo} from 'react';
|
||||
import type {TOCItem} from '@docusaurus/types';
|
||||
import type {TOCItem} from '@docusaurus/mdx-loader';
|
||||
|
||||
export type TOCTreeNode = {
|
||||
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 & {
|
||||
readonly headTags: string;
|
||||
readonly preBodyTags: string;
|
||||
readonly postBodyTags: string;
|
||||
readonly siteMetadata: SiteMetadata;
|
||||
readonly routes: RouteConfig[];
|
||||
readonly routesPaths: string[];
|
||||
readonly plugins: LoadedPlugin[];
|
||||
headTags: string;
|
||||
preBodyTags: string;
|
||||
postBodyTags: string;
|
||||
siteMetadata: SiteMetadata;
|
||||
routes: RouteConfig[];
|
||||
routesPaths: string[];
|
||||
plugins: LoadedPlugin[];
|
||||
};
|
||||
|
||||
// === Plugin ===
|
||||
|
@ -447,9 +447,7 @@ export type PluginContentLoadedActions = {
|
|||
export type ConfigureWebpackUtils = {
|
||||
getStyleLoaders: (
|
||||
isServer: boolean,
|
||||
cssOptions: {
|
||||
[key: string]: unknown;
|
||||
},
|
||||
cssOptions: {[key: string]: unknown},
|
||||
) => RuleSetRule[];
|
||||
getJSLoader: (options: {
|
||||
isServer: boolean;
|
||||
|
@ -464,7 +462,7 @@ export type AllContent = {
|
|||
};
|
||||
|
||||
// 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 = {
|
||||
/**
|
||||
|
@ -557,40 +555,6 @@ export type Plugin<Content = unknown> = {
|
|||
}) => 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 & {
|
||||
readonly options: Required<PluginOptions>;
|
||||
readonly version: PluginVersionInformation;
|
||||
|
@ -612,9 +576,8 @@ export type SwizzleComponentConfig = {
|
|||
|
||||
export type SwizzleConfig = {
|
||||
components: {[componentName: string]: SwizzleComponentConfig};
|
||||
// Other settings could be added here,
|
||||
// For example: the ability to declare the config as exhaustive
|
||||
// so that we can emit errors
|
||||
// Other settings could be added here, like the ability to declare the config
|
||||
// as exhaustive so that we can emit errors
|
||||
};
|
||||
|
||||
export type PluginModule = {
|
||||
|
@ -626,21 +589,13 @@ export type PluginModule = {
|
|||
getSwizzleConfig?: () => SwizzleConfig | undefined;
|
||||
};
|
||||
|
||||
export type ImportedPluginModule = PluginModule & {
|
||||
default?: PluginModule;
|
||||
};
|
||||
|
||||
export type Preset = {
|
||||
plugins?: PluginConfig[];
|
||||
themes?: PluginConfig[];
|
||||
};
|
||||
|
||||
export type PresetModule = {
|
||||
<T>(context: LoadContext, presetOptions: T): Preset;
|
||||
};
|
||||
|
||||
export type ImportedPresetModule = PresetModule & {
|
||||
default?: PresetModule;
|
||||
(context: LoadContext, presetOptions: unknown): Preset;
|
||||
};
|
||||
|
||||
// === 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 = {
|
||||
onRouteDidUpdate?: (args: {
|
||||
previousLocation: Location | null;
|
||||
|
@ -799,25 +741,6 @@ export type ClientModule = {
|
|||
}) => (() => 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 = {
|
||||
/**
|
||||
* Throw an error, or simply return undefined if the data cannot be found. Use
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
*/
|
||||
|
||||
import Joi from './Joi';
|
||||
import {isValidPathname, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||
import type {Tag} from '@docusaurus/types';
|
||||
import {isValidPathname, DEFAULT_PLUGIN_ID, type Tag} from '@docusaurus/utils';
|
||||
import {JoiFrontMatter} from './JoiFrontMatter';
|
||||
|
||||
export const PluginIdSchema = Joi.string()
|
||||
|
|
|
@ -57,6 +57,9 @@ export {
|
|||
buildSshUrl,
|
||||
} from './urlUtils';
|
||||
export {
|
||||
type Tag,
|
||||
type TagsListItem,
|
||||
type TagModule,
|
||||
type FrontMatterTag,
|
||||
normalizeFrontMatterTags,
|
||||
groupTaggedItems,
|
||||
|
|
|
@ -7,7 +7,25 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
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;
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
import leven from 'leven';
|
||||
import _ from 'lodash';
|
||||
import logger from '@docusaurus/logger';
|
||||
import type {NormalizedPluginConfig} from '../../server/plugins/configs';
|
||||
import type {
|
||||
InitializedPlugin,
|
||||
SwizzleAction,
|
||||
SwizzleActionStatus,
|
||||
NormalizedPluginConfig,
|
||||
} from '@docusaurus/types';
|
||||
|
||||
export const SwizzleActions: SwizzleAction[] = ['wrap', 'eject'];
|
||||
|
|
|
@ -12,10 +12,46 @@ import {resolveModuleName} from './moduleShorthand';
|
|||
import type {
|
||||
LoadContext,
|
||||
PluginConfig,
|
||||
ImportedPluginModule,
|
||||
NormalizedPluginConfig,
|
||||
PluginModule,
|
||||
PluginOptions,
|
||||
} 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(
|
||||
pluginConfig: Exclude<PluginConfig, false | null>,
|
||||
configPath: string,
|
||||
|
|
|
@ -13,7 +13,6 @@ import type {
|
|||
PluginModule,
|
||||
PluginOptions,
|
||||
InitializedPlugin,
|
||||
NormalizedPluginConfig,
|
||||
} from '@docusaurus/types';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||
import {getPluginVersion} from '../siteMetadata';
|
||||
|
@ -22,7 +21,7 @@ import {
|
|||
normalizePluginOptions,
|
||||
normalizeThemeConfig,
|
||||
} from '@docusaurus/utils-validation';
|
||||
import {loadPluginConfigs} from './configs';
|
||||
import {loadPluginConfigs, type NormalizedPluginConfig} from './configs';
|
||||
|
||||
function getOptionValidationFunction(
|
||||
normalizedPluginConfig: NormalizedPluginConfig,
|
||||
|
|
|
@ -10,11 +10,13 @@ import importFresh from 'import-fresh';
|
|||
import type {
|
||||
LoadContext,
|
||||
PluginConfig,
|
||||
ImportedPresetModule,
|
||||
PresetModule,
|
||||
DocusaurusConfig,
|
||||
} from '@docusaurus/types';
|
||||
import {resolveModuleName} from './moduleShorthand';
|
||||
|
||||
type ImportedPresetModule = PresetModule & {default?: PresetModule};
|
||||
|
||||
/**
|
||||
* Calls preset functions, aggregates each of their return values, and returns
|
||||
* the plugin and theme configs.
|
||||
|
|
|
@ -12,7 +12,7 @@ import {excludeJS, clientDir, createBaseConfig} from '../base';
|
|||
import * as utils from '@docusaurus/utils/lib/webpackUtils';
|
||||
import {posixPath} from '@docusaurus/utils';
|
||||
import _ from 'lodash';
|
||||
import type {Props, ThemeAliases} from '@docusaurus/types';
|
||||
import type {Props} from '@docusaurus/types';
|
||||
|
||||
describe('babel transpilation exclude logic', () => {
|
||||
it('always transpiles client dir files', () => {
|
||||
|
@ -106,9 +106,8 @@ describe('base webpack config', () => {
|
|||
});
|
||||
|
||||
it('creates webpack aliases', async () => {
|
||||
// @ts-expect-error: Docusaurus webpack alias is always an object
|
||||
const aliases: ThemeAliases =
|
||||
(await createBaseConfig(props, true)).resolve?.alias ?? {};
|
||||
const aliases = ((await createBaseConfig(props, true)).resolve?.alias ??
|
||||
{}) as {[alias: string]: string};
|
||||
// Make aliases relative so that test work on all computers
|
||||
const relativeAliases = _.mapValues(aliases, (a) =>
|
||||
posixPath(path.relative(props.siteDir, a)),
|
||||
|
|
|
@ -15,7 +15,12 @@ import {
|
|||
Globby,
|
||||
} from '@docusaurus/utils';
|
||||
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');
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue