fumadocs-mdx 12.0.0 → 12.0.1

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.
Files changed (40) hide show
  1. package/dist/bin.cjs +102 -84
  2. package/dist/bin.js +1 -1
  3. package/dist/bun/index.cjs +156 -130
  4. package/dist/bun/index.js +8 -8
  5. package/dist/chunk-ADR6R7HM.js +29 -0
  6. package/dist/{chunk-3M4SHY6K.js → chunk-FSZMKRVH.js} +1 -1
  7. package/dist/{chunk-POXTQZ4D.js → chunk-LGYVNESJ.js} +2 -6
  8. package/dist/chunk-LMG6UWCL.js +167 -0
  9. package/dist/{chunk-SWNOXPYJ.js → chunk-QAUWMR5D.js} +6 -6
  10. package/dist/{chunk-KGUBBRL6.js → chunk-SP7CHRTS.js} +9 -37
  11. package/dist/{chunk-YC25YEBF.js → chunk-U4MQ44TS.js} +1 -1
  12. package/dist/chunk-XMFLD5J6.js +30 -0
  13. package/dist/{chunk-TLD6JMT6.js → chunk-ZX7TM4AR.js} +4 -2
  14. package/dist/config/index.cjs +84 -56
  15. package/dist/config/index.js +2 -2
  16. package/dist/load-UUXLUBHL.js +9 -0
  17. package/dist/loader-mdx.cjs +217 -174
  18. package/dist/loader-mdx.js +7 -7
  19. package/dist/next/index.cjs +128 -108
  20. package/dist/next/index.js +39 -53
  21. package/dist/node/loader.cjs +152 -109
  22. package/dist/node/loader.js +6 -7
  23. package/dist/postinstall-SCSXM4IM.js +10 -0
  24. package/dist/{preset-WFEORCAB.js → preset-ZMP6U62C.js} +1 -1
  25. package/dist/runtime/next/async.cjs +117 -65
  26. package/dist/runtime/next/async.d.cts +1 -1
  27. package/dist/runtime/next/async.d.ts +1 -1
  28. package/dist/runtime/next/async.js +15 -8
  29. package/dist/runtime/next/index.d.cts +2 -2
  30. package/dist/runtime/next/index.d.ts +2 -2
  31. package/dist/{types-DLIAvrgC.d.ts → types-CFlQxTN8.d.ts} +4 -5
  32. package/dist/{types-Dl8HLbm5.d.cts → types-DkGjw-Uo.d.cts} +4 -5
  33. package/dist/vite/index.cjs +177 -145
  34. package/dist/vite/index.d.cts +1 -0
  35. package/dist/vite/index.d.ts +1 -0
  36. package/dist/vite/index.js +14 -19
  37. package/dist/{watcher-4NDMOH4R.js → watcher-HGOH3APP.js} +1 -1
  38. package/package.json +15 -11
  39. package/dist/chunk-KTDVTBMH.js +0 -139
  40. package/dist/postinstall-U7VROOY7.js +0 -9
@@ -30,7 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // src/mdx/preset.ts
33
+ // src/loaders/mdx/preset.ts
34
34
  var preset_exports = {};
35
35
  __export(preset_exports, {
36
36
  getDefaultMDXOptions: () => getDefaultMDXOptions
@@ -111,12 +111,67 @@ function getDefaultMDXOptions({
111
111
  }
112
112
  var plugins;
113
113
  var init_preset = __esm({
114
- "src/mdx/preset.ts"() {
114
+ "src/loaders/mdx/preset.ts"() {
115
115
  "use strict";
116
116
  plugins = __toESM(require("fumadocs-core/mdx-plugins"), 1);
117
117
  }
118
118
  });
119
119
 
120
+ // src/config/build.ts
121
+ function buildConfig(config) {
122
+ const collections = /* @__PURE__ */ new Map();
123
+ let globalConfig = {};
124
+ for (const [k, v] of Object.entries(config)) {
125
+ if (!v) {
126
+ continue;
127
+ }
128
+ if (typeof v === "object" && "type" in v) {
129
+ if (v.type === "docs") {
130
+ collections.set(k, v);
131
+ continue;
132
+ }
133
+ if (v.type === "doc" || v.type === "meta") {
134
+ collections.set(k, v);
135
+ continue;
136
+ }
137
+ }
138
+ if (k === "default" && v) {
139
+ globalConfig = v;
140
+ continue;
141
+ }
142
+ throw new Error(
143
+ `Unknown export "${k}", you can only export collections from source configuration file.`
144
+ );
145
+ }
146
+ const mdxOptionsCache = /* @__PURE__ */ new Map();
147
+ return {
148
+ global: globalConfig,
149
+ collections,
150
+ async getDefaultMDXOptions(mode = "default") {
151
+ const cached = mdxOptionsCache.get(mode);
152
+ if (cached) return cached;
153
+ const input = this.global.mdxOptions;
154
+ async function uncached() {
155
+ const options = typeof input === "function" ? await input() : input;
156
+ const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_preset(), preset_exports));
157
+ if (options?.preset === "minimal") return options;
158
+ return getDefaultMDXOptions2({
159
+ ...options,
160
+ _withoutBundler: mode === "remote"
161
+ });
162
+ }
163
+ const result = uncached();
164
+ mdxOptionsCache.set(mode, result);
165
+ return result;
166
+ }
167
+ };
168
+ }
169
+ var init_build = __esm({
170
+ "src/config/build.ts"() {
171
+ "use strict";
172
+ }
173
+ });
174
+
120
175
  // src/bun/index.ts
121
176
  var bun_exports = {};
122
177
  __export(bun_exports, {
@@ -201,19 +256,10 @@ async function getGitTimestamp(file) {
201
256
  }
202
257
  }
203
258
 
204
- // src/utils/count-lines.ts
205
- function countLines(s) {
206
- let num = 0;
207
- for (const c of s) {
208
- if (c === "\n") num++;
209
- }
210
- return num;
211
- }
212
-
213
- // src/mdx/build-mdx.ts
259
+ // src/loaders/mdx/build-mdx.ts
214
260
  var import_mdx = require("@mdx-js/mdx");
215
261
 
216
- // src/mdx/remark-include.ts
262
+ // src/loaders/mdx/remark-include.ts
217
263
  var import_unified = require("unified");
218
264
  var import_unist_util_visit = require("unist-util-visit");
219
265
  var path2 = __toESM(require("path"), 1);
@@ -221,7 +267,28 @@ var fs = __toESM(require("fs/promises"), 1);
221
267
  var import_remark_parse = __toESM(require("remark-parse"), 1);
222
268
  var import_remark_mdx = __toESM(require("remark-mdx"), 1);
223
269
  var import_mdx_plugins = require("fumadocs-core/mdx-plugins");
224
- var baseProcessor = (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading);
270
+ var ElementLikeTypes = [
271
+ "mdxJsxFlowElement",
272
+ "mdxJsxTextElement",
273
+ "containerDirective",
274
+ "textDirective",
275
+ "leafDirective"
276
+ ];
277
+ function isElementLike(node) {
278
+ return ElementLikeTypes.includes(node.type);
279
+ }
280
+ function parseElementAttributes(element) {
281
+ if (Array.isArray(element.attributes)) {
282
+ const attributes = {};
283
+ for (const attr of element.attributes) {
284
+ if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
285
+ attributes[attr.name] = attr.value;
286
+ }
287
+ }
288
+ return attributes;
289
+ }
290
+ return element.attributes ?? {};
291
+ }
225
292
  function flattenNode(node) {
226
293
  if ("children" in node)
227
294
  return node.children.map((child) => flattenNode(child)).join("");
@@ -238,21 +305,31 @@ function parseSpecifier(specifier) {
238
305
  }
239
306
  function extractSection(root, section) {
240
307
  let nodes;
241
- for (const node of root.children) {
242
- if (node.type === "mdxJsxFlowElement" && node.name === "section" && node.attributes.some(
243
- (attr) => attr.type === "mdxJsxAttribute" && attr.name === "id" && attr.value === section
244
- )) {
245
- nodes = node.children;
246
- break;
308
+ let capturingHeadingContent = false;
309
+ (0, import_unist_util_visit.visit)(root, (node) => {
310
+ if (node.type === "heading") {
311
+ if (capturingHeadingContent) {
312
+ return false;
313
+ }
314
+ if (node.data?.hProperties?.id === section) {
315
+ capturingHeadingContent = true;
316
+ nodes = [node];
317
+ return "skip";
318
+ }
319
+ return;
247
320
  }
248
- if (node.type === "heading" && node.data?.hProperties?.id === section) {
249
- nodes = [node];
250
- continue;
321
+ if (capturingHeadingContent) {
322
+ nodes?.push(node);
323
+ return "skip";
251
324
  }
252
- if (!nodes) continue;
253
- if (node.type === "heading") break;
254
- nodes.push(node);
255
- }
325
+ if (isElementLike(node) && node.name === "section") {
326
+ const attributes = parseElementAttributes(node);
327
+ if (attributes.id === section) {
328
+ nodes = node.children;
329
+ return false;
330
+ }
331
+ }
332
+ });
256
333
  if (nodes)
257
334
  return {
258
335
  type: "root",
@@ -284,55 +361,52 @@ ${e instanceof Error ? e.message : String(e)}`,
284
361
  data: {}
285
362
  };
286
363
  }
287
- const processor = (data._getProcessor ?? getDefaultProcessor)(
364
+ const parser = (data._getProcessor ?? getDefaultProcessor)(
288
365
  ext === ".mdx" ? "mdx" : "md"
289
366
  );
290
- let parsed = await baseProcessor.run(
291
- processor.parse(fumaMatter(content).content)
292
- );
367
+ const parsed = fumaMatter(content);
368
+ let mdast = parser.parse({
369
+ path: file,
370
+ value: parsed.content,
371
+ data: { frontmatter: parsed.data }
372
+ });
293
373
  if (heading) {
294
- const extracted = extractSection(parsed, heading);
374
+ const extracted = extractSection(
375
+ await (0, import_unified.unified)().use(import_mdx_plugins.remarkHeading).run(mdast),
376
+ heading
377
+ );
295
378
  if (!extracted)
296
379
  throw new Error(
297
- `Cannot find section ${heading} in ${file}, make sure you have encapsulated the section in a <section id="${heading}"> tag.`
380
+ `Cannot find section ${heading} in ${file}, make sure you have encapsulated the section in a <section id="${heading}"> tag, or a :::section directive with remark-directive configured.`
298
381
  );
299
- parsed = extracted;
382
+ mdast = extracted;
300
383
  }
301
- await update(parsed, path2.dirname(file), data);
302
- return parsed;
384
+ await update(mdast, path2.dirname(file), data);
385
+ return mdast;
303
386
  }
304
387
  async function update(tree, directory, data) {
305
388
  const queue = [];
306
- (0, import_unist_util_visit.visit)(
307
- tree,
308
- ["mdxJsxFlowElement", "mdxJsxTextElement"],
309
- (_node, _, parent) => {
310
- const node = _node;
311
- if (node.name !== TagName) return;
312
- const params = {};
313
- const specifier = flattenNode(node);
314
- if (specifier.length === 0) return "skip";
315
- for (const attr of node.attributes) {
316
- if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
317
- params[attr.name] = attr.value;
318
- }
319
- }
320
- const { file: relativePath, section } = parseSpecifier(specifier);
321
- const file = path2.resolve(
322
- "cwd" in params ? process.cwd() : directory,
323
- relativePath
324
- );
325
- queue.push(
326
- embedContent(file, section, params, data).then((replace) => {
327
- Object.assign(
328
- parent && parent.type === "paragraph" ? parent : node,
329
- replace
330
- );
331
- })
332
- );
333
- return "skip";
334
- }
335
- );
389
+ (0, import_unist_util_visit.visit)(tree, ElementLikeTypes, (_node, _, parent) => {
390
+ const node = _node;
391
+ if (node.name !== TagName) return;
392
+ const specifier = flattenNode(node);
393
+ if (specifier.length === 0) return "skip";
394
+ const attributes = parseElementAttributes(node);
395
+ const { file: relativePath, section } = parseSpecifier(specifier);
396
+ const file = path2.resolve(
397
+ "cwd" in attributes ? process.cwd() : directory,
398
+ relativePath
399
+ );
400
+ queue.push(
401
+ embedContent(file, section, attributes, data).then((replace) => {
402
+ Object.assign(
403
+ parent && parent.type === "paragraph" ? parent : node,
404
+ replace
405
+ );
406
+ })
407
+ );
408
+ return "skip";
409
+ });
336
410
  await Promise.all(queue);
337
411
  }
338
412
  return async (tree, file) => {
@@ -345,7 +419,7 @@ function getDefaultProcessor(format) {
345
419
  return mdProcessor.use(import_remark_mdx.default);
346
420
  }
347
421
 
348
- // src/mdx/remark-postprocess.ts
422
+ // src/loaders/mdx/remark-postprocess.ts
349
423
  var import_unist_util_visit2 = require("unist-util-visit");
350
424
  var import_mdast_util_to_markdown = require("mdast-util-to-markdown");
351
425
  var import_estree_util_value_to_estree = require("estree-util-value-to-estree");
@@ -374,7 +448,7 @@ function remarkPostprocess({
374
448
  if (includeProcessedMarkdown) {
375
449
  file.data._markdown = (0, import_mdast_util_to_markdown.toMarkdown)(tree, {
376
450
  ...this.data("settings"),
377
- // @ts-expect-error - from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
451
+ // from https://github.com/remarkjs/remark/blob/main/packages/remark-stringify/lib/index.js
378
452
  extensions: this.data("toMarkdownExtensions") || []
379
453
  });
380
454
  }
@@ -428,7 +502,7 @@ function flattenNode2(node) {
428
502
  return "";
429
503
  }
430
504
 
431
- // src/mdx/build-mdx.ts
505
+ // src/loaders/mdx/build-mdx.ts
432
506
  var cache2 = /* @__PURE__ */ new Map();
433
507
  async function buildMDX(cacheKey, source, options) {
434
508
  const { filePath, frontmatter, data, _compiler, ...rest } = options;
@@ -464,7 +538,7 @@ async function buildMDX(cacheKey, source, options) {
464
538
  return processor;
465
539
  }
466
540
  return getProcessor(
467
- options.format ?? filePath.endsWith(".mdx") ? "mdx" : "md"
541
+ options.format ?? (filePath.endsWith(".mdx") ? "mdx" : "md")
468
542
  ).process({
469
543
  value: source,
470
544
  path: filePath,
@@ -477,7 +551,7 @@ async function buildMDX(cacheKey, source, options) {
477
551
  });
478
552
  }
479
553
 
480
- // src/loaders/mdx.ts
554
+ // src/loaders/mdx/index.ts
481
555
  var import_zod = require("zod");
482
556
  var import_promises = __toESM(require("fs/promises"), 1);
483
557
  var import_node_path2 = __toESM(require("path"), 1);
@@ -576,68 +650,19 @@ function createMdxLoader(configLoader) {
576
650
  function generateCacheHash(input) {
577
651
  return (0, import_node_crypto.createHash)("md5").update(input).digest("hex");
578
652
  }
579
-
580
- // src/utils/config.ts
581
- var fs3 = __toESM(require("fs/promises"), 1);
582
- var path4 = __toESM(require("path"), 1);
583
- var import_node_url = require("url");
584
-
585
- // src/config/build.ts
586
- function buildConfig(config) {
587
- const collections = /* @__PURE__ */ new Map();
588
- let globalConfig = {};
589
- for (const [k, v] of Object.entries(config)) {
590
- if (!v) {
591
- continue;
592
- }
593
- if (typeof v === "object" && "type" in v) {
594
- if (v.type === "docs") {
595
- collections.set(k, v);
596
- continue;
597
- }
598
- if (v.type === "doc" || v.type === "meta") {
599
- collections.set(k, v);
600
- continue;
601
- }
602
- }
603
- if (k === "default" && v) {
604
- globalConfig = v;
605
- continue;
606
- }
607
- throw new Error(
608
- `Unknown export "${k}", you can only export collections from source configuration file.`
609
- );
653
+ function countLines(s) {
654
+ let num = 0;
655
+ for (const c of s) {
656
+ if (c === "\n") num++;
610
657
  }
611
- const mdxOptionsCache = /* @__PURE__ */ new Map();
612
- return {
613
- global: globalConfig,
614
- collections,
615
- async getDefaultMDXOptions(mode = "default") {
616
- const cached = mdxOptionsCache.get(mode);
617
- if (cached) return cached;
618
- const input = this.global.mdxOptions;
619
- async function uncached() {
620
- const options = typeof input === "function" ? await input() : input;
621
- const { getDefaultMDXOptions: getDefaultMDXOptions2 } = await Promise.resolve().then(() => (init_preset(), preset_exports));
622
- if (options?.preset === "minimal") return options;
623
- return getDefaultMDXOptions2({
624
- ...options,
625
- _withoutBundler: mode === "remote"
626
- });
627
- }
628
- const result = uncached();
629
- mdxOptionsCache.set(mode, result);
630
- return result;
631
- }
632
- };
658
+ return num;
633
659
  }
634
660
 
635
- // src/utils/config.ts
661
+ // src/loaders/config/index.ts
662
+ var import_node_path3 = __toESM(require("path"), 1);
636
663
  function findConfigFile() {
637
- return path4.resolve("source.config.ts");
664
+ return import_node_path3.default.resolve("source.config.ts");
638
665
  }
639
-
640
- // src/loaders/config-loader.ts
641
666
  function resolvedConfig(loaded) {
642
667
  return {
643
668
  getConfig() {
@@ -647,12 +672,13 @@ function resolvedConfig(loaded) {
647
672
  }
648
673
 
649
674
  // src/bun/index.ts
675
+ init_build();
650
676
  var import_node_querystring = require("querystring");
651
- var import_node_url2 = require("url");
677
+ var import_node_url = require("url");
652
678
  function createMdxPlugin(options = {}) {
653
679
  const { configPath = findConfigFile() } = options;
654
680
  async function getMdxLoader() {
655
- const importPath = (0, import_node_url2.pathToFileURL)(configPath).href;
681
+ const importPath = (0, import_node_url.pathToFileURL)(configPath).href;
656
682
  const out = buildConfig(await import(importPath));
657
683
  return createMdxLoader(resolvedConfig(out));
658
684
  }
package/dist/bun/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import {
2
- createMdxLoader,
3
- resolvedConfig
4
- } from "../chunk-KGUBBRL6.js";
2
+ createMdxLoader
3
+ } from "../chunk-SP7CHRTS.js";
5
4
  import "../chunk-IQAEAI4P.js";
6
5
  import {
7
- findConfigFile
8
- } from "../chunk-POXTQZ4D.js";
9
- import "../chunk-SWNOXPYJ.js";
10
- import "../chunk-KTDVTBMH.js";
6
+ findConfigFile,
7
+ resolvedConfig
8
+ } from "../chunk-XMFLD5J6.js";
11
9
  import {
12
10
  buildConfig
13
- } from "../chunk-YC25YEBF.js";
11
+ } from "../chunk-U4MQ44TS.js";
12
+ import "../chunk-QAUWMR5D.js";
13
+ import "../chunk-LMG6UWCL.js";
14
14
  import "../chunk-VWJKRQZR.js";
15
15
 
16
16
  // src/bun/index.ts
@@ -0,0 +1,29 @@
1
+ // src/next/map/file-cache.ts
2
+ import { LRUCache } from "lru-cache";
3
+ import fs from "fs/promises";
4
+ import path from "path";
5
+ var map = new LRUCache({
6
+ max: 100
7
+ });
8
+ function toFullPath(file) {
9
+ if (path.isAbsolute(file)) {
10
+ return path.relative(process.cwd(), file);
11
+ }
12
+ return file;
13
+ }
14
+ async function readFileWithCache(file) {
15
+ const fullPath = toFullPath(file);
16
+ const cached = map.get(fullPath);
17
+ if (cached) return cached;
18
+ const read = fs.readFile(fullPath).then((s) => s.toString());
19
+ map.set(fullPath, read);
20
+ return read;
21
+ }
22
+ function removeFileCache(file) {
23
+ map.delete(toFullPath(file));
24
+ }
25
+
26
+ export {
27
+ readFileWithCache,
28
+ removeFileCache
29
+ };
@@ -1,4 +1,4 @@
1
- // src/mdx/preset.ts
1
+ // src/loaders/mdx/preset.ts
2
2
  import * as plugins from "fumadocs-core/mdx-plugins";
3
3
  function pluginOption(def, options = []) {
4
4
  const list = def(Array.isArray(options) ? options : []).filter(
@@ -1,14 +1,11 @@
1
1
  import {
2
2
  buildConfig
3
- } from "./chunk-YC25YEBF.js";
3
+ } from "./chunk-U4MQ44TS.js";
4
4
 
5
- // src/utils/config.ts
5
+ // src/loaders/config/load.ts
6
6
  import * as fs from "fs/promises";
7
7
  import * as path from "path";
8
8
  import { pathToFileURL } from "url";
9
- function findConfigFile() {
10
- return path.resolve("source.config.ts");
11
- }
12
9
  var cache = null;
13
10
  async function compileConfig(configPath, outDir) {
14
11
  const { build } = await import("esbuild");
@@ -54,7 +51,6 @@ async function getConfigHash(configPath) {
54
51
  }
55
52
 
56
53
  export {
57
- findConfigFile,
58
54
  loadConfig,
59
55
  getConfigHash
60
56
  };
@@ -0,0 +1,167 @@
1
+ import {
2
+ fumaMatter
3
+ } from "./chunk-VWJKRQZR.js";
4
+
5
+ // src/loaders/mdx/remark-include.ts
6
+ import { unified } from "unified";
7
+ import { visit } from "unist-util-visit";
8
+ import * as path from "path";
9
+ import * as fs from "fs/promises";
10
+ import remarkParse from "remark-parse";
11
+ import remarkMdx from "remark-mdx";
12
+ import { remarkHeading } from "fumadocs-core/mdx-plugins";
13
+ var ElementLikeTypes = [
14
+ "mdxJsxFlowElement",
15
+ "mdxJsxTextElement",
16
+ "containerDirective",
17
+ "textDirective",
18
+ "leafDirective"
19
+ ];
20
+ function isElementLike(node) {
21
+ return ElementLikeTypes.includes(node.type);
22
+ }
23
+ function parseElementAttributes(element) {
24
+ if (Array.isArray(element.attributes)) {
25
+ const attributes = {};
26
+ for (const attr of element.attributes) {
27
+ if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
28
+ attributes[attr.name] = attr.value;
29
+ }
30
+ }
31
+ return attributes;
32
+ }
33
+ return element.attributes ?? {};
34
+ }
35
+ function flattenNode(node) {
36
+ if ("children" in node)
37
+ return node.children.map((child) => flattenNode(child)).join("");
38
+ if ("value" in node) return node.value;
39
+ return "";
40
+ }
41
+ function parseSpecifier(specifier) {
42
+ const idx = specifier.lastIndexOf("#");
43
+ if (idx === -1) return { file: specifier };
44
+ return {
45
+ file: specifier.slice(0, idx),
46
+ section: specifier.slice(idx + 1)
47
+ };
48
+ }
49
+ function extractSection(root, section) {
50
+ let nodes;
51
+ let capturingHeadingContent = false;
52
+ visit(root, (node) => {
53
+ if (node.type === "heading") {
54
+ if (capturingHeadingContent) {
55
+ return false;
56
+ }
57
+ if (node.data?.hProperties?.id === section) {
58
+ capturingHeadingContent = true;
59
+ nodes = [node];
60
+ return "skip";
61
+ }
62
+ return;
63
+ }
64
+ if (capturingHeadingContent) {
65
+ nodes?.push(node);
66
+ return "skip";
67
+ }
68
+ if (isElementLike(node) && node.name === "section") {
69
+ const attributes = parseElementAttributes(node);
70
+ if (attributes.id === section) {
71
+ nodes = node.children;
72
+ return false;
73
+ }
74
+ }
75
+ });
76
+ if (nodes)
77
+ return {
78
+ type: "root",
79
+ children: nodes
80
+ };
81
+ }
82
+ function remarkInclude() {
83
+ const TagName = "include";
84
+ async function embedContent(file, heading, params, data) {
85
+ let content;
86
+ try {
87
+ content = (await fs.readFile(file)).toString();
88
+ } catch (e) {
89
+ throw new Error(
90
+ `failed to read file ${file}
91
+ ${e instanceof Error ? e.message : String(e)}`,
92
+ { cause: e }
93
+ );
94
+ }
95
+ const ext = path.extname(file);
96
+ data._compiler?.addDependency(file);
97
+ if (params.lang || ext !== ".md" && ext !== ".mdx") {
98
+ const lang = params.lang ?? ext.slice(1);
99
+ return {
100
+ type: "code",
101
+ lang,
102
+ meta: params.meta,
103
+ value: content,
104
+ data: {}
105
+ };
106
+ }
107
+ const parser = (data._getProcessor ?? getDefaultProcessor)(
108
+ ext === ".mdx" ? "mdx" : "md"
109
+ );
110
+ const parsed = fumaMatter(content);
111
+ let mdast = parser.parse({
112
+ path: file,
113
+ value: parsed.content,
114
+ data: { frontmatter: parsed.data }
115
+ });
116
+ if (heading) {
117
+ const extracted = extractSection(
118
+ await unified().use(remarkHeading).run(mdast),
119
+ heading
120
+ );
121
+ if (!extracted)
122
+ throw new Error(
123
+ `Cannot find section ${heading} in ${file}, make sure you have encapsulated the section in a <section id="${heading}"> tag, or a :::section directive with remark-directive configured.`
124
+ );
125
+ mdast = extracted;
126
+ }
127
+ await update(mdast, path.dirname(file), data);
128
+ return mdast;
129
+ }
130
+ async function update(tree, directory, data) {
131
+ const queue = [];
132
+ visit(tree, ElementLikeTypes, (_node, _, parent) => {
133
+ const node = _node;
134
+ if (node.name !== TagName) return;
135
+ const specifier = flattenNode(node);
136
+ if (specifier.length === 0) return "skip";
137
+ const attributes = parseElementAttributes(node);
138
+ const { file: relativePath, section } = parseSpecifier(specifier);
139
+ const file = path.resolve(
140
+ "cwd" in attributes ? process.cwd() : directory,
141
+ relativePath
142
+ );
143
+ queue.push(
144
+ embedContent(file, section, attributes, data).then((replace) => {
145
+ Object.assign(
146
+ parent && parent.type === "paragraph" ? parent : node,
147
+ replace
148
+ );
149
+ })
150
+ );
151
+ return "skip";
152
+ });
153
+ await Promise.all(queue);
154
+ }
155
+ return async (tree, file) => {
156
+ await update(tree, path.dirname(file.path), file.data);
157
+ };
158
+ }
159
+ function getDefaultProcessor(format) {
160
+ const mdProcessor = unified().use(remarkParse);
161
+ if (format === "md") return mdProcessor;
162
+ return mdProcessor.use(remarkMdx);
163
+ }
164
+
165
+ export {
166
+ remarkInclude
167
+ };