fumadocs-core 16.0.7 → 16.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breadcrumb.js +3 -3
- package/dist/chunk-A4G5V4FQ.js +47 -0
- package/dist/chunk-ADBHPKXG.js +78 -0
- package/dist/chunk-CH7YHH7V.js +222 -0
- package/dist/chunk-EFVXL2PP.js +144 -0
- package/dist/chunk-FUUVPEA5.js +29 -0
- package/dist/chunk-GLRQBLGN.js +59 -0
- package/dist/{chunk-JD3M54YF.js → chunk-HNZEUF6C.js} +4 -47
- package/dist/chunk-JOXPHQ2R.js +73 -0
- package/dist/chunk-ONG4RVCR.js +8 -0
- package/dist/chunk-SLIKY7GW.js +111 -0
- package/dist/chunk-TWIDBWFG.js +84 -0
- package/dist/chunk-VW3XKOZZ.js +214 -0
- package/dist/chunk-X2HFD5QJ.js +275 -0
- package/dist/chunk-XJ6ZQNEX.js +91 -0
- package/dist/content/github.d.ts +7 -1
- package/dist/content/github.js +2 -1
- package/dist/content/toc.js +2 -1
- package/dist/mdx-plugins/codeblock-utils.d.ts +29 -0
- package/dist/mdx-plugins/codeblock-utils.js +9 -0
- package/dist/mdx-plugins/index.d.ts +18 -247
- package/dist/mdx-plugins/index.js +42 -1326
- package/dist/mdx-plugins/rehype-code.d.ts +55 -0
- package/dist/mdx-plugins/rehype-code.js +15 -0
- package/dist/mdx-plugins/rehype-toc.d.ts +14 -0
- package/dist/mdx-plugins/rehype-toc.js +7 -0
- package/dist/mdx-plugins/remark-admonition.d.ts +18 -0
- package/dist/mdx-plugins/remark-admonition.js +8 -0
- package/dist/mdx-plugins/remark-code-tab.d.ts +30 -0
- package/dist/mdx-plugins/remark-code-tab.js +8 -0
- package/dist/mdx-plugins/remark-gfm.d.ts +1 -0
- package/dist/mdx-plugins/remark-gfm.js +7 -0
- package/dist/mdx-plugins/remark-heading.d.ts +31 -0
- package/dist/mdx-plugins/remark-heading.js +8 -0
- package/dist/mdx-plugins/remark-image.d.ts +57 -0
- package/dist/mdx-plugins/remark-image.js +7 -0
- package/dist/mdx-plugins/remark-mdx-files.d.ts +40 -0
- package/dist/mdx-plugins/remark-mdx-files.js +7 -0
- package/dist/mdx-plugins/remark-mdx-mermaid.d.ts +15 -0
- package/dist/mdx-plugins/remark-mdx-mermaid.js +7 -0
- package/dist/mdx-plugins/remark-npm.d.ts +31 -0
- package/dist/mdx-plugins/remark-npm.js +8 -0
- package/dist/mdx-plugins/remark-steps.d.ts +23 -0
- package/dist/mdx-plugins/remark-steps.js +7 -0
- package/dist/{remark-structure-BJxaB5zZ.d.ts → mdx-plugins/remark-structure.d.ts} +1 -1
- package/dist/mdx-plugins/remark-structure.js +10 -0
- package/dist/search/algolia.d.ts +1 -1
- package/dist/search/client.d.ts +1 -1
- package/dist/search/orama-cloud.d.ts +3 -2
- package/dist/search/server.d.ts +1 -1
- package/dist/search/server.js +3 -3
- package/dist/source/index.js +3 -3
- package/package.json +11 -7
- package/dist/remark-code-tab-DmyIyi6m.d.ts +0 -57
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flattenNode
|
|
3
|
+
} from "./chunk-A4G5V4FQ.js";
|
|
4
|
+
|
|
5
|
+
// src/mdx-plugins/remark-admonition.ts
|
|
6
|
+
import { visit } from "unist-util-visit";
|
|
7
|
+
function remarkAdmonition(options = {}) {
|
|
8
|
+
const tag = options.tag ?? ":::";
|
|
9
|
+
const typeMap = options.typeMap ?? {
|
|
10
|
+
info: "info",
|
|
11
|
+
warn: "warn",
|
|
12
|
+
note: "info",
|
|
13
|
+
tip: "info",
|
|
14
|
+
warning: "warn",
|
|
15
|
+
danger: "error"
|
|
16
|
+
};
|
|
17
|
+
function replaceNodes(nodes) {
|
|
18
|
+
if (nodes.length === 0) return;
|
|
19
|
+
let open = -1;
|
|
20
|
+
let attributes = [];
|
|
21
|
+
let hasIntercept = false;
|
|
22
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
23
|
+
if (nodes[i].type !== "paragraph") continue;
|
|
24
|
+
const text = flattenNode(nodes[i]);
|
|
25
|
+
const typeName = Object.keys(typeMap).find(
|
|
26
|
+
(type) => text.startsWith(`${tag}${type}`)
|
|
27
|
+
);
|
|
28
|
+
if (typeName) {
|
|
29
|
+
if (open !== -1) {
|
|
30
|
+
hasIntercept = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
open = i;
|
|
34
|
+
attributes.push({
|
|
35
|
+
type: "mdxJsxAttribute",
|
|
36
|
+
name: "type",
|
|
37
|
+
value: typeMap[typeName]
|
|
38
|
+
});
|
|
39
|
+
const meta = text.slice(`${tag}${typeName}`.length);
|
|
40
|
+
if (meta.startsWith("[") && meta.endsWith("]")) {
|
|
41
|
+
attributes.push({
|
|
42
|
+
type: "mdxJsxAttribute",
|
|
43
|
+
name: "title",
|
|
44
|
+
value: meta.slice(1, -1)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (open !== -1 && text === tag) {
|
|
49
|
+
const children = nodes.slice(open + 1, i);
|
|
50
|
+
nodes.splice(open, i - open + 1, {
|
|
51
|
+
type: "mdxJsxFlowElement",
|
|
52
|
+
name: "Callout",
|
|
53
|
+
attributes,
|
|
54
|
+
children: hasIntercept ? replaceNodes(children) : children
|
|
55
|
+
});
|
|
56
|
+
open = -1;
|
|
57
|
+
hasIntercept = false;
|
|
58
|
+
attributes = [];
|
|
59
|
+
i = open;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return (tree) => {
|
|
64
|
+
visit(tree, (node) => {
|
|
65
|
+
if (!("children" in node)) return;
|
|
66
|
+
replaceNodes(node.children);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
remarkAdmonition
|
|
73
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flattenNode,
|
|
3
|
+
toMdxExport
|
|
4
|
+
} from "./chunk-A4G5V4FQ.js";
|
|
5
|
+
|
|
6
|
+
// src/mdx-plugins/remark-structure.ts
|
|
7
|
+
import Slugger from "github-slugger";
|
|
8
|
+
import { remark } from "remark";
|
|
9
|
+
import remarkGfm from "remark-gfm";
|
|
10
|
+
import { visit } from "unist-util-visit";
|
|
11
|
+
function remarkStructure({
|
|
12
|
+
types = [
|
|
13
|
+
"heading",
|
|
14
|
+
"paragraph",
|
|
15
|
+
"blockquote",
|
|
16
|
+
"tableCell",
|
|
17
|
+
"mdxJsxFlowElement"
|
|
18
|
+
],
|
|
19
|
+
allowedMdxAttributes = (node) => {
|
|
20
|
+
if (!node.name) return false;
|
|
21
|
+
return ["TypeTable", "Callout"].includes(node.name);
|
|
22
|
+
},
|
|
23
|
+
exportAs = false
|
|
24
|
+
} = {}) {
|
|
25
|
+
const slugger = new Slugger();
|
|
26
|
+
if (Array.isArray(allowedMdxAttributes)) {
|
|
27
|
+
const arr = allowedMdxAttributes;
|
|
28
|
+
allowedMdxAttributes = (_node, attribute) => attribute.type === "mdxJsxAttribute" && arr.includes(attribute.name);
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(types)) {
|
|
31
|
+
const arr = types;
|
|
32
|
+
types = (node) => arr.includes(node.type);
|
|
33
|
+
}
|
|
34
|
+
return (tree, file) => {
|
|
35
|
+
slugger.reset();
|
|
36
|
+
const data = { contents: [], headings: [] };
|
|
37
|
+
let lastHeading;
|
|
38
|
+
if (file.data.frontmatter) {
|
|
39
|
+
const frontmatter = file.data.frontmatter;
|
|
40
|
+
if (frontmatter._openapi?.structuredData) {
|
|
41
|
+
data.headings.push(...frontmatter._openapi.structuredData.headings);
|
|
42
|
+
data.contents.push(...frontmatter._openapi.structuredData.contents);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
visit(tree, (element) => {
|
|
46
|
+
if (element.type === "root" || !types(element)) return;
|
|
47
|
+
if (element.type === "heading") {
|
|
48
|
+
element.data ||= {};
|
|
49
|
+
element.data.hProperties ||= {};
|
|
50
|
+
const properties = element.data.hProperties;
|
|
51
|
+
const content2 = flattenNode(element).trim();
|
|
52
|
+
const id = properties.id ?? slugger.slug(content2);
|
|
53
|
+
data.headings.push({
|
|
54
|
+
id,
|
|
55
|
+
content: content2
|
|
56
|
+
});
|
|
57
|
+
lastHeading = id;
|
|
58
|
+
return "skip";
|
|
59
|
+
}
|
|
60
|
+
if (element.data?._string) {
|
|
61
|
+
for (const content2 of element.data._string) {
|
|
62
|
+
data.contents.push({
|
|
63
|
+
heading: lastHeading,
|
|
64
|
+
content: content2
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return "skip";
|
|
68
|
+
}
|
|
69
|
+
if (element.type === "mdxJsxFlowElement" && element.name) {
|
|
70
|
+
data.contents.push(
|
|
71
|
+
...element.attributes.flatMap((attribute) => {
|
|
72
|
+
const value = typeof attribute.value === "string" ? attribute.value : attribute.value?.value;
|
|
73
|
+
if (!value || value.length === 0) return [];
|
|
74
|
+
if (allowedMdxAttributes && !allowedMdxAttributes(element, attribute))
|
|
75
|
+
return [];
|
|
76
|
+
return {
|
|
77
|
+
heading: lastHeading,
|
|
78
|
+
content: attribute.type === "mdxJsxAttribute" ? `${attribute.name}: ${value}` : value
|
|
79
|
+
};
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const content = flattenNode(element).trim();
|
|
85
|
+
if (content.length === 0) return;
|
|
86
|
+
data.contents.push({
|
|
87
|
+
heading: lastHeading,
|
|
88
|
+
content
|
|
89
|
+
});
|
|
90
|
+
return "skip";
|
|
91
|
+
});
|
|
92
|
+
file.data.structuredData = data;
|
|
93
|
+
if (exportAs) {
|
|
94
|
+
tree.children.unshift(
|
|
95
|
+
toMdxExport(
|
|
96
|
+
typeof exportAs === "string" ? exportAs : "structuredData",
|
|
97
|
+
data
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function structure(content, remarkPlugins = [], options = {}) {
|
|
104
|
+
const result = remark().use(remarkGfm).use(remarkPlugins).use(remarkStructure, options).processSync(content);
|
|
105
|
+
return result.data.structuredData;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export {
|
|
109
|
+
remarkStructure,
|
|
110
|
+
structure
|
|
111
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/mdx-plugins/codeblock-utils.ts
|
|
2
|
+
function generateCodeBlockTabs({
|
|
3
|
+
persist = false,
|
|
4
|
+
defaultValue,
|
|
5
|
+
triggers,
|
|
6
|
+
tabs,
|
|
7
|
+
...options
|
|
8
|
+
}) {
|
|
9
|
+
const attributes = [];
|
|
10
|
+
if (options.attributes) attributes.push(...options.attributes);
|
|
11
|
+
if (defaultValue) {
|
|
12
|
+
attributes.push({
|
|
13
|
+
type: "mdxJsxAttribute",
|
|
14
|
+
name: "defaultValue",
|
|
15
|
+
value: defaultValue
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (typeof persist === "object") {
|
|
19
|
+
attributes.push(
|
|
20
|
+
{
|
|
21
|
+
type: "mdxJsxAttribute",
|
|
22
|
+
name: "groupId",
|
|
23
|
+
value: persist.id
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: "mdxJsxAttribute",
|
|
27
|
+
name: "persist",
|
|
28
|
+
value: null
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const children = [
|
|
33
|
+
{
|
|
34
|
+
type: "mdxJsxFlowElement",
|
|
35
|
+
name: "CodeBlockTabsList",
|
|
36
|
+
attributes: [],
|
|
37
|
+
children: triggers.map(
|
|
38
|
+
(trigger) => ({
|
|
39
|
+
type: "mdxJsxFlowElement",
|
|
40
|
+
attributes: [
|
|
41
|
+
{ type: "mdxJsxAttribute", name: "value", value: trigger.value }
|
|
42
|
+
],
|
|
43
|
+
name: "CodeBlockTabsTrigger",
|
|
44
|
+
children: trigger.children
|
|
45
|
+
})
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
for (const tab of tabs) {
|
|
50
|
+
children.push({
|
|
51
|
+
type: "mdxJsxFlowElement",
|
|
52
|
+
name: "CodeBlockTab",
|
|
53
|
+
attributes: [
|
|
54
|
+
{ type: "mdxJsxAttribute", name: "value", value: tab.value }
|
|
55
|
+
],
|
|
56
|
+
children: tab.children
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
type: "mdxJsxFlowElement",
|
|
61
|
+
name: "CodeBlockTabs",
|
|
62
|
+
attributes,
|
|
63
|
+
children
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function parseCodeBlockAttributes(meta, allowedNames) {
|
|
67
|
+
let str = meta;
|
|
68
|
+
const StringRegex = /(?<=^|\s)(?<name>\w+)(?:=(?:"([^"]*)"|'([^']*)'))?/g;
|
|
69
|
+
const attributes = {};
|
|
70
|
+
str = str.replaceAll(StringRegex, (match, name, value_1, value_2) => {
|
|
71
|
+
if (allowedNames && !allowedNames.includes(name)) return match;
|
|
72
|
+
attributes[name] = value_1 ?? value_2 ?? null;
|
|
73
|
+
return "";
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
rest: str,
|
|
77
|
+
attributes
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
generateCodeBlockTabs,
|
|
83
|
+
parseCodeBlockAttributes
|
|
84
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// src/mdx-plugins/remark-image.ts
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { visit } from "unist-util-visit";
|
|
4
|
+
import { imageSize } from "image-size";
|
|
5
|
+
import { imageSizeFromFile } from "image-size/fromFile";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
var VALID_BLUR_EXT = [".jpeg", ".png", ".webp", ".avif", ".jpg"];
|
|
8
|
+
var EXTERNAL_URL_REGEX = /^https?:\/\//;
|
|
9
|
+
function remarkImage({
|
|
10
|
+
placeholder = "blur",
|
|
11
|
+
external = true,
|
|
12
|
+
useImport = true,
|
|
13
|
+
onError = "error",
|
|
14
|
+
publicDir = path.join(process.cwd(), "public")
|
|
15
|
+
} = {}) {
|
|
16
|
+
return async (tree, file) => {
|
|
17
|
+
const importsToInject = [];
|
|
18
|
+
const promises = [];
|
|
19
|
+
async function onImage(src, node) {
|
|
20
|
+
if (src.type === "file" && useImport) {
|
|
21
|
+
const variableName = `__img${importsToInject.length}`;
|
|
22
|
+
const hasBlur = placeholder === "blur" && VALID_BLUR_EXT.some((ext) => src.file.endsWith(ext));
|
|
23
|
+
if (!file.dirname) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"When `useImport` is enabled, you must specify `dirname` in the VFile passed to compiler."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
importsToInject.push({
|
|
29
|
+
variableName,
|
|
30
|
+
importPath: getImportPath(src.file, file.dirname)
|
|
31
|
+
});
|
|
32
|
+
const out = {
|
|
33
|
+
children: [],
|
|
34
|
+
type: "mdxJsxFlowElement",
|
|
35
|
+
name: "img",
|
|
36
|
+
attributes: [
|
|
37
|
+
{
|
|
38
|
+
type: "mdxJsxAttribute",
|
|
39
|
+
name: "alt",
|
|
40
|
+
value: node.alt ?? "image"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "mdxJsxAttribute",
|
|
44
|
+
name: "src",
|
|
45
|
+
value: {
|
|
46
|
+
type: "mdxJsxAttributeValueExpression",
|
|
47
|
+
value: variableName,
|
|
48
|
+
data: {
|
|
49
|
+
estree: {
|
|
50
|
+
body: [
|
|
51
|
+
{
|
|
52
|
+
type: "ExpressionStatement",
|
|
53
|
+
expression: { type: "Identifier", name: variableName }
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
type: "Program",
|
|
57
|
+
sourceType: "script"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
if (hasBlur) {
|
|
65
|
+
out.attributes.push({
|
|
66
|
+
type: "mdxJsxAttribute",
|
|
67
|
+
name: "placeholder",
|
|
68
|
+
value: "blur"
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
const size = await getImageSize(src, external).catch((e) => {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`[Remark Image] Failed obtain image size for ${node.url} (public directory configured as ${publicDir})`,
|
|
76
|
+
{
|
|
77
|
+
cause: e
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
if (!size) return;
|
|
82
|
+
return {
|
|
83
|
+
type: "mdxJsxFlowElement",
|
|
84
|
+
name: "img",
|
|
85
|
+
attributes: [
|
|
86
|
+
{
|
|
87
|
+
type: "mdxJsxAttribute",
|
|
88
|
+
name: "alt",
|
|
89
|
+
value: node.alt ?? "image"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: "mdxJsxAttribute",
|
|
93
|
+
name: "src",
|
|
94
|
+
// `src` doesn't support file paths, we can use `node.url` for files and let the underlying framework handle it
|
|
95
|
+
value: src.type === "url" ? src.url.toString() : node.url
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: "mdxJsxAttribute",
|
|
99
|
+
name: "width",
|
|
100
|
+
value: size.width.toString()
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: "mdxJsxAttribute",
|
|
104
|
+
name: "height",
|
|
105
|
+
value: size.height.toString()
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
children: []
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
visit(tree, "image", (node) => {
|
|
112
|
+
const src = parseSrc(decodeURI(node.url), publicDir, file.dirname);
|
|
113
|
+
if (!src) return;
|
|
114
|
+
const task = onImage(src, node).catch((e) => {
|
|
115
|
+
if (onError === "ignore" || node.url.endsWith(".svg")) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (onError === "hide") {
|
|
119
|
+
return {
|
|
120
|
+
type: "mdxJsxFlowElement",
|
|
121
|
+
name: null,
|
|
122
|
+
attributes: [],
|
|
123
|
+
children: []
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (onError === "error") throw e;
|
|
127
|
+
onError(e);
|
|
128
|
+
}).then((res) => {
|
|
129
|
+
if (res) Object.assign(node, res);
|
|
130
|
+
});
|
|
131
|
+
promises.push(task);
|
|
132
|
+
});
|
|
133
|
+
await Promise.all(promises);
|
|
134
|
+
if (importsToInject.length === 0) return;
|
|
135
|
+
const imports = importsToInject.map(
|
|
136
|
+
({ variableName, importPath }) => ({
|
|
137
|
+
type: "mdxjsEsm",
|
|
138
|
+
data: {
|
|
139
|
+
estree: {
|
|
140
|
+
body: [
|
|
141
|
+
{
|
|
142
|
+
type: "ImportDeclaration",
|
|
143
|
+
source: { type: "Literal", value: importPath },
|
|
144
|
+
specifiers: [
|
|
145
|
+
{
|
|
146
|
+
type: "ImportDefaultSpecifier",
|
|
147
|
+
local: { type: "Identifier", name: variableName }
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
tree.children.unshift(...imports);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function getImportPath(file, dir) {
|
|
160
|
+
const relative2 = path.relative(dir, file).replaceAll(path.sep, "/");
|
|
161
|
+
return relative2.startsWith("../") ? relative2 : `./${relative2}`;
|
|
162
|
+
}
|
|
163
|
+
function parseSrc(src, publicDir, dir) {
|
|
164
|
+
if (src.startsWith("file:///"))
|
|
165
|
+
return { type: "file", file: fileURLToPath(src) };
|
|
166
|
+
if (EXTERNAL_URL_REGEX.test(src)) {
|
|
167
|
+
return {
|
|
168
|
+
type: "url",
|
|
169
|
+
url: new URL(src)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (src.startsWith("/")) {
|
|
173
|
+
if (EXTERNAL_URL_REGEX.test(publicDir)) {
|
|
174
|
+
const url = new URL(publicDir);
|
|
175
|
+
const segs = [...url.pathname.split("/"), ...src.split("/")].filter(
|
|
176
|
+
(v) => v.length > 0
|
|
177
|
+
);
|
|
178
|
+
url.pathname = `/${segs.join("/")}`;
|
|
179
|
+
return { type: "url", url };
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
type: "file",
|
|
183
|
+
file: path.join(publicDir, src)
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (!dir) {
|
|
187
|
+
console.warn(
|
|
188
|
+
`[Remark Image] found relative path ${src} but missing 'dirname' in VFile, this image will be skipped for now.`
|
|
189
|
+
);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
type: "file",
|
|
194
|
+
file: path.join(dir, src)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function getImageSize(src, onExternal) {
|
|
198
|
+
if (src.type === "file") return imageSizeFromFile(src.file);
|
|
199
|
+
if (onExternal === false) return;
|
|
200
|
+
const { timeout } = typeof onExternal === "object" ? onExternal : {};
|
|
201
|
+
const res = await fetch(src.url, {
|
|
202
|
+
signal: typeof timeout === "number" ? AbortSignal.timeout(timeout) : void 0
|
|
203
|
+
});
|
|
204
|
+
if (!res.ok) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`[Remark Image] Failed to fetch ${src.url} (${res.status}): ${await res.text()}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
return imageSize(new Uint8Array(await res.arrayBuffer()));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export {
|
|
213
|
+
remarkImage
|
|
214
|
+
};
|