fumadocs-mdx 11.7.1 → 11.7.3

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.
@@ -8,13 +8,16 @@ import {
8
8
  toImportPath
9
9
  } from "../chunk-OWZSTKKX.js";
10
10
  import {
11
- buildConfig
12
- } from "../chunk-GWR7KMRU.js";
11
+ getGitTimestamp
12
+ } from "../chunk-VUEZTR2H.js";
13
13
  import {
14
14
  ValidationError,
15
15
  validate
16
16
  } from "../chunk-ZOWJF3OH.js";
17
17
  import "../chunk-AVMO2SRO.js";
18
+ import {
19
+ buildConfig
20
+ } from "../chunk-JFNBRKRV.js";
18
21
  import {
19
22
  fumaMatter
20
23
  } from "../chunk-KVWX6THC.js";
@@ -22,16 +25,144 @@ import {
22
25
  // src/vite/index.ts
23
26
  import { parse } from "querystring";
24
27
  import { z } from "zod";
25
- import fs from "fs/promises";
26
- import path from "path";
28
+ import * as fs from "fs/promises";
29
+ import * as path from "path";
27
30
  import { load } from "js-yaml";
28
- var fileRegex = /\.(md|mdx)$/;
31
+
32
+ // src/vite/generate-glob.ts
33
+ function generateGlob(name, collection) {
34
+ const patterns = mapGlobPatterns(getGlobPatterns(collection));
35
+ const options = {
36
+ query: {
37
+ collection: name
38
+ },
39
+ base: getGlobBase(collection)
40
+ };
41
+ if (collection.type === "meta") {
42
+ options.import = "default";
43
+ }
44
+ return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(options, null, 2)})`;
45
+ }
46
+ function mapGlobPatterns(patterns) {
47
+ return patterns.map((file) => {
48
+ if (file.startsWith("./")) return file;
49
+ if (file.startsWith("/")) return `.${file}`;
50
+ return `./${file}`;
51
+ });
52
+ }
53
+ function getGlobBase(collection) {
54
+ let dir = collection.dir;
55
+ if (Array.isArray(dir)) {
56
+ if (dir.length !== 1)
57
+ throw new Error(
58
+ `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
59
+ );
60
+ dir = dir[0];
61
+ }
62
+ if (!dir.startsWith("./") && !dir.startsWith("/")) {
63
+ return "/" + dir;
64
+ }
65
+ return dir;
66
+ }
67
+
68
+ // src/vite/index.ts
29
69
  var onlySchema = z.literal(["frontmatter", "all"]);
30
70
  function mdx(config, options = {}) {
31
71
  const { generateIndexFile = true, configPath = "source.config.ts" } = options;
32
- const [err, loaded] = buildConfig(config);
33
- if (err || !loaded) {
34
- throw new Error(err);
72
+ const loaded = buildConfig(config);
73
+ async function transformMeta(path2, query, value) {
74
+ const isJson = path2.endsWith(".json");
75
+ const parsed = parse(query);
76
+ const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
77
+ if (!collection) return null;
78
+ let schema;
79
+ switch (collection.type) {
80
+ case "meta":
81
+ schema = collection.schema;
82
+ break;
83
+ case "docs":
84
+ schema = collection.meta.schema;
85
+ break;
86
+ }
87
+ if (!schema) return null;
88
+ let data;
89
+ try {
90
+ data = isJson ? JSON.parse(value) : load(value);
91
+ } catch {
92
+ return null;
93
+ }
94
+ const out = await validate(
95
+ schema,
96
+ data,
97
+ { path: path2, source: value },
98
+ `invalid data in ${path2}`
99
+ );
100
+ return {
101
+ code: isJson ? JSON.stringify(out) : `export default ${JSON.stringify(out)}`,
102
+ map: null
103
+ };
104
+ }
105
+ async function transformContent(file, query, value) {
106
+ const matter = fumaMatter(value);
107
+ const isDevelopment = this.environment.mode === "dev";
108
+ const parsed = parse(query);
109
+ const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
110
+ const only = parsed.only ? onlySchema.parse(parsed.only) : "all";
111
+ let schema;
112
+ let mdxOptions;
113
+ switch (collection?.type) {
114
+ case "doc":
115
+ mdxOptions = collection.mdxOptions;
116
+ schema = collection.schema;
117
+ break;
118
+ case "docs":
119
+ mdxOptions = collection.docs.mdxOptions;
120
+ schema = collection.docs.schema;
121
+ break;
122
+ }
123
+ if (schema) {
124
+ matter.data = await validate(
125
+ schema,
126
+ matter.data,
127
+ {
128
+ source: value,
129
+ path: file
130
+ },
131
+ `invalid frontmatter in ${file}`
132
+ );
133
+ }
134
+ if (only === "frontmatter") {
135
+ return {
136
+ code: `export const frontmatter = ${JSON.stringify(matter.data)}`,
137
+ map: null
138
+ };
139
+ }
140
+ const data = {};
141
+ if (loaded.global.lastModifiedTime === "git") {
142
+ data.lastModified = (await getGitTimestamp(file))?.getTime();
143
+ }
144
+ mdxOptions ??= await loaded.getDefaultMDXOptions();
145
+ const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
146
+ const compiled = await buildMDX(
147
+ parsed.collection ?? "global",
148
+ "\n".repeat(lineOffset) + matter.content,
149
+ {
150
+ development: isDevelopment,
151
+ ...mdxOptions,
152
+ data,
153
+ filePath: file,
154
+ frontmatter: matter.data,
155
+ _compiler: {
156
+ addDependency: (file2) => {
157
+ this.addWatchFile(file2);
158
+ }
159
+ }
160
+ }
161
+ );
162
+ return {
163
+ code: String(compiled.value),
164
+ map: compiled.map
165
+ };
35
166
  }
36
167
  return {
37
168
  name: "fumadocs-mdx",
@@ -43,6 +174,7 @@ function mdx(config, options = {}) {
43
174
  const outdir = process.cwd();
44
175
  const outFile = "source.generated.ts";
45
176
  const lines = [
177
+ '/// <reference types="vite/client" />',
46
178
  `import { fromConfig } from 'fumadocs-mdx/runtime/vite';`,
47
179
  `import type * as Config from '${toImportPath(configPath, {
48
180
  relativeTo: outdir
@@ -78,139 +210,22 @@ ${args}
78
210
  await fs.writeFile(path.join(outdir, outFile), lines.join("\n"));
79
211
  },
80
212
  async transform(value, id) {
81
- const [path2, query = ""] = id.split("?");
82
- const isJson = path2.endsWith(".json");
83
- const isYaml = path2.endsWith(".yaml");
84
- if (isJson || isYaml) {
85
- const parsed2 = parse(query);
86
- const collection2 = parsed2.collection ? loaded.collections.get(parsed2.collection) : void 0;
87
- if (!collection2) return null;
88
- let schema2;
89
- switch (collection2.type) {
90
- case "meta":
91
- schema2 = collection2.schema;
92
- break;
93
- case "docs":
94
- schema2 = collection2.meta.schema;
95
- break;
213
+ const [file, query = ""] = id.split("?");
214
+ const ext = path.extname(file);
215
+ try {
216
+ if ([".yaml", ".json"].includes(ext))
217
+ return await transformMeta(file, query, value);
218
+ if ([".md", ".mdx"].includes(ext))
219
+ return await transformContent.call(this, file, query, value);
220
+ } catch (e) {
221
+ if (e instanceof ValidationError) {
222
+ throw new Error(e.toStringFormatted());
96
223
  }
97
- if (!schema2) return null;
98
- let data;
99
- try {
100
- data = isJson ? JSON.parse(value) : load(value);
101
- } catch {
102
- return null;
103
- }
104
- const out = await validate(
105
- schema2,
106
- data,
107
- { path: path2, source: value },
108
- `invalid data in ${path2}`
109
- );
110
- return {
111
- code: isJson ? JSON.stringify(out) : `export default ${JSON.stringify(out)}`,
112
- map: null
113
- };
114
- }
115
- if (!fileRegex.test(path2)) return;
116
- const matter = fumaMatter(value);
117
- const isDevelopment = this.environment.mode === "dev";
118
- const parsed = parse(query);
119
- const collection = parsed.collection ? loaded.collections.get(parsed.collection) : void 0;
120
- const only = parsed.only ? onlySchema.parse(parsed.only) : "all";
121
- let schema;
122
- let mdxOptions;
123
- switch (collection?.type) {
124
- case "doc":
125
- mdxOptions = collection.mdxOptions;
126
- schema = collection.schema;
127
- break;
128
- case "docs":
129
- mdxOptions = collection.docs.mdxOptions;
130
- schema = collection.docs.schema;
131
- break;
224
+ throw e;
132
225
  }
133
- if (schema) {
134
- try {
135
- matter.data = await validate(
136
- schema,
137
- matter.data,
138
- {
139
- source: value,
140
- path: path2
141
- },
142
- `invalid frontmatter in ${path2}`
143
- );
144
- } catch (e) {
145
- if (e instanceof ValidationError) {
146
- throw new Error(e.toStringFormatted());
147
- }
148
- throw e;
149
- }
150
- }
151
- if (only === "frontmatter") {
152
- return {
153
- code: `export const frontmatter = ${JSON.stringify(matter.data)}`
154
- };
155
- }
156
- mdxOptions ??= await loaded.getDefaultMDXOptions();
157
- const lineOffset = isDevelopment ? countLines(matter.matter) : 0;
158
- const file = await buildMDX(
159
- parsed.collection ?? "global",
160
- "\n".repeat(lineOffset) + matter.content,
161
- {
162
- development: isDevelopment,
163
- ...mdxOptions,
164
- filePath: path2,
165
- frontmatter: matter.data,
166
- _compiler: {
167
- addDependency: (file2) => {
168
- this.addWatchFile(file2);
169
- }
170
- }
171
- }
172
- );
173
- return {
174
- code: String(file.value),
175
- map: file.map
176
- };
177
226
  }
178
227
  };
179
228
  }
180
- function generateGlob(name, collection) {
181
- const patterns = mapGlobPatterns(getGlobPatterns(collection));
182
- const options = {
183
- query: {
184
- collection: name
185
- },
186
- base: getGlobBase(collection)
187
- };
188
- if (collection.type === "meta") {
189
- options.import = "default";
190
- }
191
- return `import.meta.glob(${JSON.stringify(patterns)}, ${JSON.stringify(options, null, 2)})`;
192
- }
193
- function mapGlobPatterns(patterns) {
194
- return patterns.map((file) => {
195
- if (file.startsWith("./")) return file;
196
- if (file.startsWith("/")) return `.${file}`;
197
- return `./${file}`;
198
- });
199
- }
200
- function getGlobBase(collection) {
201
- let dir = collection.dir;
202
- if (Array.isArray(dir)) {
203
- if (dir.length !== 1)
204
- throw new Error(
205
- `[Fumadocs MDX] Vite Plugin doesn't support multiple \`dir\` for a collection at the moment.`
206
- );
207
- dir = dir[0];
208
- }
209
- if (!dir.startsWith("./") && !dir.startsWith("/")) {
210
- return "/" + dir;
211
- }
212
- return dir;
213
- }
214
229
  export {
215
230
  mdx as default
216
231
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-mdx",
3
- "version": "11.7.1",
3
+ "version": "11.7.3",
4
4
  "description": "The built-in source for Fumadocs",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -62,24 +62,25 @@
62
62
  "tinyexec": "^1.0.1",
63
63
  "tinyglobby": "^0.2.14",
64
64
  "unist-util-visit": "^5.0.0",
65
- "zod": "^4.0.10"
65
+ "zod": "^4.0.14"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/js-yaml": "^4.0.9",
69
69
  "@types/mdast": "^4.0.3",
70
70
  "@types/mdx": "^2.0.13",
71
71
  "@types/node": "^24.1.0",
72
- "@types/react": "^19.1.8",
72
+ "@types/react": "^19.1.9",
73
73
  "mdast-util-mdx-jsx": "^3.2.0",
74
- "next": "^15.4.4",
75
- "react": "^19.1.0",
74
+ "next": "^15.4.5",
75
+ "react": "^19.1.1",
76
+ "rollup": "^4.46.2",
76
77
  "unified": "^11.0.5",
77
78
  "vfile": "^6.0.3",
78
79
  "vite": "^7.0.5",
79
- "webpack": "^5.100.2",
80
+ "webpack": "^5.101.0",
80
81
  "@fumadocs/mdx-remote": "1.4.0",
81
82
  "eslint-config-custom": "0.0.0",
82
- "fumadocs-core": "15.6.6",
83
+ "fumadocs-core": "15.6.7",
83
84
  "tsconfig": "0.0.0"
84
85
  },
85
86
  "peerDependencies": {
@@ -1,51 +0,0 @@
1
- // src/config/build.ts
2
- function buildConfig(config) {
3
- const collections = /* @__PURE__ */ new Map();
4
- let globalConfig;
5
- for (const [k, v] of Object.entries(config)) {
6
- if (!v) {
7
- continue;
8
- }
9
- if (typeof v === "object" && "type" in v) {
10
- if (v.type === "docs") {
11
- collections.set(k, v);
12
- continue;
13
- }
14
- if (v.type === "doc" || v.type === "meta") {
15
- collections.set(k, v);
16
- continue;
17
- }
18
- }
19
- if (k === "default") {
20
- globalConfig = v;
21
- continue;
22
- }
23
- return [
24
- `Unknown export "${k}", you can only export collections from source configuration file.`,
25
- null
26
- ];
27
- }
28
- let cachedMdxOptions;
29
- return [
30
- null,
31
- {
32
- global: globalConfig,
33
- collections,
34
- async getDefaultMDXOptions() {
35
- if (cachedMdxOptions) return cachedMdxOptions;
36
- const input = this.global?.mdxOptions;
37
- async function uncached() {
38
- const options = typeof input === "function" ? await input() : input;
39
- const { getDefaultMDXOptions } = await import("./mdx-options-UDV5WEFU.js");
40
- if (options?.preset === "minimal") return options;
41
- return getDefaultMDXOptions(options ?? {});
42
- }
43
- return cachedMdxOptions = uncached();
44
- }
45
- }
46
- ];
47
- }
48
-
49
- export {
50
- buildConfig
51
- };