mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-23 19:48:54 +02:00
151 lines
4.6 KiB
TypeScript
151 lines
4.6 KiB
TypeScript
/**
|
|
* 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 logger from '@docusaurus/logger';
|
|
import {escapePath, type WebpackCompilerName} from '@docusaurus/utils';
|
|
import {getProcessor, type SimpleProcessorResult} from './processor';
|
|
import {validateMDXFrontMatter} from './frontMatter';
|
|
import preprocessor from './preprocessor';
|
|
import type {Options} from './options';
|
|
|
|
/**
|
|
* 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")}`
|
|
*/
|
|
export function createAssetsExportCode({
|
|
assets,
|
|
inlineMarkdownAssetImageFileLoader,
|
|
}: {
|
|
assets: unknown;
|
|
inlineMarkdownAssetImageFileLoader: string;
|
|
}): string {
|
|
if (
|
|
typeof assets !== 'object' ||
|
|
!assets ||
|
|
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: unknown) => 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)
|
|
return `require("${inlineMarkdownAssetImageFileLoader}${escapePath(
|
|
assetValue,
|
|
)}").default`;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const assetEntries = Object.entries(assets);
|
|
|
|
const codeLines = assetEntries
|
|
.map(([key, value]: [string, unknown]) => {
|
|
const assetRequireCode = createAssetValueCode(value);
|
|
return assetRequireCode ? `"${key}": ${assetRequireCode},` : undefined;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
return `{\n${codeLines.join('\n')}\n}`;
|
|
}
|
|
|
|
/**
|
|
* data.contentTitle is set by the remark contentTitle plugin
|
|
*/
|
|
export function extractContentTitleData(data: {
|
|
[key: string]: unknown;
|
|
}): string | undefined {
|
|
return data.contentTitle as string | undefined;
|
|
}
|
|
|
|
export async function compileToJSX({
|
|
filePath,
|
|
fileContent,
|
|
frontMatter,
|
|
options,
|
|
compilerName,
|
|
}: {
|
|
filePath: string;
|
|
fileContent: string;
|
|
frontMatter: Record<string, unknown>;
|
|
options: Options;
|
|
compilerName: WebpackCompilerName;
|
|
}): Promise<SimpleProcessorResult> {
|
|
const preprocessedFileContent = preprocessor({
|
|
fileContent,
|
|
filePath,
|
|
admonitions: options.admonitions,
|
|
markdownConfig: options.markdownConfig,
|
|
});
|
|
|
|
const mdxFrontMatter = validateMDXFrontMatter(frontMatter.mdx);
|
|
|
|
const processor = await getProcessor({
|
|
filePath,
|
|
options,
|
|
mdxFrontMatter,
|
|
});
|
|
|
|
try {
|
|
return await processor.process({
|
|
content: preprocessedFileContent,
|
|
filePath,
|
|
frontMatter,
|
|
compilerName,
|
|
});
|
|
} catch (errorUnknown) {
|
|
const error = errorUnknown as Error;
|
|
|
|
// MDX can emit errors that have useful extra attributes
|
|
const errorJSON = JSON.stringify(error, null, 2);
|
|
const errorDetails =
|
|
errorJSON === '{}'
|
|
? // regular JS error case: print stacktrace
|
|
error.stack ?? 'N/A'
|
|
: // MDX error: print extra attributes + stacktrace
|
|
`${errorJSON}\n${error.stack}`;
|
|
|
|
throw new Error(
|
|
`MDX compilation failed for file ${logger.path(filePath)}\nCause: ${
|
|
error.message
|
|
}\nDetails:\n${errorDetails}`,
|
|
// TODO error cause doesn't seem to be used by Webpack stats.errors :s
|
|
{cause: error},
|
|
);
|
|
}
|
|
}
|
|
|
|
// TODO Docusaurus v4, remove temporary polyfill when upgrading to Node 22+
|
|
export interface PromiseWithResolvers<T> {
|
|
promise: Promise<T>;
|
|
resolve: (value: T | PromiseLike<T>) => void;
|
|
reject: (reason?: any) => void;
|
|
}
|
|
// TODO Docusaurus v4, remove temporary polyfill when upgrading to Node 22+
|
|
export function promiseWithResolvers<T>(): PromiseWithResolvers<T> {
|
|
// @ts-expect-error: it's fine
|
|
const out: PromiseWithResolvers<T> = {};
|
|
out.promise = new Promise((resolve, reject) => {
|
|
out.resolve = resolve;
|
|
out.reject = reject;
|
|
});
|
|
return out;
|
|
}
|