mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 06:31:49 +00:00
Core: Improve AST plugins
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-core': patch
|
||||
---
|
||||
|
||||
Improve AST plugins
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Processor, Transformer } from 'unified';
|
||||
import type { BlockContent, Code, DefinitionContent, Root } from 'mdast';
|
||||
import type { BlockContent, Code, Root, RootContent } from 'mdast';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import type { MdxJsxFlowElement } from 'mdast-util-mdx';
|
||||
import { generateCodeBlockTabs, parseCodeBlockAttributes } from '@/mdx-plugins/codeblock-utils';
|
||||
|
||||
type TabType = keyof typeof Types;
|
||||
type TabType = 'CodeBlockTabs' | 'Tabs';
|
||||
export interface RemarkCodeTabOptions {
|
||||
Tabs?: TabType;
|
||||
|
||||
@@ -18,17 +18,54 @@ export interface RemarkCodeTabOptions {
|
||||
|
||||
declare module 'mdast' {
|
||||
export interface CodeData {
|
||||
/**
|
||||
* [Fumadocs: remark-code-tab] the associated tab value
|
||||
*/
|
||||
tab?: string;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
/**
|
||||
* [Fumadocs: remark-code-tab] internal
|
||||
*/
|
||||
_code_tab_visited?: true;
|
||||
}
|
||||
}
|
||||
|
||||
const Tabs = {
|
||||
convert(
|
||||
processor: Processor,
|
||||
nodes: Code[],
|
||||
withMdx = false,
|
||||
withParent = true,
|
||||
): MdxJsxFlowElement {
|
||||
type TabHandler = (
|
||||
processor: Processor,
|
||||
nodes: Code[],
|
||||
withMdx: boolean,
|
||||
withParent: boolean,
|
||||
) => RootContent[];
|
||||
|
||||
const Types: Record<TabType, TabHandler> = {
|
||||
CodeBlockTabs(processor, nodes, withMdx, withParent) {
|
||||
const tabs = Array.from(processTabValue(nodes).entries());
|
||||
|
||||
const node = generateCodeBlockTabs({
|
||||
defaultValue: tabs[0][0],
|
||||
triggers: tabs.map(([name]) => ({
|
||||
value: name,
|
||||
children: [
|
||||
withMdx
|
||||
? (mdxToAst(processor, name) as unknown as BlockContent)
|
||||
: {
|
||||
type: 'text',
|
||||
value: name,
|
||||
},
|
||||
],
|
||||
})),
|
||||
tabs: tabs.map(([name, codes]) => ({
|
||||
value: name,
|
||||
children: codes,
|
||||
})),
|
||||
});
|
||||
|
||||
if (!withParent) return node.children;
|
||||
return [node];
|
||||
},
|
||||
Tabs(processor, nodes, withMdx, withParent) {
|
||||
const tabs = Array.from(processTabValue(nodes).entries());
|
||||
|
||||
if (!withMdx) {
|
||||
@@ -47,42 +84,44 @@ const Tabs = {
|
||||
};
|
||||
});
|
||||
|
||||
if (!withParent) return createFragment(children);
|
||||
if (!withParent) return children;
|
||||
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tabs',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'items',
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
value: tabs.map(([name]) => name).join(', '),
|
||||
data: {
|
||||
estree: {
|
||||
type: 'Program',
|
||||
sourceType: 'module',
|
||||
comments: [],
|
||||
body: [
|
||||
{
|
||||
type: 'ExpressionStatement',
|
||||
expression: {
|
||||
type: 'ArrayExpression',
|
||||
elements: tabs.map(([name]) => ({
|
||||
type: 'Literal',
|
||||
value: name,
|
||||
})),
|
||||
return [
|
||||
{
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tabs',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'items',
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
value: tabs.map(([name]) => name).join(', '),
|
||||
data: {
|
||||
estree: {
|
||||
type: 'Program',
|
||||
sourceType: 'module',
|
||||
comments: [],
|
||||
body: [
|
||||
{
|
||||
type: 'ExpressionStatement',
|
||||
expression: {
|
||||
type: 'ArrayExpression',
|
||||
elements: tabs.map(([name]) => ({
|
||||
type: 'Literal',
|
||||
value: name,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
children,
|
||||
};
|
||||
],
|
||||
children,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const children: MdxJsxFlowElement[] = [
|
||||
@@ -120,61 +159,25 @@ const Tabs = {
|
||||
),
|
||||
];
|
||||
|
||||
if (!withParent) return createFragment(children);
|
||||
if (!withParent) return children;
|
||||
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tabs',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'defaultValue',
|
||||
value: tabs[0][0],
|
||||
},
|
||||
],
|
||||
children,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const CodeBlockTabs = {
|
||||
convert(
|
||||
processor: Processor,
|
||||
nodes: Code[],
|
||||
withMdx = false,
|
||||
withParent = true,
|
||||
): MdxJsxFlowElement {
|
||||
const tabs = Array.from(processTabValue(nodes).entries());
|
||||
|
||||
const node = generateCodeBlockTabs({
|
||||
defaultValue: tabs[0][0],
|
||||
triggers: tabs.map(([name]) => ({
|
||||
value: name,
|
||||
children: [
|
||||
withMdx
|
||||
? (mdxToAst(processor, name) as unknown as BlockContent)
|
||||
: {
|
||||
type: 'text',
|
||||
value: name,
|
||||
},
|
||||
return [
|
||||
{
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'Tabs',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'defaultValue',
|
||||
value: tabs[0][0],
|
||||
},
|
||||
],
|
||||
})),
|
||||
tabs: tabs.map(([name, codes]) => ({
|
||||
value: name,
|
||||
children: codes,
|
||||
})),
|
||||
});
|
||||
|
||||
if (!withParent) return createFragment(node.children);
|
||||
return node;
|
||||
children,
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
const Types = {
|
||||
CodeBlockTabs,
|
||||
Tabs,
|
||||
};
|
||||
|
||||
export function remarkCodeTab(
|
||||
this: Processor,
|
||||
options: RemarkCodeTabOptions = {},
|
||||
@@ -182,10 +185,8 @@ export function remarkCodeTab(
|
||||
const { parseMdx = false, Tabs = 'CodeBlockTabs' } = options;
|
||||
|
||||
return (tree) => {
|
||||
const ignored = new WeakSet();
|
||||
|
||||
visit(tree, (node) => {
|
||||
if (!('children' in node) || ignored.has(node)) return 'skip';
|
||||
if (!('children' in node) || node.data?._code_tab_visited) return 'skip';
|
||||
let localTabs: TabType = Tabs;
|
||||
let localParseMdx = parseMdx;
|
||||
let withParent = true;
|
||||
@@ -206,15 +207,19 @@ export function remarkCodeTab(
|
||||
let end = 0;
|
||||
const close = () => {
|
||||
if (start === -1 || start === end) return;
|
||||
const replacement = Types[localTabs].convert(
|
||||
const replacement = Types[localTabs](
|
||||
this,
|
||||
node.children.slice(start, end) as Code[],
|
||||
localParseMdx,
|
||||
withParent,
|
||||
);
|
||||
|
||||
ignored.add(replacement);
|
||||
node.children.splice(start, end - start, replacement);
|
||||
for (const element of replacement) {
|
||||
element.data ??= {};
|
||||
element.data._code_tab_visited = true;
|
||||
}
|
||||
|
||||
node.children.splice(start, end - start, ...replacement);
|
||||
end = start;
|
||||
start = -1;
|
||||
};
|
||||
@@ -272,12 +277,3 @@ function mdxToAst(processor: Processor, name: string) {
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function createFragment(children: (BlockContent | DefinitionContent)[]): MdxJsxFlowElement {
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: null,
|
||||
attributes: [],
|
||||
children,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { BlockContent, DefinitionContent, PhrasingContent, Root } from 'mdast';
|
||||
import type { MdxJsxAttribute, MdxJsxFlowElement } from 'mdast-util-mdx';
|
||||
import { Transformer } from 'unified';
|
||||
import type { Transformer } from 'unified';
|
||||
import { visit } from 'unist-util-visit';
|
||||
|
||||
export interface RemarkDirectiveAdmonitionOptions {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as path from 'node:path';
|
||||
import type { Image, Root } from 'mdast';
|
||||
import type { Image, Root, RootContent } from 'mdast';
|
||||
import type { Transformer } from 'unified';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import type { MdxjsEsm } from 'mdast-util-mdx';
|
||||
import type { ISizeCalculationResult } from 'image-size/types/interface';
|
||||
import type { MdxJsxAttribute, MdxJsxFlowElement } from 'mdast-util-mdx';
|
||||
import type { MdxJsxFlowElement } from 'mdast-util-mdx';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const VALID_BLUR_EXT = ['.jpeg', '.png', '.webp', '.avif', '.jpg'];
|
||||
@@ -90,23 +90,7 @@ export function remarkImage({
|
||||
const importsToInject: { variableName: string; importPath: string }[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
async function onImage(src: Source, node: Image): Promise<MdxJsxFlowElement | undefined> {
|
||||
const attributes: MdxJsxAttribute[] = [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'alt',
|
||||
value: node.alt ?? 'image',
|
||||
},
|
||||
];
|
||||
|
||||
if (node.title) {
|
||||
attributes.push({
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'title',
|
||||
value: node.title,
|
||||
});
|
||||
}
|
||||
|
||||
async function updateImage(src: Source, node: Image): Promise<RootContent | undefined> {
|
||||
if (src.type === 'file' && useImport) {
|
||||
// Unique variable name for the given static image URL
|
||||
const variableName = `__img${importsToInject.length}`;
|
||||
@@ -124,34 +108,47 @@ export function remarkImage({
|
||||
importPath: getImportPath(src.file, file.dirname),
|
||||
});
|
||||
|
||||
attributes.push({
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'src',
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
value: variableName,
|
||||
data: {
|
||||
estree: {
|
||||
body: [
|
||||
{
|
||||
type: 'ExpressionStatement',
|
||||
expression: { type: 'Identifier', name: variableName },
|
||||
},
|
||||
],
|
||||
type: 'Program',
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const out: MdxJsxFlowElement = {
|
||||
children: [],
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'img',
|
||||
attributes,
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'alt',
|
||||
value: node.alt ?? 'image',
|
||||
},
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'src',
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
value: variableName,
|
||||
data: {
|
||||
estree: {
|
||||
body: [
|
||||
{
|
||||
type: 'ExpressionStatement',
|
||||
expression: { type: 'Identifier', name: variableName },
|
||||
},
|
||||
],
|
||||
type: 'Program',
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (node.title) {
|
||||
out.attributes.push({
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'title',
|
||||
value: node.title,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasBlur) {
|
||||
out.attributes.push({
|
||||
type: 'mdxJsxAttribute',
|
||||
@@ -173,39 +170,20 @@ export function remarkImage({
|
||||
});
|
||||
|
||||
if (!size) return;
|
||||
|
||||
attributes.push(
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'src',
|
||||
// `src` doesn't support file paths, we can use `node.url` for files and let the underlying framework handle it
|
||||
value: src.type === 'url' ? src.url.toString() : node.url,
|
||||
},
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'width',
|
||||
value: size.width.toString(),
|
||||
},
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'height',
|
||||
value: size.height.toString(),
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'img',
|
||||
attributes,
|
||||
children: [],
|
||||
};
|
||||
node.data ??= {};
|
||||
node.data.hProperties ??= {};
|
||||
// `src` doesn't support file paths, we can use `node.url` for files and let the underlying framework handle it
|
||||
node.data.hProperties.src = src.type === 'url' ? src.url.href : node.url;
|
||||
node.data.hProperties.width = size.width.toString();
|
||||
node.data.hProperties.height = size.height.toString();
|
||||
}
|
||||
|
||||
visit(tree, 'image', (node) => {
|
||||
visit(tree, 'image', (node, idx, parent) => {
|
||||
if (typeof idx !== 'number' || !parent) return;
|
||||
const src = parseSrc(decodeURI(node.url), publicDir, file.dirname);
|
||||
if (!src) return;
|
||||
|
||||
const task = onImage(src, node)
|
||||
const task = updateImage(src, node)
|
||||
.catch((e) => {
|
||||
// ignore SVG as it is not always needed
|
||||
if (onError === 'ignore' || node.url.endsWith('.svg')) {
|
||||
@@ -213,19 +191,17 @@ export function remarkImage({
|
||||
}
|
||||
|
||||
if (onError === 'hide') {
|
||||
return {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: null,
|
||||
attributes: [],
|
||||
children: [],
|
||||
} satisfies MdxJsxFlowElement;
|
||||
parent.children.splice(idx, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (onError === 'error') throw e;
|
||||
onError(e);
|
||||
})
|
||||
.then((res) => {
|
||||
if (res) Object.assign(node, res);
|
||||
if (res) {
|
||||
parent.children[idx] = res;
|
||||
}
|
||||
});
|
||||
|
||||
promises.push(task);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { toMdxExport } from './utils';
|
||||
import type { Heading, Parents, Root } from 'mdast';
|
||||
import { defaultStringifier, type StringifyOptions } from './stringifier';
|
||||
import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx';
|
||||
import type { Info, State } from 'mdast-util-to-markdown';
|
||||
import { defaultHandlers, type Info, type State } from 'mdast-util-to-markdown';
|
||||
import type { PlaceholderData } from './remark-llms.runtime';
|
||||
|
||||
export interface LLMsOptions extends StringifyOptions {
|
||||
@@ -92,8 +92,8 @@ export function remarkLLMs(
|
||||
handlers: {
|
||||
heading(node: Heading, _p, state, info) {
|
||||
const id = node.data?.hProperties?.id;
|
||||
const content = state.containerPhrasing(node, info);
|
||||
return headingIds && id ? `${content} [#${id}]` : content;
|
||||
const defaultValue = defaultHandlers.heading(node, _p, state, info);
|
||||
return headingIds && id ? `${defaultValue} [#${id}]` : defaultValue;
|
||||
},
|
||||
...rest.handlers,
|
||||
},
|
||||
|
||||
@@ -32,10 +32,10 @@ export function remarkMdxMermaid(options: RemarkMdxMermaidOptions = {}): Transfo
|
||||
const { lang = 'mermaid' } = options;
|
||||
|
||||
return (tree) => {
|
||||
visit(tree, 'code', (node) => {
|
||||
if (node.lang !== lang || !node.value) return;
|
||||
visit(tree, 'code', (node, idx, parent) => {
|
||||
if (node.lang !== lang || !node.value || typeof idx !== 'number' || !parent) return;
|
||||
|
||||
Object.assign(node, toMDX(node.value));
|
||||
parent.children[idx] = toMDX(node.value);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ export interface RemarkNpmOptions {
|
||||
packageManagers?: PackageManager[];
|
||||
}
|
||||
|
||||
const aliases = ['npm', 'package-install'];
|
||||
|
||||
/**
|
||||
* It generates multiple tabs of codeblocks for different package managers from a npm command codeblock.
|
||||
*/
|
||||
@@ -48,13 +46,25 @@ export function remarkNpm({
|
||||
],
|
||||
}: RemarkNpmOptions = {}): Transformer<Root, Root> {
|
||||
return (tree) => {
|
||||
visit(tree, 'code', (node) => {
|
||||
if (!node.lang || !aliases.includes(node.lang)) return;
|
||||
let code = node.value;
|
||||
visit(tree, 'code', (node, idx, parent) => {
|
||||
if (typeof idx !== 'number' || !parent) return;
|
||||
let code: string;
|
||||
|
||||
if (node.lang === 'package-install' && !code.startsWith('npm') && !code.startsWith('npx')) {
|
||||
code = `npm install ${code}`;
|
||||
switch (node.lang) {
|
||||
case 'package-install':
|
||||
code = node.value;
|
||||
|
||||
if (!code.startsWith('npm') && !code.startsWith('npx')) {
|
||||
code = `npm install ${code}`;
|
||||
}
|
||||
break;
|
||||
case 'npm':
|
||||
code = node.value;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const options: CodeBlockTabsOptions = {
|
||||
persist,
|
||||
tabs: [],
|
||||
@@ -84,7 +94,7 @@ export function remarkNpm({
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(node, generateCodeBlockTabs(options));
|
||||
parent.children[idx] = generateCodeBlockTabs(options);
|
||||
return 'skip';
|
||||
});
|
||||
};
|
||||
|
||||
@@ -4,11 +4,11 @@ import remarkGfm from 'remark-gfm';
|
||||
import type { PluggableList, Processor, Transformer } from 'unified';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import { toMdxExport } from './utils';
|
||||
import {
|
||||
type MdxJsxAttribute,
|
||||
type MdxJsxExpressionAttribute,
|
||||
type MdxJsxFlowElement,
|
||||
type MdxJsxTextElement,
|
||||
import type {
|
||||
MdxJsxAttribute,
|
||||
MdxJsxExpressionAttribute,
|
||||
MdxJsxFlowElement,
|
||||
MdxJsxTextElement,
|
||||
} from 'mdast-util-mdx';
|
||||
import { remarkHeading } from './remark-heading';
|
||||
import {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "External",
|
||||
"data": {
|
||||
"hProperties": {
|
||||
"height": "630",
|
||||
"src": "https://fumadocs.dev/banner.png",
|
||||
"width": "1200",
|
||||
},
|
||||
},
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 25,
|
||||
"line": 1,
|
||||
"offset": 24,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "image",
|
||||
"url": "/banner.png",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 25,
|
||||
"line": 1,
|
||||
"offset": 24,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 1,
|
||||
"line": 2,
|
||||
"offset": 25,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"type": "root",
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<img alt="External" src="https://fumadocs.dev/banner.png" width="1200" height="630" />
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "Test",
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 20,
|
||||
"line": 1,
|
||||
"offset": 19,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "image",
|
||||
"url": "./test.png",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 20,
|
||||
"line": 1,
|
||||
"offset": 19,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "External",
|
||||
"data": {
|
||||
"hProperties": {
|
||||
"height": "630",
|
||||
"src": "https://fumadocs.dev/banner.png",
|
||||
"width": "1200",
|
||||
},
|
||||
},
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 45,
|
||||
"line": 3,
|
||||
"offset": 65,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 3,
|
||||
"offset": 21,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "image",
|
||||
"url": "https://fumadocs.dev/banner.png",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 45,
|
||||
"line": 3,
|
||||
"offset": 65,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 3,
|
||||
"offset": 21,
|
||||
},
|
||||
},
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "Inline",
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 30,
|
||||
"line": 5,
|
||||
"offset": 96,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 5,
|
||||
"offset": 67,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "image",
|
||||
"url": "./remark-image.svg",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 30,
|
||||
"line": 5,
|
||||
"offset": 96,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 5,
|
||||
"offset": 67,
|
||||
},
|
||||
},
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 1,
|
||||
"line": 6,
|
||||
"offset": 97,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"type": "root",
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||

|
||||
|
||||
<img alt="External" src="https://fumadocs.dev/banner.png" width="1200" height="630" />
|
||||
|
||||

|
||||
+7
-54
@@ -53,7 +53,6 @@
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "Test",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "alt",
|
||||
@@ -86,21 +85,7 @@
|
||||
],
|
||||
"children": [],
|
||||
"name": "img",
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 20,
|
||||
"line": 1,
|
||||
"offset": 19,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 1,
|
||||
"offset": 0,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "mdxJsxFlowElement",
|
||||
"url": "./test.png",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
@@ -121,30 +106,13 @@
|
||||
"children": [
|
||||
{
|
||||
"alt": "External",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "alt",
|
||||
"type": "mdxJsxAttribute",
|
||||
"value": "External",
|
||||
"data": {
|
||||
"hProperties": {
|
||||
"height": "630",
|
||||
"src": "https://fumadocs.dev/banner.png",
|
||||
"width": "1200",
|
||||
},
|
||||
{
|
||||
"name": "src",
|
||||
"type": "mdxJsxAttribute",
|
||||
"value": "https://fumadocs.dev/banner.png",
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"type": "mdxJsxAttribute",
|
||||
"value": "1200",
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "mdxJsxAttribute",
|
||||
"value": "630",
|
||||
},
|
||||
],
|
||||
"children": [],
|
||||
"name": "img",
|
||||
},
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 45,
|
||||
@@ -158,7 +126,7 @@
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "mdxJsxFlowElement",
|
||||
"type": "image",
|
||||
"url": "https://fumadocs.dev/banner.png",
|
||||
},
|
||||
],
|
||||
@@ -179,7 +147,6 @@
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"alt": "Inline",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "alt",
|
||||
@@ -212,21 +179,7 @@
|
||||
],
|
||||
"children": [],
|
||||
"name": "img",
|
||||
"position": {
|
||||
"end": {
|
||||
"column": 30,
|
||||
"line": 5,
|
||||
"offset": 96,
|
||||
},
|
||||
"start": {
|
||||
"column": 1,
|
||||
"line": 5,
|
||||
"offset": 67,
|
||||
},
|
||||
},
|
||||
"title": null,
|
||||
"type": "mdxJsxFlowElement",
|
||||
"url": "./remark-image.svg",
|
||||
},
|
||||
],
|
||||
"position": {
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
## Hello World
|
||||
|
||||
Below is a **MDX** component:
|
||||
|
||||
<MyPage title="test">
|
||||
|
||||
Binary file not shown.
@@ -85,9 +85,7 @@ test('Remark Steps', async () => {
|
||||
test('Remark Image: With Path', async () => {
|
||||
const file = path.resolve(cwd, './fixtures/remark-image.md');
|
||||
const content = await fs.readFile(file);
|
||||
const processor = remark()
|
||||
.use(remarkImage, { publicDir: path.resolve(cwd, './fixtures') })
|
||||
.use(remarkMdx);
|
||||
const processor = remark().use(remarkImage, { publicDir: path.resolve(cwd, './fixtures') });
|
||||
|
||||
const result = await processor.run(processor.parse(content), {
|
||||
path: file,
|
||||
@@ -100,31 +98,27 @@ test('Remark Image: With Path', async () => {
|
||||
|
||||
test('Remark Image: Without Import', async () => {
|
||||
const content = await fs.readFile(path.resolve(cwd, './fixtures/remark-image.md'));
|
||||
const result = await remark()
|
||||
.use(remarkImage, {
|
||||
publicDir: path.resolve(cwd, './fixtures'),
|
||||
useImport: false,
|
||||
})
|
||||
.use(remarkMdx)
|
||||
.process(content);
|
||||
const processor = remark().use(remarkImage, {
|
||||
publicDir: path.resolve(cwd, './fixtures'),
|
||||
useImport: false,
|
||||
});
|
||||
|
||||
await expect(result.value).toMatchFileSnapshot(
|
||||
path.resolve(cwd, './fixtures/remark-image-without-import.output.mdx'),
|
||||
const result = await processor.run(processor.parse(content));
|
||||
await expect(result).toMatchFileSnapshot(
|
||||
path.resolve(cwd, './fixtures/remark-image-without-import.output.json'),
|
||||
);
|
||||
});
|
||||
|
||||
test('Remark Image: `publicDir` with URL', async () => {
|
||||
const content = await fs.readFile(path.resolve(cwd, './fixtures/remark-image-public-dir.md'));
|
||||
const result = await remark()
|
||||
.use(remarkImage, {
|
||||
publicDir: 'https://fumadocs.dev',
|
||||
useImport: false,
|
||||
})
|
||||
.use(remarkMdx)
|
||||
.process(content);
|
||||
const processor = remark().use(remarkImage, {
|
||||
publicDir: 'https://fumadocs.dev',
|
||||
useImport: false,
|
||||
});
|
||||
|
||||
await expect(result.value).toMatchFileSnapshot(
|
||||
path.resolve(cwd, './fixtures/remark-image-public-dir.output.mdx'),
|
||||
const result = await processor.run(processor.parse(content));
|
||||
await expect(result).toMatchFileSnapshot(
|
||||
path.resolve(cwd, './fixtures/remark-image-public-dir.output.json'),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user