fumadocs-mdx 11.6.4 → 11.6.6

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.
@@ -55,8 +55,32 @@ async function getConfigHash(configPath) {
55
55
  throw new Error("Cannot find config file");
56
56
  }
57
57
 
58
+ // src/utils/git-timestamp.ts
59
+ import path2 from "path";
60
+ import { x } from "tinyexec";
61
+ var cache2 = /* @__PURE__ */ new Map();
62
+ async function getGitTimestamp(file) {
63
+ const cached = cache2.get(file);
64
+ if (cached) return cached;
65
+ try {
66
+ const out = await x(
67
+ "git",
68
+ ["log", "-1", '--pretty="%ai"', path2.relative(process.cwd(), file)],
69
+ {
70
+ throwOnError: true
71
+ }
72
+ );
73
+ const time = new Date(out.stdout);
74
+ cache2.set(file, time);
75
+ return time;
76
+ } catch {
77
+ return;
78
+ }
79
+ }
80
+
58
81
  export {
59
82
  findConfigFile,
60
83
  loadConfig,
61
- getConfigHash
84
+ getConfigHash,
85
+ getGitTimestamp
62
86
  };
@@ -22,22 +22,20 @@ var ValidationError = class extends Error {
22
22
  super(message);
23
23
  this.issues = issues;
24
24
  }
25
- print() {
26
- console.error(
27
- [
28
- `[MDX] ${this.message}:`,
29
- ...this.issues.map(
30
- (issue) => picocolors.redBright(
31
- `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
32
- )
33
- )
34
- ].join("\n")
35
- );
36
- }
37
25
  toString() {
38
26
  return `${this.message}:
39
27
  ${this.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`;
40
28
  }
29
+ toStringFormatted() {
30
+ return [
31
+ picocolors.bold(`[MDX] ${this.message}:`),
32
+ ...this.issues.map(
33
+ (issue) => picocolors.redBright(
34
+ `- ${picocolors.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
35
+ )
36
+ )
37
+ ].join("\n");
38
+ }
41
39
  };
42
40
  async function validate(schema, data, context, errorMessage) {
43
41
  if (typeof schema === "function" && !("~standard" in schema)) {
@@ -99,7 +99,7 @@ function getDefaultMDXOptions({
99
99
  (v) => [
100
100
  rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
101
101
  ...v,
102
- [plugins.rehypeToc]
102
+ plugins.rehypeToc
103
103
  ],
104
104
  mdxOptions.rehypePlugins
105
105
  );
@@ -198,7 +198,7 @@ function getDefaultMDXOptions({
198
198
  (v) => [
199
199
  rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
200
200
  ...v,
201
- [plugins.rehypeToc]
201
+ plugins.rehypeToc
202
202
  ],
203
203
  mdxOptions.rehypePlugins
204
204
  );
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  frontmatterSchema,
3
3
  metaSchema
4
- } from "../chunk-2ZOW45YZ.js";
4
+ } from "../chunk-OTM6WYMS.js";
5
5
  import {
6
6
  remarkInclude
7
7
  } from "../chunk-3UUEUK4M.js";
8
8
  import {
9
9
  getDefaultMDXOptions
10
- } from "../chunk-7UCWBLFI.js";
10
+ } from "../chunk-VC3Y6FLZ.js";
11
11
 
12
12
  // src/config/define.ts
13
13
  function defineCollections(options) {
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { PageData, MetaData, Source, VirtualFile } from 'fumadocs-core/source';
2
2
  import { B as BaseCollectionEntry } from './define-uoePrCQ_.cjs';
3
- import { R as Runtime } from './types-Cph8Ml_K.cjs';
3
+ import { R as Runtime } from './types-BsJd_P5O.cjs';
4
4
  import '@mdx-js/mdx';
5
5
  import 'mdx/types';
6
6
  import 'fumadocs-core/mdx-plugins';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { PageData, MetaData, Source, VirtualFile } from 'fumadocs-core/source';
2
2
  import { B as BaseCollectionEntry } from './define-uoePrCQ_.js';
3
- import { R as Runtime } from './types-BvEsyMKj.js';
3
+ import { R as Runtime } from './types-BYJBKH4G.js';
4
4
  import '@mdx-js/mdx';
5
5
  import 'mdx/types';
6
6
  import 'fumadocs-core/mdx-plugins';
@@ -138,7 +138,7 @@ function getDefaultMDXOptions({
138
138
  (v) => [
139
139
  rehypeCodeOptions !== false && [plugins.rehypeCode, rehypeCodeOptions],
140
140
  ...v,
141
- [plugins.rehypeToc]
141
+ plugins.rehypeToc
142
142
  ],
143
143
  mdxOptions.rehypePlugins
144
144
  );
@@ -332,7 +332,7 @@ function remarkInclude() {
332
332
 
333
333
  // src/utils/build-mdx.ts
334
334
  var cache2 = /* @__PURE__ */ new Map();
335
- async function buildMDX(cacheKey, source, options = {}) {
335
+ async function buildMDX(cacheKey, source, options) {
336
336
  const { filePath, frontmatter, data, ...rest } = options;
337
337
  let format = options.format;
338
338
  if (!format && filePath) {
@@ -364,30 +364,25 @@ async function buildMDX(cacheKey, source, options = {}) {
364
364
 
365
365
  // src/utils/git-timestamp.ts
366
366
  var import_node_path = __toESM(require("path"), 1);
367
- var import_node_fs = __toESM(require("fs"), 1);
368
- var import_cross_spawn = require("cross-spawn");
367
+ var import_tinyexec = require("tinyexec");
369
368
  var cache3 = /* @__PURE__ */ new Map();
370
- function getGitTimestamp(file) {
371
- const cachedTimestamp = cache3.get(file);
372
- if (cachedTimestamp) return Promise.resolve(cachedTimestamp);
373
- return new Promise((resolve3, reject) => {
374
- const cwd = import_node_path.default.dirname(file);
375
- if (!import_node_fs.default.existsSync(cwd)) {
376
- resolve3(void 0);
377
- return;
378
- }
379
- const fileName = import_node_path.default.basename(file);
380
- const child = (0, import_cross_spawn.spawn)("git", ["log", "-1", '--pretty="%ai"', fileName], {
381
- cwd
382
- });
383
- let output;
384
- child.stdout.on("data", (d) => output = new Date(String(d)));
385
- child.on("close", () => {
386
- if (output) cache3.set(file, output);
387
- resolve3(output);
388
- });
389
- child.on("error", reject);
390
- });
369
+ async function getGitTimestamp(file) {
370
+ const cached = cache3.get(file);
371
+ if (cached) return cached;
372
+ try {
373
+ const out = await (0, import_tinyexec.x)(
374
+ "git",
375
+ ["log", "-1", '--pretty="%ai"', import_node_path.default.relative(process.cwd(), file)],
376
+ {
377
+ throwOnError: true
378
+ }
379
+ );
380
+ const time = new Date(out.stdout);
381
+ cache3.set(file, time);
382
+ return time;
383
+ } catch {
384
+ return;
385
+ }
391
386
  }
392
387
 
393
388
  // src/utils/schema.ts
@@ -414,22 +409,20 @@ var ValidationError = class extends Error {
414
409
  super(message);
415
410
  this.issues = issues;
416
411
  }
417
- print() {
418
- console.error(
419
- [
420
- `[MDX] ${this.message}:`,
421
- ...this.issues.map(
422
- (issue) => import_picocolors.default.redBright(
423
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
424
- )
425
- )
426
- ].join("\n")
427
- );
428
- }
429
412
  toString() {
430
413
  return `${this.message}:
431
414
  ${this.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`;
432
415
  }
416
+ toStringFormatted() {
417
+ return [
418
+ import_picocolors.default.bold(`[MDX] ${this.message}:`),
419
+ ...this.issues.map(
420
+ (issue) => import_picocolors.default.redBright(
421
+ `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
422
+ )
423
+ )
424
+ ].join("\n");
425
+ }
433
426
  };
434
427
  async function validate(schema, data, context, errorMessage) {
435
428
  if (typeof schema === "function" && !("~standard" in schema)) {
@@ -448,56 +441,48 @@ async function validate(schema, data, context, errorMessage) {
448
441
  }
449
442
 
450
443
  // src/loader-mdx.ts
451
- function parseQuery(query) {
452
- let collection;
453
- let hash;
454
- const parsed = (0, import_node_querystring.parse)(query.slice(1));
455
- if (parsed.collection && typeof parsed.collection === "string")
456
- collection = parsed.collection;
457
- if (parsed.hash && typeof parsed.hash === "string") hash = parsed.hash;
458
- return { collection, hash };
459
- }
460
444
  async function loader(source, callback) {
461
445
  this.cacheable(true);
462
446
  const context = this.context;
463
447
  const filePath = this.resourcePath;
464
- const { _ctx } = this.getOptions();
448
+ const { configPath } = this.getOptions();
465
449
  const matter2 = (0, import_gray_matter2.default)(source);
466
450
  const {
467
- hash: configHash = await getConfigHash(_ctx.configPath),
451
+ hash: configHash = await getConfigHash(configPath),
468
452
  collection: collectionId
469
- } = parseQuery(this.resourceQuery);
470
- const config = await loadConfig(_ctx.configPath, configHash);
453
+ } = (0, import_node_querystring.parse)(this.resourceQuery.slice(1));
454
+ const config = await loadConfig(configPath, configHash);
471
455
  let collection = collectionId !== void 0 ? config.collections.get(collectionId) : void 0;
472
456
  if (collection && collection.type === "docs") collection = collection.docs;
473
457
  if (collection && collection.type !== "doc") {
474
458
  collection = void 0;
475
459
  }
476
- let mdxOptions = collection?.mdxOptions;
477
- if (!mdxOptions) {
478
- const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
479
- config._mdx_loader ??= {};
480
- const extendedOptions = config.global?.mdxOptions;
481
- config._mdx_loader.cachedProcessorOptions ??= typeof extendedOptions === "function" ? getDefaultMDXOptions2(await extendedOptions()) : getDefaultMDXOptions2(extendedOptions ?? {});
482
- mdxOptions = config._mdx_loader.cachedProcessorOptions;
483
- }
460
+ const mdxOptions = collection?.mdxOptions ?? await loadDefaultOptions(config);
484
461
  if (collection?.schema) {
485
- matter2.data = await validate(
486
- collection.schema,
487
- matter2.data,
488
- {
489
- source,
490
- path: filePath
491
- },
492
- `invalid frontmatter in ${filePath}`
493
- );
462
+ try {
463
+ matter2.data = await validate(
464
+ collection.schema,
465
+ matter2.data,
466
+ {
467
+ source,
468
+ path: filePath
469
+ },
470
+ `invalid frontmatter in ${filePath}`
471
+ );
472
+ } catch (e) {
473
+ if (e instanceof ValidationError) {
474
+ return callback(new Error(e.toStringFormatted()));
475
+ }
476
+ return callback(e);
477
+ }
494
478
  }
495
479
  let timestamp;
496
- if (config.global?.lastModifiedTime === "git")
480
+ if (config.global?.lastModifiedTime === "git") {
497
481
  timestamp = (await getGitTimestamp(filePath))?.getTime();
482
+ }
498
483
  try {
499
484
  const lineOffset = "\n".repeat(
500
- this.mode === "development" ? lines(source) - lines(matter2.content) : 0
485
+ this.mode === "development" ? lines(matter2.matter) : 0
501
486
  );
502
487
  const file = await buildMDX(
503
488
  `${configHash}:${collectionId ?? "global"}`,
@@ -521,6 +506,16 @@ async function loader(source, callback) {
521
506
  callback(error);
522
507
  }
523
508
  }
509
+ async function loadDefaultOptions(config) {
510
+ const input = config.global?.mdxOptions;
511
+ config._mdx_loader ??= {};
512
+ const mdxLoader = config._mdx_loader;
513
+ if (!mdxLoader.cachedOptions) {
514
+ const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_mdx_options(), mdx_options_exports));
515
+ mdxLoader.cachedOptions = typeof input === "function" ? getDefaultMDXOptions2(await input()) : getDefaultMDXOptions2(input ?? {});
516
+ }
517
+ return mdxLoader.cachedOptions;
518
+ }
524
519
  function lines(s) {
525
520
  let num = 0;
526
521
  for (const c of s) {
@@ -1,12 +1,7 @@
1
1
  import { LoaderContext } from 'webpack';
2
2
 
3
3
  interface Options {
4
- /**
5
- * @internal
6
- */
7
- _ctx: {
8
- configPath: string;
9
- };
4
+ configPath: string;
10
5
  }
11
6
  /**
12
7
  * Load MDX/markdown files
@@ -1,12 +1,7 @@
1
1
  import { LoaderContext } from 'webpack';
2
2
 
3
3
  interface Options {
4
- /**
5
- * @internal
6
- */
7
- _ctx: {
8
- configPath: string;
9
- };
4
+ configPath: string;
10
5
  }
11
6
  /**
12
7
  * Load MDX/markdown files
@@ -1,24 +1,26 @@
1
1
  import {
2
2
  getConfigHash,
3
+ getGitTimestamp,
3
4
  loadConfig
4
- } from "./chunk-LC4HO353.js";
5
+ } from "./chunk-GWITJLOZ.js";
5
6
  import {
7
+ ValidationError,
6
8
  validate
7
- } from "./chunk-2ZOW45YZ.js";
9
+ } from "./chunk-OTM6WYMS.js";
8
10
  import {
9
11
  remarkInclude
10
12
  } from "./chunk-3UUEUK4M.js";
11
13
  import "./chunk-DRVUBK5B.js";
12
14
 
13
15
  // src/loader-mdx.ts
14
- import * as path2 from "path";
16
+ import * as path from "path";
15
17
  import { parse } from "querystring";
16
18
  import grayMatter from "gray-matter";
17
19
 
18
20
  // src/utils/build-mdx.ts
19
21
  import { createProcessor } from "@mdx-js/mdx";
20
22
  var cache = /* @__PURE__ */ new Map();
21
- async function buildMDX(cacheKey, source, options = {}) {
23
+ async function buildMDX(cacheKey, source, options) {
22
24
  const { filePath, frontmatter, data, ...rest } = options;
23
25
  let format = options.format;
24
26
  if (!format && filePath) {
@@ -48,85 +50,49 @@ async function buildMDX(cacheKey, source, options = {}) {
48
50
  });
49
51
  }
50
52
 
51
- // src/utils/git-timestamp.ts
52
- import path from "path";
53
- import fs from "fs";
54
- import { spawn } from "cross-spawn";
55
- var cache2 = /* @__PURE__ */ new Map();
56
- function getGitTimestamp(file) {
57
- const cachedTimestamp = cache2.get(file);
58
- if (cachedTimestamp) return Promise.resolve(cachedTimestamp);
59
- return new Promise((resolve, reject) => {
60
- const cwd = path.dirname(file);
61
- if (!fs.existsSync(cwd)) {
62
- resolve(void 0);
63
- return;
64
- }
65
- const fileName = path.basename(file);
66
- const child = spawn("git", ["log", "-1", '--pretty="%ai"', fileName], {
67
- cwd
68
- });
69
- let output;
70
- child.stdout.on("data", (d) => output = new Date(String(d)));
71
- child.on("close", () => {
72
- if (output) cache2.set(file, output);
73
- resolve(output);
74
- });
75
- child.on("error", reject);
76
- });
77
- }
78
-
79
53
  // src/loader-mdx.ts
80
- function parseQuery(query) {
81
- let collection;
82
- let hash;
83
- const parsed = parse(query.slice(1));
84
- if (parsed.collection && typeof parsed.collection === "string")
85
- collection = parsed.collection;
86
- if (parsed.hash && typeof parsed.hash === "string") hash = parsed.hash;
87
- return { collection, hash };
88
- }
89
54
  async function loader(source, callback) {
90
55
  this.cacheable(true);
91
56
  const context = this.context;
92
57
  const filePath = this.resourcePath;
93
- const { _ctx } = this.getOptions();
58
+ const { configPath } = this.getOptions();
94
59
  const matter = grayMatter(source);
95
60
  const {
96
- hash: configHash = await getConfigHash(_ctx.configPath),
61
+ hash: configHash = await getConfigHash(configPath),
97
62
  collection: collectionId
98
- } = parseQuery(this.resourceQuery);
99
- const config = await loadConfig(_ctx.configPath, configHash);
63
+ } = parse(this.resourceQuery.slice(1));
64
+ const config = await loadConfig(configPath, configHash);
100
65
  let collection = collectionId !== void 0 ? config.collections.get(collectionId) : void 0;
101
66
  if (collection && collection.type === "docs") collection = collection.docs;
102
67
  if (collection && collection.type !== "doc") {
103
68
  collection = void 0;
104
69
  }
105
- let mdxOptions = collection?.mdxOptions;
106
- if (!mdxOptions) {
107
- const { getDefaultMDXOptions } = await import("./mdx-options-7J2A6BUA.js");
108
- config._mdx_loader ??= {};
109
- const extendedOptions = config.global?.mdxOptions;
110
- config._mdx_loader.cachedProcessorOptions ??= typeof extendedOptions === "function" ? getDefaultMDXOptions(await extendedOptions()) : getDefaultMDXOptions(extendedOptions ?? {});
111
- mdxOptions = config._mdx_loader.cachedProcessorOptions;
112
- }
70
+ const mdxOptions = collection?.mdxOptions ?? await loadDefaultOptions(config);
113
71
  if (collection?.schema) {
114
- matter.data = await validate(
115
- collection.schema,
116
- matter.data,
117
- {
118
- source,
119
- path: filePath
120
- },
121
- `invalid frontmatter in ${filePath}`
122
- );
72
+ try {
73
+ matter.data = await validate(
74
+ collection.schema,
75
+ matter.data,
76
+ {
77
+ source,
78
+ path: filePath
79
+ },
80
+ `invalid frontmatter in ${filePath}`
81
+ );
82
+ } catch (e) {
83
+ if (e instanceof ValidationError) {
84
+ return callback(new Error(e.toStringFormatted()));
85
+ }
86
+ return callback(e);
87
+ }
123
88
  }
124
89
  let timestamp;
125
- if (config.global?.lastModifiedTime === "git")
90
+ if (config.global?.lastModifiedTime === "git") {
126
91
  timestamp = (await getGitTimestamp(filePath))?.getTime();
92
+ }
127
93
  try {
128
94
  const lineOffset = "\n".repeat(
129
- this.mode === "development" ? lines(source) - lines(matter.content) : 0
95
+ this.mode === "development" ? lines(matter.matter) : 0
130
96
  );
131
97
  const file = await buildMDX(
132
98
  `${configHash}:${collectionId ?? "global"}`,
@@ -145,11 +111,21 @@ async function loader(source, callback) {
145
111
  callback(void 0, String(file.value), file.map ?? void 0);
146
112
  } catch (error) {
147
113
  if (!(error instanceof Error)) throw error;
148
- const fpath = path2.relative(context, filePath);
114
+ const fpath = path.relative(context, filePath);
149
115
  error.message = `${fpath}:${error.name}: ${error.message}`;
150
116
  callback(error);
151
117
  }
152
118
  }
119
+ async function loadDefaultOptions(config) {
120
+ const input = config.global?.mdxOptions;
121
+ config._mdx_loader ??= {};
122
+ const mdxLoader = config._mdx_loader;
123
+ if (!mdxLoader.cachedOptions) {
124
+ const { getDefaultMDXOptions } = await import("./mdx-options-YGL3EP3M.js");
125
+ mdxLoader.cachedOptions = typeof input === "function" ? getDefaultMDXOptions(await input()) : getDefaultMDXOptions(input ?? {});
126
+ }
127
+ return mdxLoader.cachedOptions;
128
+ }
153
129
  function lines(s) {
154
130
  let num = 0;
155
131
  for (const c of s) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDefaultMDXOptions
3
- } from "./chunk-7UCWBLFI.js";
3
+ } from "./chunk-VC3Y6FLZ.js";
4
4
  export {
5
5
  getDefaultMDXOptions
6
6
  };
@@ -36,24 +36,21 @@ __export(watcher_exports, {
36
36
  watcher: () => watcher
37
37
  });
38
38
  function watcher(configPath, config, ignored) {
39
- const deps = [configPath];
40
- function add(dir) {
41
- if (Array.isArray(dir)) deps.push(...dir);
42
- else deps.push(dir);
43
- }
39
+ const watcher2 = new import_chokidar.FSWatcher({
40
+ ignoreInitial: true,
41
+ persistent: true,
42
+ ignored
43
+ });
44
+ watcher2.add(configPath);
44
45
  for (const collection of config.collections.values()) {
45
46
  if (collection.type === "docs") {
46
- add(collection.docs.dir);
47
- add(collection.meta.dir);
47
+ watcher2.add(collection.docs.dir);
48
+ watcher2.add(collection.meta.dir);
48
49
  } else {
49
- add(collection.dir);
50
+ watcher2.add(collection.dir);
50
51
  }
51
52
  }
52
- return (0, import_chokidar.watch)(deps, {
53
- ignoreInitial: true,
54
- ignored,
55
- persistent: true
56
- });
53
+ return watcher2;
57
54
  }
58
55
  var import_chokidar;
59
56
  var init_watcher = __esm({
@@ -73,7 +70,7 @@ __export(next_exports, {
73
70
  module.exports = __toCommonJS(next_exports);
74
71
 
75
72
  // src/next/create.ts
76
- var import_node_path2 = __toESM(require("path"), 1);
73
+ var import_node_path3 = __toESM(require("path"), 1);
77
74
 
78
75
  // src/utils/config.ts
79
76
  var fs = __toESM(require("fs/promises"), 1);
@@ -167,20 +164,20 @@ async function getConfigHash(configPath) {
167
164
  }
168
165
 
169
166
  // src/map/index.ts
170
- var path3 = __toESM(require("path"), 1);
167
+ var path4 = __toESM(require("path"), 1);
171
168
  var fs3 = __toESM(require("fs/promises"), 1);
172
169
 
173
170
  // src/map/generate.ts
174
- var path2 = __toESM(require("path"), 1);
171
+ var path3 = __toESM(require("path"), 1);
175
172
  var fs2 = __toESM(require("fs/promises"), 1);
176
- var import_fast_glob = __toESM(require("fast-glob"), 1);
173
+ var import_tinyglobby = require("tinyglobby");
177
174
 
178
175
  // src/utils/get-type-from-path.ts
179
176
  var import_node_path = require("path");
180
177
  var docTypes = [".mdx", ".md"];
181
178
  var metaTypes = [".json", ".yaml"];
182
- function getTypeFromPath(path6) {
183
- const ext = (0, import_node_path.extname)(path6);
179
+ function getTypeFromPath(path7) {
180
+ const ext = (0, import_node_path.extname)(path7);
184
181
  if (docTypes.includes(ext)) return "doc";
185
182
  if (metaTypes.includes(ext)) return "meta";
186
183
  }
@@ -209,22 +206,20 @@ var ValidationError = class extends Error {
209
206
  super(message);
210
207
  this.issues = issues;
211
208
  }
212
- print() {
213
- console.error(
214
- [
215
- `[MDX] ${this.message}:`,
216
- ...this.issues.map(
217
- (issue) => import_picocolors.default.redBright(
218
- `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
219
- )
220
- )
221
- ].join("\n")
222
- );
223
- }
224
209
  toString() {
225
210
  return `${this.message}:
226
211
  ${this.issues.map((issue) => ` ${issue.path}: ${issue.message}`).join("\n")}`;
227
212
  }
213
+ toStringFormatted() {
214
+ return [
215
+ import_picocolors.default.bold(`[MDX] ${this.message}:`),
216
+ ...this.issues.map(
217
+ (issue) => import_picocolors.default.redBright(
218
+ `- ${import_picocolors.default.bold(issue.path?.join(".") ?? "*")}: ${issue.message}`
219
+ )
220
+ )
221
+ ].join("\n");
222
+ }
228
223
  };
229
224
  async function validate(schema, data, context, errorMessage) {
230
225
  if (typeof schema === "function" && !("~standard" in schema)) {
@@ -248,16 +243,16 @@ var map = new import_lru_cache.LRUCache({
248
243
  max: 200
249
244
  });
250
245
  var fileCache = {
251
- read(namespace, path6) {
252
- return map.get(`${namespace}.${path6}`);
246
+ read(namespace, path7) {
247
+ return map.get(`${namespace}.${path7}`);
253
248
  },
254
- write(namespace, path6, data) {
255
- map.set(`${namespace}.${path6}`, data);
249
+ write(namespace, path7, data) {
250
+ map.set(`${namespace}.${path7}`, data);
256
251
  },
257
- removeCache(path6) {
252
+ removeCache(path7) {
258
253
  for (const key of map.keys()) {
259
254
  const keyPath = key.slice(key.indexOf(".") + 1);
260
- if (keyPath === path6) map.delete(key);
255
+ if (keyPath === path7) map.delete(key);
261
256
  }
262
257
  }
263
258
  };
@@ -265,13 +260,38 @@ var fileCache = {
265
260
  // src/map/generate.ts
266
261
  var import_gray_matter = __toESM(require("gray-matter"), 1);
267
262
  var import_js_yaml = require("js-yaml");
263
+
264
+ // src/utils/git-timestamp.ts
265
+ var import_node_path2 = __toESM(require("path"), 1);
266
+ var import_tinyexec = require("tinyexec");
267
+ var cache2 = /* @__PURE__ */ new Map();
268
+ async function getGitTimestamp(file) {
269
+ const cached = cache2.get(file);
270
+ if (cached) return cached;
271
+ try {
272
+ const out = await (0, import_tinyexec.x)(
273
+ "git",
274
+ ["log", "-1", '--pretty="%ai"', import_node_path2.default.relative(process.cwd(), file)],
275
+ {
276
+ throwOnError: true
277
+ }
278
+ );
279
+ const time = new Date(out.stdout);
280
+ cache2.set(file, time);
281
+ return time;
282
+ } catch {
283
+ return;
284
+ }
285
+ }
286
+
287
+ // src/map/generate.ts
268
288
  async function readFileWithCache(file) {
269
289
  const cached = fileCache.read("read-file", file);
270
290
  if (cached) return cached;
271
291
  return (await fs2.readFile(file)).toString();
272
292
  }
273
293
  async function generateJS(configPath, config, outputPath, configHash) {
274
- const outDir2 = path2.dirname(outputPath);
294
+ const outDir2 = path3.dirname(outputPath);
275
295
  let asyncInit = false;
276
296
  const lines = [
277
297
  getImportCode({
@@ -347,8 +367,13 @@ async function generateJS(configPath, config, outputPath, configHash) {
347
367
  `invalid frontmatter in ${file.absolutePath}`
348
368
  );
349
369
  }
370
+ let lastModified;
371
+ if (config.global?.lastModifiedTime === "git") {
372
+ lastModified = await getGitTimestamp(file.absolutePath);
373
+ }
350
374
  return JSON.stringify({
351
375
  info: file,
376
+ lastModified,
352
377
  data: parsed.data,
353
378
  content: parsed.content
354
379
  });
@@ -389,14 +414,14 @@ async function getCollectionFiles(collection) {
389
414
  const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
390
415
  await Promise.all(
391
416
  dirs.map(async (dir) => {
392
- const result = await (0, import_fast_glob.default)(collection.files ?? "**/*", {
393
- cwd: path2.resolve(dir),
417
+ const result = await (0, import_tinyglobby.glob)(collection.files ?? "**/*", {
418
+ cwd: path3.resolve(dir),
394
419
  absolute: true
395
420
  });
396
421
  for (const item of result) {
397
422
  if (getTypeFromPath(item) !== collection.type) continue;
398
423
  files.set(item, {
399
- path: path2.relative(dir, item),
424
+ path: path3.relative(dir, item),
400
425
  absolutePath: item
401
426
  });
402
427
  }
@@ -418,18 +443,18 @@ function getImportCode(info) {
418
443
  return `import ${specifier}`;
419
444
  }
420
445
  function toImportPath(file, dir) {
421
- const ext = path2.extname(file);
422
- let importPath = path2.relative(
446
+ const ext = path3.extname(file);
447
+ let importPath = path3.relative(
423
448
  dir,
424
449
  ext === ".ts" ? file.substring(0, file.length - ext.length) : file
425
450
  );
426
- if (!path2.isAbsolute(importPath) && !importPath.startsWith(".")) {
451
+ if (!path3.isAbsolute(importPath) && !importPath.startsWith(".")) {
427
452
  importPath = `./${importPath}`;
428
453
  }
429
- return importPath.replaceAll(path2.sep, "/");
454
+ return importPath.replaceAll(path3.sep, "/");
430
455
  }
431
456
  function parseMetaEntry(file, content) {
432
- const extname3 = path2.extname(file);
457
+ const extname3 = path3.extname(file);
433
458
  try {
434
459
  if (extname3 === ".json") return JSON.parse(content);
435
460
  if (extname3 === ".yaml") return (0, import_js_yaml.load)(content);
@@ -445,7 +470,7 @@ function parseMetaEntry(file, content) {
445
470
  async function start(dev, configPath, outDir2) {
446
471
  let configHash = await getConfigHash(configPath);
447
472
  let config = await loadConfig(configPath, configHash, true);
448
- const outPath = path3.resolve(outDir2, `index.ts`);
473
+ const outPath = path4.resolve(outDir2, `index.ts`);
449
474
  async function updateMapFile() {
450
475
  const start2 = performance.now();
451
476
  try {
@@ -455,7 +480,7 @@ async function start(dev, configPath, outDir2) {
455
480
  );
456
481
  } catch (err) {
457
482
  if (err instanceof ValidationError) {
458
- err.print();
483
+ console.error(err.toStringFormatted());
459
484
  } else {
460
485
  console.error(err);
461
486
  }
@@ -471,7 +496,7 @@ async function start(dev, configPath, outDir2) {
471
496
  });
472
497
  instance.on("all", (event, file) => {
473
498
  if (typeof file !== "string") return;
474
- const absolutePath = path3.resolve(file);
499
+ const absolutePath = path4.resolve(file);
475
500
  const onUpdate = async () => {
476
501
  const isConfigFile = absolutePath === configPath;
477
502
  if (isConfigFile) {
@@ -491,7 +516,7 @@ async function start(dev, configPath, outDir2) {
491
516
  }
492
517
 
493
518
  // src/next/create.ts
494
- var outDir = import_node_path2.default.resolve(".source");
519
+ var outDir = import_node_path3.default.resolve(".source");
495
520
  var defaultPageExtensions = ["mdx", "md", "jsx", "js", "tsx", "ts"];
496
521
  function createMDX({
497
522
  configPath = findConfigFile()
@@ -504,9 +529,7 @@ function createMDX({
504
529
  }
505
530
  return (nextConfig = {}) => {
506
531
  const mdxLoaderOptions = {
507
- _ctx: {
508
- configPath
509
- }
532
+ configPath
510
533
  };
511
534
  return {
512
535
  ...nextConfig,
@@ -549,14 +572,14 @@ function createMDX({
549
572
  }
550
573
 
551
574
  // src/postinstall.ts
552
- var path5 = __toESM(require("path"), 1);
575
+ var path6 = __toESM(require("path"), 1);
553
576
  var fs4 = __toESM(require("fs/promises"), 1);
554
577
  async function postInstall(configPath = findConfigFile()) {
555
- const jsOut = path5.resolve(".source/index.ts");
578
+ const jsOut = path6.resolve(".source/index.ts");
556
579
  const hash = await getConfigHash(configPath);
557
580
  const config = await loadConfig(configPath, hash, true);
558
- await fs4.rm(path5.dirname(jsOut), { recursive: true });
559
- await fs4.mkdir(path5.dirname(jsOut), { recursive: true });
581
+ await fs4.rm(path6.dirname(jsOut), { recursive: true });
582
+ await fs4.mkdir(path6.dirname(jsOut), { recursive: true });
560
583
  await fs4.writeFile(jsOut, await generateJS(configPath, config, jsOut, hash));
561
584
  console.log("[MDX] types generated");
562
585
  }
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  findConfigFile,
3
3
  getConfigHash,
4
+ getGitTimestamp,
4
5
  loadConfig
5
- } from "../chunk-LC4HO353.js";
6
+ } from "../chunk-GWITJLOZ.js";
6
7
  import {
7
8
  ValidationError,
8
9
  validate
9
- } from "../chunk-2ZOW45YZ.js";
10
+ } from "../chunk-OTM6WYMS.js";
10
11
  import "../chunk-DRVUBK5B.js";
11
12
 
12
13
  // src/next/create.ts
@@ -19,7 +20,7 @@ import * as fs2 from "fs/promises";
19
20
  // src/map/generate.ts
20
21
  import * as path from "path";
21
22
  import * as fs from "fs/promises";
22
- import fg from "fast-glob";
23
+ import { glob } from "tinyglobby";
23
24
 
24
25
  // src/utils/get-type-from-path.ts
25
26
  import { extname } from "path";
@@ -136,8 +137,13 @@ async function generateJS(configPath, config, outputPath, configHash) {
136
137
  `invalid frontmatter in ${file.absolutePath}`
137
138
  );
138
139
  }
140
+ let lastModified;
141
+ if (config.global?.lastModifiedTime === "git") {
142
+ lastModified = await getGitTimestamp(file.absolutePath);
143
+ }
139
144
  return JSON.stringify({
140
145
  info: file,
146
+ lastModified,
141
147
  data: parsed.data,
142
148
  content: parsed.content
143
149
  });
@@ -178,7 +184,7 @@ async function getCollectionFiles(collection) {
178
184
  const dirs = Array.isArray(collection.dir) ? collection.dir : [collection.dir];
179
185
  await Promise.all(
180
186
  dirs.map(async (dir) => {
181
- const result = await fg(collection.files ?? "**/*", {
187
+ const result = await glob(collection.files ?? "**/*", {
182
188
  cwd: path.resolve(dir),
183
189
  absolute: true
184
190
  });
@@ -244,7 +250,7 @@ async function start(dev, configPath, outDir2) {
244
250
  );
245
251
  } catch (err) {
246
252
  if (err instanceof ValidationError) {
247
- err.print();
253
+ console.error(err.toStringFormatted());
248
254
  } else {
249
255
  console.error(err);
250
256
  }
@@ -253,7 +259,7 @@ async function start(dev, configPath, outDir2) {
253
259
  }
254
260
  await updateMapFile();
255
261
  if (dev) {
256
- const { watcher } = await import("../watcher-7O2HAQ63.js");
262
+ const { watcher } = await import("../watcher-4NDMOH4R.js");
257
263
  const instance = watcher(configPath, config, [outPath]);
258
264
  instance.on("ready", () => {
259
265
  console.log("[MDX] started dev server");
@@ -293,9 +299,7 @@ function createMDX({
293
299
  }
294
300
  return (nextConfig = {}) => {
295
301
  const mdxLoaderOptions = {
296
- _ctx: {
297
- configPath
298
- }
302
+ configPath
299
303
  };
300
304
  return {
301
305
  ...nextConfig,
@@ -223,10 +223,14 @@ async function initCompiler(config, collection) {
223
223
  mdxOptions = col.docs?.mdxOptions;
224
224
  if (!mdxOptions) {
225
225
  config._mdx_async ??= {};
226
- config._mdx_async.cachedMdxOptions ??= typeof config.global?.mdxOptions === "function" ? await config.global.mdxOptions() : config.global?.mdxOptions ?? {};
227
- mdxOptions = config._mdx_async.cachedMdxOptions;
226
+ const async = config._mdx_async;
227
+ const globalConfig = config.global;
228
+ if (globalConfig && !async.cachedMdxOptions) {
229
+ async.cachedMdxOptions = typeof globalConfig.mdxOptions === "function" ? await globalConfig.mdxOptions() : globalConfig.mdxOptions;
230
+ }
231
+ mdxOptions = async.cachedMdxOptions;
228
232
  }
229
- const remarkPlugins = mdxOptions.remarkPlugins ?? [];
233
+ const remarkPlugins = mdxOptions?.remarkPlugins ?? [];
230
234
  return (0, import_mdx_remote.createCompiler)({
231
235
  ...mdxOptions,
232
236
  remarkPlugins: (v) => typeof remarkPlugins === "function" ? [remarkInclude, ...remarkPlugins(v), import_mdx_plugins.remarkStructure] : [remarkInclude, ...v, ...remarkPlugins, import_mdx_plugins.remarkStructure]
@@ -235,7 +239,7 @@ async function initCompiler(config, collection) {
235
239
  var _runtimeAsync = {
236
240
  doc(files, collection, config) {
237
241
  const init = initCompiler(config, collection);
238
- return files.map(({ info: file, data, content }) => {
242
+ return files.map(({ info: file, data, content, lastModified }) => {
239
243
  return {
240
244
  ...data,
241
245
  _file: file,
@@ -249,6 +253,7 @@ var _runtimeAsync = {
249
253
  return {
250
254
  body: out.body,
251
255
  toc: out.toc,
256
+ lastModified,
252
257
  structuredData: out.vfile.data.structuredData,
253
258
  _exports: out.exports ?? {}
254
259
  };
@@ -1,4 +1,4 @@
1
- import { L as LoadedConfig, a as RuntimeAsync } from '../types-Cph8Ml_K.cjs';
1
+ import { L as LoadedConfig, a as RuntimeAsync } from '../types-BsJd_P5O.cjs';
2
2
  import '../define-uoePrCQ_.cjs';
3
3
  import '@mdx-js/mdx';
4
4
  import 'mdx/types';
@@ -1,4 +1,4 @@
1
- import { L as LoadedConfig, a as RuntimeAsync } from '../types-BvEsyMKj.js';
1
+ import { L as LoadedConfig, a as RuntimeAsync } from '../types-BYJBKH4G.js';
2
2
  import '../define-uoePrCQ_.js';
3
3
  import '@mdx-js/mdx';
4
4
  import 'mdx/types';
@@ -22,10 +22,14 @@ async function initCompiler(config, collection) {
22
22
  mdxOptions = col.docs?.mdxOptions;
23
23
  if (!mdxOptions) {
24
24
  config._mdx_async ??= {};
25
- config._mdx_async.cachedMdxOptions ??= typeof config.global?.mdxOptions === "function" ? await config.global.mdxOptions() : config.global?.mdxOptions ?? {};
26
- mdxOptions = config._mdx_async.cachedMdxOptions;
25
+ const async = config._mdx_async;
26
+ const globalConfig = config.global;
27
+ if (globalConfig && !async.cachedMdxOptions) {
28
+ async.cachedMdxOptions = typeof globalConfig.mdxOptions === "function" ? await globalConfig.mdxOptions() : globalConfig.mdxOptions;
29
+ }
30
+ mdxOptions = async.cachedMdxOptions;
27
31
  }
28
- const remarkPlugins = mdxOptions.remarkPlugins ?? [];
32
+ const remarkPlugins = mdxOptions?.remarkPlugins ?? [];
29
33
  return createCompiler({
30
34
  ...mdxOptions,
31
35
  remarkPlugins: (v) => typeof remarkPlugins === "function" ? [remarkInclude, ...remarkPlugins(v), remarkStructure] : [remarkInclude, ...v, ...remarkPlugins, remarkStructure]
@@ -34,7 +38,7 @@ async function initCompiler(config, collection) {
34
38
  var _runtimeAsync = {
35
39
  doc(files, collection, config) {
36
40
  const init = initCompiler(config, collection);
37
- return files.map(({ info: file, data, content }) => {
41
+ return files.map(({ info: file, data, content, lastModified }) => {
38
42
  return {
39
43
  ...data,
40
44
  _file: file,
@@ -48,6 +52,7 @@ var _runtimeAsync = {
48
52
  return {
49
53
  body: out.body,
50
54
  toc: out.toc,
55
+ lastModified,
51
56
  structuredData: out.vfile.data.structuredData,
52
57
  _exports: out.exports ?? {}
53
58
  };
@@ -8,7 +8,7 @@ interface LoadedConfig {
8
8
  collections: Map<string, DocCollection | MetaCollection | DocsCollection>;
9
9
  global?: GlobalConfig;
10
10
  _mdx_loader?: {
11
- cachedProcessorOptions?: ProcessorOptions;
11
+ cachedOptions?: ProcessorOptions;
12
12
  };
13
13
  _mdx_async?: {
14
14
  cachedMdxOptions?: MDXOptions;
@@ -23,6 +23,7 @@ interface AsyncRuntimeFile {
23
23
  info: FileInfo;
24
24
  data: Record<string, unknown>;
25
25
  content: string;
26
+ lastModified?: Date;
26
27
  }
27
28
  type DocOut<Schema extends StandardSchemaV1> = Override<MarkdownProps & {
28
29
  /**
@@ -8,7 +8,7 @@ interface LoadedConfig {
8
8
  collections: Map<string, DocCollection | MetaCollection | DocsCollection>;
9
9
  global?: GlobalConfig;
10
10
  _mdx_loader?: {
11
- cachedProcessorOptions?: ProcessorOptions;
11
+ cachedOptions?: ProcessorOptions;
12
12
  };
13
13
  _mdx_async?: {
14
14
  cachedMdxOptions?: MDXOptions;
@@ -23,6 +23,7 @@ interface AsyncRuntimeFile {
23
23
  info: FileInfo;
24
24
  data: Record<string, unknown>;
25
25
  content: string;
26
+ lastModified?: Date;
26
27
  }
27
28
  type DocOut<Schema extends StandardSchemaV1> = Override<MarkdownProps & {
28
29
  /**
@@ -0,0 +1,22 @@
1
+ // src/map/watcher.ts
2
+ import { FSWatcher } from "chokidar";
3
+ function watcher(configPath, config, ignored) {
4
+ const watcher2 = new FSWatcher({
5
+ ignoreInitial: true,
6
+ persistent: true,
7
+ ignored
8
+ });
9
+ watcher2.add(configPath);
10
+ for (const collection of config.collections.values()) {
11
+ if (collection.type === "docs") {
12
+ watcher2.add(collection.docs.dir);
13
+ watcher2.add(collection.meta.dir);
14
+ } else {
15
+ watcher2.add(collection.dir);
16
+ }
17
+ }
18
+ return watcher2;
19
+ }
20
+ export {
21
+ watcher
22
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-mdx",
3
- "version": "11.6.4",
3
+ "version": "11.6.6",
4
4
  "description": "The built-in source for Fumadocs",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -45,32 +45,31 @@
45
45
  "@mdx-js/mdx": "^3.1.0",
46
46
  "@standard-schema/spec": "^1.0.0",
47
47
  "chokidar": "^4.0.3",
48
- "cross-spawn": "^7.0.6",
49
48
  "esbuild": "^0.25.4",
50
49
  "estree-util-value-to-estree": "^3.4.0",
51
- "fast-glob": "^3.3.3",
52
50
  "gray-matter": "^4.0.3",
53
51
  "js-yaml": "^4.1.0",
54
52
  "lru-cache": "^11.1.0",
55
53
  "picocolors": "^1.1.1",
54
+ "tinyexec": "^1.0.1",
55
+ "tinyglobby": "^0.2.13",
56
56
  "unist-util-visit": "^5.0.0",
57
- "zod": "^3.24.4"
57
+ "zod": "^3.25.28"
58
58
  },
59
59
  "devDependencies": {
60
- "@types/cross-spawn": "^6.0.6",
61
60
  "@types/js-yaml": "^4.0.9",
62
61
  "@types/mdast": "^4.0.3",
63
62
  "@types/mdx": "^2.0.13",
64
- "@types/react": "^19.1.4",
63
+ "@types/react": "^19.1.5",
65
64
  "mdast-util-mdx-jsx": "^3.2.0",
66
65
  "next": "^15.3.2",
67
66
  "unified": "^11.0.5",
68
67
  "vfile": "^6.0.3",
69
- "webpack": "^5.99.8",
70
- "@fumadocs/mdx-remote": "1.3.1",
68
+ "webpack": "^5.99.9",
69
+ "@fumadocs/mdx-remote": "1.3.2",
71
70
  "eslint-config-custom": "0.0.0",
72
- "tsconfig": "0.0.0",
73
- "fumadocs-core": "15.3.3"
71
+ "fumadocs-core": "15.4.0",
72
+ "tsconfig": "0.0.0"
74
73
  },
75
74
  "peerDependencies": {
76
75
  "@fumadocs/mdx-remote": "^1.2.0",
@@ -1,25 +0,0 @@
1
- // src/map/watcher.ts
2
- import { watch } from "chokidar";
3
- function watcher(configPath, config, ignored) {
4
- const deps = [configPath];
5
- function add(dir) {
6
- if (Array.isArray(dir)) deps.push(...dir);
7
- else deps.push(dir);
8
- }
9
- for (const collection of config.collections.values()) {
10
- if (collection.type === "docs") {
11
- add(collection.docs.dir);
12
- add(collection.meta.dir);
13
- } else {
14
- add(collection.dir);
15
- }
16
- }
17
- return watch(deps, {
18
- ignoreInitial: true,
19
- ignored,
20
- persistent: true
21
- });
22
- }
23
- export {
24
- watcher
25
- };