fumadocs-mdx 11.1.1 → 11.2.0

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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ getDefaultMDXOptions
3
+ } from "./chunk-MKWJLEE7.js";
4
+
1
5
  // src/config/cached.ts
2
6
  import { createHash } from "node:crypto";
3
7
  import fs from "node:fs";
@@ -6,39 +10,6 @@ import fs from "node:fs";
6
10
  import * as path from "node:path";
7
11
  import { pathToFileURL } from "node:url";
8
12
  import { build } from "esbuild";
9
-
10
- // src/config/validate.ts
11
- function validateConfig(config) {
12
- const out = {
13
- collections: /* @__PURE__ */ new Map(),
14
- _runtime: {
15
- files: /* @__PURE__ */ new Map()
16
- }
17
- };
18
- for (const [k, v] of Object.entries(config)) {
19
- if (!v) {
20
- continue;
21
- }
22
- if (typeof v === "object" && "_doc" in v && v._doc === "collections") {
23
- out.collections.set(
24
- k,
25
- v
26
- );
27
- continue;
28
- }
29
- if (k === "default") {
30
- out.global = v;
31
- continue;
32
- }
33
- return [
34
- `Unknown export "${k}", you can only export collections from source configuration file.`,
35
- null
36
- ];
37
- }
38
- return [null, out];
39
- }
40
-
41
- // src/config/load.ts
42
13
  function findConfigFile() {
43
14
  return path.resolve("source.config.ts");
44
15
  }
@@ -63,13 +34,48 @@ async function loadConfig(configPath) {
63
34
  throw new Error("failed to compile configuration file");
64
35
  }
65
36
  const url = pathToFileURL(outputPath);
66
- const [err, config] = validateConfig(
37
+ const [err, config] = buildConfig(
67
38
  // every call to `loadConfig` will cause the previous cache to be ignored
68
39
  await import(`${url.toString()}?hash=${Date.now().toString()}`)
69
40
  );
70
41
  if (err !== null) throw new Error(err);
71
42
  return config;
72
43
  }
44
+ function buildConfig(config) {
45
+ const collections = /* @__PURE__ */ new Map();
46
+ let globalConfig;
47
+ for (const [k, v] of Object.entries(config)) {
48
+ if (!v) {
49
+ continue;
50
+ }
51
+ if (typeof v === "object" && "_doc" in v && v._doc === "collections") {
52
+ collections.set(
53
+ k,
54
+ v
55
+ );
56
+ continue;
57
+ }
58
+ if (k === "default") {
59
+ globalConfig = v;
60
+ continue;
61
+ }
62
+ return [
63
+ `Unknown export "${k}", you can only export collections from source configuration file.`,
64
+ null
65
+ ];
66
+ }
67
+ return [
68
+ null,
69
+ {
70
+ global: globalConfig,
71
+ collections,
72
+ defaultMdxOptions: getDefaultMDXOptions(globalConfig?.mdxOptions ?? {}),
73
+ _runtime: {
74
+ files: /* @__PURE__ */ new Map()
75
+ }
76
+ }
77
+ ];
78
+ }
73
79
 
74
80
  // src/config/cached.ts
75
81
  var cache = /* @__PURE__ */ new Map();
@@ -1,52 +1,3 @@
1
- // src/utils/schema.ts
2
- import { z } from "zod";
3
- var metaSchema = z.object({
4
- title: z.string().optional(),
5
- pages: z.array(z.string()).optional(),
6
- description: z.string().optional(),
7
- root: z.boolean().optional(),
8
- defaultOpen: z.boolean().optional(),
9
- icon: z.string().optional()
10
- });
11
- var frontmatterSchema = z.object({
12
- title: z.string(),
13
- description: z.string().optional(),
14
- icon: z.string().optional(),
15
- full: z.boolean().optional(),
16
- // Fumadocs OpenAPI generated
17
- _openapi: z.object({}).passthrough().optional()
18
- });
19
-
20
- // src/config/define.ts
21
- function defineCollections(options) {
22
- return {
23
- _doc: "collections",
24
- // @ts-expect-error -- internal type inferring
25
- _type: void 0,
26
- ...options
27
- };
28
- }
29
- function defineDocs(options) {
30
- const dir = options?.dir ?? "content/docs";
31
- return {
32
- docs: defineCollections({
33
- type: "doc",
34
- dir,
35
- schema: frontmatterSchema,
36
- ...options?.docs
37
- }),
38
- meta: defineCollections({
39
- type: "meta",
40
- dir,
41
- schema: metaSchema,
42
- ...options?.meta
43
- })
44
- };
45
- }
46
- function defineConfig(config = {}) {
47
- return config;
48
- }
49
-
50
1
  // src/utils/mdx-options.ts
51
2
  import {
52
3
  rehypeCode,
@@ -161,10 +112,5 @@ function getDefaultMDXOptions({
161
112
  }
162
113
 
163
114
  export {
164
- metaSchema,
165
- frontmatterSchema,
166
- defineCollections,
167
- defineDocs,
168
- defineConfig,
169
115
  getDefaultMDXOptions
170
116
  };
@@ -1,5 +1,5 @@
1
- import { F as FileInfo, G as GlobalConfig, M as MarkdownProps, B as BaseCollectionEntry } from '../types-D11VoRzy.js';
2
- export { C as CollectionEntry, D as DefaultMDXOptions, b as GetOutput, I as InferSchema, a as InferSchemaType, g as getDefaultMDXOptions } from '../types-D11VoRzy.js';
1
+ import { F as FileInfo, G as GlobalConfig, M as MarkdownProps, B as BaseCollectionEntry } from '../types-BOXkLY5B.js';
2
+ export { C as CollectionEntry, D as DefaultMDXOptions, b as GetOutput, I as InferSchema, a as InferSchemaType, g as getDefaultMDXOptions } from '../types-BOXkLY5B.js';
3
3
  import { z, ZodTypeAny } from 'zod';
4
4
  import { ProcessorOptions } from '@mdx-js/mdx';
5
5
  import 'mdx/types';
@@ -21,6 +21,10 @@ interface MDXOptions extends ProcessorOptions {
21
21
  * Custom Vfile data
22
22
  */
23
23
  data?: Record<string, unknown>;
24
+ _compiler?: CompilerOptions;
25
+ }
26
+ interface CompilerOptions {
27
+ addDependency: (file: string) => void;
24
28
  }
25
29
 
26
30
  declare const metaSchema: z.ZodObject<{
@@ -1,11 +1,55 @@
1
1
  import {
2
- defineCollections,
3
- defineConfig,
4
- defineDocs,
5
- frontmatterSchema,
6
- getDefaultMDXOptions,
7
- metaSchema
8
- } from "../chunk-YA4EPE5U.js";
2
+ getDefaultMDXOptions
3
+ } from "../chunk-MKWJLEE7.js";
4
+
5
+ // src/utils/schema.ts
6
+ import { z } from "zod";
7
+ var metaSchema = z.object({
8
+ title: z.string().optional(),
9
+ pages: z.array(z.string()).optional(),
10
+ description: z.string().optional(),
11
+ root: z.boolean().optional(),
12
+ defaultOpen: z.boolean().optional(),
13
+ icon: z.string().optional()
14
+ });
15
+ var frontmatterSchema = z.object({
16
+ title: z.string(),
17
+ description: z.string().optional(),
18
+ icon: z.string().optional(),
19
+ full: z.boolean().optional(),
20
+ // Fumadocs OpenAPI generated
21
+ _openapi: z.object({}).passthrough().optional()
22
+ });
23
+
24
+ // src/config/define.ts
25
+ function defineCollections(options) {
26
+ return {
27
+ _doc: "collections",
28
+ // @ts-expect-error -- internal type inferring
29
+ _type: void 0,
30
+ ...options
31
+ };
32
+ }
33
+ function defineDocs(options) {
34
+ const dir = options?.dir ?? "content/docs";
35
+ return {
36
+ docs: defineCollections({
37
+ type: "doc",
38
+ dir,
39
+ schema: frontmatterSchema,
40
+ ...options?.docs
41
+ }),
42
+ meta: defineCollections({
43
+ type: "meta",
44
+ dir,
45
+ schema: metaSchema,
46
+ ...options?.meta
47
+ })
48
+ };
49
+ }
50
+ function defineConfig(config = {}) {
51
+ return config;
52
+ }
9
53
  export {
10
54
  defineCollections,
11
55
  defineConfig,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PageData, MetaData, Source } from 'fumadocs-core/source';
2
- import { F as FileInfo, B as BaseCollectionEntry } from './types-D11VoRzy.js';
2
+ import { F as FileInfo, B as BaseCollectionEntry } from './types-BOXkLY5B.js';
3
3
  import { MetaFile } from './loader-mdx.js';
4
4
  import 'zod';
5
5
  import 'mdx/types';
@@ -1,24 +1,43 @@
1
- import {
2
- getDefaultMDXOptions
3
- } from "./chunk-YA4EPE5U.js";
4
1
  import {
5
2
  getConfigHash,
6
3
  getManifestEntryPath,
7
4
  loadConfigCached
8
- } from "./chunk-QYUB4AKH.js";
5
+ } from "./chunk-BP4S5VOB.js";
6
+ import "./chunk-MKWJLEE7.js";
9
7
 
10
8
  // src/loader-mdx.ts
11
- import path2 from "node:path";
12
- import fs2 from "node:fs/promises";
9
+ import * as path3 from "node:path";
10
+ import * as fs2 from "node:fs/promises";
13
11
  import { parse } from "node:querystring";
14
12
  import grayMatter from "gray-matter";
15
13
 
16
14
  // src/utils/build-mdx.ts
17
15
  import { createProcessor } from "@mdx-js/mdx";
16
+ import { visit } from "unist-util-visit";
17
+ import { readFileSync } from "node:fs";
18
+ import * as path from "node:path";
19
+ import matter from "gray-matter";
18
20
  var cache = /* @__PURE__ */ new Map();
19
21
  function cacheKey(group, format) {
20
22
  return `${group}:${format}`;
21
23
  }
24
+ function remarkInclude(options) {
25
+ return (tree, file) => {
26
+ visit(tree, "mdxJsxFlowElement", (node) => {
27
+ if (node.name === "include") {
28
+ const child = node.children.at(0);
29
+ if (!child || child.type !== "text") return;
30
+ const specifier = child.value;
31
+ const targetPath = path.resolve(path.dirname(file.path), specifier);
32
+ const content = readFileSync(targetPath);
33
+ const parsed = this.parse(matter(content).content);
34
+ options.addDependency(targetPath);
35
+ Object.assign(node, parsed);
36
+ }
37
+ return "skip";
38
+ });
39
+ };
40
+ }
22
41
  function buildMDX(group, configHash, source, options = {}) {
23
42
  const { filePath, frontmatter, data, ...rest } = options;
24
43
  let format = options.format;
@@ -34,6 +53,10 @@ function buildMDX(group, configHash, source, options = {}) {
34
53
  outputFormat: "program",
35
54
  development: process.env.NODE_ENV === "development",
36
55
  ...rest,
56
+ remarkPlugins: [
57
+ options._compiler ? [remarkInclude, options._compiler] : null,
58
+ ...rest.remarkPlugins ?? []
59
+ ],
37
60
  format
38
61
  }),
39
62
  configHash
@@ -69,20 +92,20 @@ function formatError(file, error) {
69
92
  }
70
93
 
71
94
  // src/utils/git-timestamp.ts
72
- import path from "node:path";
95
+ import path2 from "node:path";
73
96
  import fs from "node:fs";
74
97
  import { spawn } from "cross-spawn";
75
98
  var cache2 = /* @__PURE__ */ new Map();
76
99
  function getGitTimestamp(file) {
77
100
  const cachedTimestamp = cache2.get(file);
78
101
  if (cachedTimestamp) return Promise.resolve(cachedTimestamp);
79
- return new Promise((resolve, reject) => {
80
- const cwd = path.dirname(file);
102
+ return new Promise((resolve3, reject) => {
103
+ const cwd = path2.dirname(file);
81
104
  if (!fs.existsSync(cwd)) {
82
- resolve(void 0);
105
+ resolve3(void 0);
83
106
  return;
84
107
  }
85
- const fileName = path.basename(file);
108
+ const fileName = path2.basename(file);
86
109
  const child = spawn("git", ["log", "-1", '--pretty="%ai"', fileName], {
87
110
  cwd
88
111
  });
@@ -90,14 +113,14 @@ function getGitTimestamp(file) {
90
113
  child.stdout.on("data", (d) => output = new Date(String(d)));
91
114
  child.on("close", () => {
92
115
  if (output) cache2.set(file, output);
93
- resolve(output);
116
+ resolve3(output);
94
117
  });
95
118
  child.on("error", reject);
96
119
  });
97
120
  }
98
121
 
99
122
  // src/loader-mdx.ts
100
- function getQuery(query) {
123
+ function parseQuery(query) {
101
124
  let collection;
102
125
  let hash;
103
126
  const parsed = parse(query.slice(1));
@@ -111,34 +134,35 @@ async function loader(source, callback) {
111
134
  const context = this.context;
112
135
  const filePath = this.resourcePath;
113
136
  const { _ctx } = this.getOptions();
114
- const matter = grayMatter(source);
115
- const query = getQuery(this.resourceQuery);
116
- const configHash = query.hash ?? await getConfigHash(_ctx.configPath);
137
+ const matter2 = grayMatter(source);
138
+ const {
139
+ hash: configHash = await getConfigHash(_ctx.configPath),
140
+ collection: collectionId
141
+ } = parseQuery(this.resourceQuery);
117
142
  const config = await loadConfigCached(_ctx.configPath, configHash);
118
- const collectionId = query.collection;
119
143
  let collection = collectionId !== void 0 ? config.collections.get(collectionId) : void 0;
120
144
  if (collection && collection.type !== "doc") {
121
145
  collection = void 0;
122
146
  }
123
- const mdxOptions = collection?.mdxOptions ?? getDefaultMDXOptions(config.global?.mdxOptions ?? {});
124
- function getTransformContext() {
125
- return {
126
- buildMDX: async (v, options = mdxOptions) => {
127
- const res = await buildMDX(
128
- collectionId ?? "global",
129
- configHash,
130
- v,
131
- options
132
- );
133
- return String(res.value);
134
- },
135
- source,
136
- path: filePath
137
- };
138
- }
139
- let frontmatter = matter.data;
147
+ const mdxOptions = collection?.mdxOptions ?? config.defaultMdxOptions;
148
+ let frontmatter = matter2.data;
140
149
  if (collection?.schema) {
141
- const schema = typeof collection.schema === "function" ? collection.schema(getTransformContext()) : collection.schema;
150
+ let schema = collection.schema;
151
+ if (typeof schema === "function") {
152
+ schema = schema({
153
+ async buildMDX(v, options = mdxOptions) {
154
+ const res = await buildMDX(
155
+ collectionId ?? "global",
156
+ configHash,
157
+ v,
158
+ options
159
+ );
160
+ return String(res.value);
161
+ },
162
+ source,
163
+ path: filePath
164
+ });
165
+ }
142
166
  const result = await schema.safeParseAsync(frontmatter);
143
167
  if (result.error) {
144
168
  callback(new Error(formatError(filePath, result.error)));
@@ -146,11 +170,11 @@ async function loader(source, callback) {
146
170
  }
147
171
  frontmatter = result.data;
148
172
  }
149
- const props = matter.data._mdx ?? {};
173
+ const props = matter2.data._mdx ?? {};
150
174
  if (props.mirror) {
151
- const mirrorPath = path2.resolve(path2.dirname(filePath), props.mirror);
175
+ const mirrorPath = path3.resolve(path3.dirname(filePath), props.mirror);
152
176
  this.addDependency(mirrorPath);
153
- matter.content = await fs2.readFile(mirrorPath).then((res) => grayMatter(res.toString()).content);
177
+ matter2.content = await fs2.readFile(mirrorPath).then((res) => grayMatter(res.toString()).content);
154
178
  }
155
179
  let timestamp;
156
180
  if (config.global?.lastModifiedTime === "git")
@@ -159,7 +183,7 @@ async function loader(source, callback) {
159
183
  const file = await buildMDX(
160
184
  collectionId ?? "global",
161
185
  configHash,
162
- matter.content,
186
+ matter2.content,
163
187
  {
164
188
  development: this.mode === "development",
165
189
  ...mdxOptions,
@@ -167,7 +191,8 @@ async function loader(source, callback) {
167
191
  frontmatter,
168
192
  data: {
169
193
  lastModified: timestamp
170
- }
194
+ },
195
+ _compiler: this
171
196
  }
172
197
  );
173
198
  callback(void 0, String(file.value), file.map ?? void 0);
@@ -183,7 +208,7 @@ async function loader(source, callback) {
183
208
  }
184
209
  } catch (error) {
185
210
  if (!(error instanceof Error)) throw error;
186
- const fpath = path2.relative(context, filePath);
211
+ const fpath = path3.relative(context, filePath);
187
212
  error.message = `${fpath}:${error.name}: ${error.message}`;
188
213
  callback(error);
189
214
  }
@@ -5,7 +5,8 @@ import {
5
5
  loadConfig,
6
6
  loadConfigCached,
7
7
  writeManifest
8
- } from "../chunk-QYUB4AKH.js";
8
+ } from "../chunk-BP4S5VOB.js";
9
+ import "../chunk-MKWJLEE7.js";
9
10
 
10
11
  // src/next/create.ts
11
12
  import path3 from "node:path";
@@ -19,7 +20,7 @@ import grayMatter from "gray-matter";
19
20
  // src/map/generate.ts
20
21
  import * as path from "node:path";
21
22
  import fg from "fast-glob";
22
- async function generateJS(configPath, config, outputPath, hash, getFrontmatter) {
23
+ async function generateJS(configPath, config, outputPath, configHash, getFrontmatter) {
23
24
  const outDir2 = path.dirname(outputPath);
24
25
  const imports = [
25
26
  {
@@ -36,7 +37,7 @@ async function generateJS(configPath, config, outputPath, hash, getFrontmatter)
36
37
  const items = files.map(async (file, i) => {
37
38
  config._runtime.files.set(file.absolutePath, k);
38
39
  if (collection.type === "doc" && collection.async) {
39
- const importPath = `${toImportPath(file.absolutePath, outDir2)}?hash=${hash}&collection=${k}`;
40
+ const importPath = `${toImportPath(file.absolutePath, outDir2)}?hash=${configHash}&collection=${k}`;
40
41
  const frontmatter = await getFrontmatter(file.absolutePath);
41
42
  return `toRuntimeAsync(${JSON.stringify(frontmatter)}, () => import(${JSON.stringify(importPath)}), ${JSON.stringify(file)})`;
42
43
  }
@@ -44,7 +45,7 @@ async function generateJS(configPath, config, outputPath, hash, getFrontmatter)
44
45
  imports.push({
45
46
  type: "namespace",
46
47
  name: importName,
47
- specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${k}&hash=${hash}`
48
+ specifier: `${toImportPath(file.absolutePath, outDir2)}?collection=${k}&hash=${configHash}`
48
49
  });
49
50
  return `toRuntime("${collection.type}", ${importName}, ${JSON.stringify(file)})`;
50
51
  });
@@ -148,9 +149,10 @@ async function start(dev, configPath, outDir2) {
148
149
  const { watcher } = await import("../watcher-7ALL6XOY.js");
149
150
  const instance = watcher(configPath, config);
150
151
  instance.on("ready", () => {
151
- if (!instance._readyEmitted) console.log("[MDX] started dev server");
152
+ console.log("[MDX] started dev server");
152
153
  });
153
154
  instance.on("all", (event, file) => {
155
+ if (typeof file !== "string") return;
154
156
  const onUpdate = async () => {
155
157
  const isConfigFile = path2.resolve(file) === configPath;
156
158
  if (isConfigFile) {
@@ -16,7 +16,7 @@ type DefaultMDXOptions = Omit<NonNullable<ProcessorOptions>, 'rehypePlugins' | '
16
16
  remarkStructureOptions?: StructureOptions | false;
17
17
  remarkHeadingOptions?: RemarkHeadingOptions;
18
18
  remarkImageOptions?: RemarkImageOptions | false;
19
- rehypeCodeOptions?: RehypeCodeOptions | false;
19
+ rehypeCodeOptions?: Partial<RehypeCodeOptions> | false;
20
20
  };
21
21
  declare function getDefaultMDXOptions({ valueToExport, rehypeCodeOptions, remarkImageOptions, remarkHeadingOptions, remarkStructureOptions, ...mdxOptions }: DefaultMDXOptions): ProcessorOptions;
22
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-mdx",
3
- "version": "11.1.1",
3
+ "version": "11.2.0",
4
4
  "description": "The built-in source for Fumadocs",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -36,27 +36,29 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@mdx-js/mdx": "^3.1.0",
39
- "chokidar": "^4.0.1",
40
- "cross-spawn": "^7.0.3",
41
- "esbuild": "^0.24.0",
42
- "estree-util-value-to-estree": "^3.1.2",
39
+ "chokidar": "^4.0.3",
40
+ "cross-spawn": "^7.0.6",
41
+ "esbuild": "^0.24.2",
42
+ "estree-util-value-to-estree": "^3.2.1",
43
43
  "fast-glob": "^3.3.1",
44
44
  "gray-matter": "^4.0.3",
45
45
  "micromatch": "^4.0.8",
46
- "zod": "^3.23.8"
46
+ "unist-util-visit": "^5.0.0",
47
+ "zod": "^3.24.1"
47
48
  },
48
49
  "devDependencies": {
49
50
  "@types/cross-spawn": "^6.0.6",
50
51
  "@types/mdast": "^4.0.3",
51
52
  "@types/mdx": "^2.0.13",
52
53
  "@types/micromatch": "^4.0.9",
53
- "@types/react": "^18.3.12",
54
- "next": "^15.0.1",
54
+ "@types/react": "^19.0.2",
55
+ "mdast-util-mdx-jsx": "^3.1.3",
56
+ "next": "^15.1.2",
55
57
  "unified": "^11.0.5",
56
58
  "vfile": "^6.0.3",
57
- "webpack": "^5.95.0",
59
+ "webpack": "^5.97.1",
58
60
  "eslint-config-custom": "0.0.0",
59
- "fumadocs-core": "14.1.1",
61
+ "fumadocs-core": "14.6.3",
60
62
  "tsconfig": "0.0.0"
61
63
  },
62
64
  "peerDependencies": {