@ox-content/unplugin 2.90.0 → 3.0.0-alpha.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.
package/dist/index.d.mts CHANGED
@@ -277,6 +277,14 @@ interface OxContentOptions {
277
277
  * @default true
278
278
  */
279
279
  gfm?: boolean;
280
+ /**
281
+ * Enable MDX JSX, ESM, and expressions.
282
+ *
283
+ * When omitted, MDX is enabled for `.mdx` files only. Explicit `true` or
284
+ * `false` overrides extension-based detection.
285
+ * @default inferred from the source extension
286
+ */
287
+ mdx?: boolean;
280
288
  /**
281
289
  * Enable footnotes.
282
290
  * @default true
@@ -302,11 +310,6 @@ interface OxContentOptions {
302
310
  * @default false
303
311
  */
304
312
  highlight?: boolean;
305
- /**
306
- * Syntax highlighting theme.
307
- * @default 'github-dark'
308
- */
309
- highlightTheme?: string;
310
313
  /**
311
314
  * Opt-in line annotations for fenced code blocks.
312
315
  *
@@ -327,6 +330,13 @@ interface OxContentOptions {
327
330
  * @default false
328
331
  */
329
332
  mermaid?: boolean;
333
+ /**
334
+ * Enable `$…$` inline and `$$…$$` block math.
335
+ * @default false
336
+ */
337
+ math?: boolean | {
338
+ enabled?: boolean;
339
+ };
330
340
  /**
331
341
  * Parse YAML frontmatter.
332
342
  * @default true
@@ -392,14 +402,15 @@ interface ResolvedDocsConfig {
392
402
  interface ResolvedOptions {
393
403
  srcDir: string;
394
404
  gfm: boolean;
405
+ mdx?: boolean;
395
406
  footnotes: boolean;
396
407
  tables: boolean;
397
408
  taskLists: boolean;
398
409
  strikethrough: boolean;
399
410
  highlight: boolean;
400
- highlightTheme: string;
401
411
  codeAnnotations: ResolvedCodeAnnotationsOptions;
402
412
  mermaid: boolean;
413
+ math: boolean;
403
414
  frontmatter: boolean;
404
415
  toc: boolean;
405
416
  tocMaxDepth: number;
@@ -448,6 +459,11 @@ interface OxContentMdastOptions {
448
459
  * @default true
449
460
  */
450
461
  gfm?: boolean;
462
+ /**
463
+ * Enable MDX JSX, ESM, and expression nodes.
464
+ * @default false
465
+ */
466
+ mdx?: boolean;
451
467
  /**
452
468
  * Enable footnotes.
453
469
  * @default true
package/dist/src.mjs CHANGED
@@ -86,6 +86,11 @@ const KIND_DELETE = 19;
86
86
  const KIND_FOOTNOTE_REFERENCE = 20;
87
87
  const KIND_DEFINITION = 21;
88
88
  const KIND_FOOTNOTE_DEFINITION = 22;
89
+ const KIND_MDX_JSX_FLOW = 23;
90
+ const KIND_MDX_JSX_TEXT = 24;
91
+ const KIND_MDX_ESM = 25;
92
+ const KIND_MDX_FLOW_EXPRESSION = 26;
93
+ const KIND_MDX_TEXT_EXPRESSION = 27;
89
94
  const FLAG_ORDERED = 1;
90
95
  const FLAG_SPREAD = 2;
91
96
  const FLAG_CHECKED_PRESENT = 4;
@@ -309,6 +314,35 @@ function deserializeMdastFromRaw(buffer, source) {
309
314
  if (str1 !== void 0) node.label = str1;
310
315
  return node;
311
316
  }
317
+ case KIND_MDX_JSX_FLOW: return {
318
+ type: "mdxJsxFlowElement",
319
+ name: str0 ?? null,
320
+ attributes: parseMdxAttributes(str1),
321
+ children: children ?? [],
322
+ position
323
+ };
324
+ case KIND_MDX_JSX_TEXT: return {
325
+ type: "mdxJsxTextElement",
326
+ name: str0 ?? null,
327
+ attributes: parseMdxAttributes(str1),
328
+ children: children ?? [],
329
+ position
330
+ };
331
+ case KIND_MDX_ESM: return {
332
+ type: "mdxjsEsm",
333
+ value: str0 ?? "",
334
+ position
335
+ };
336
+ case KIND_MDX_FLOW_EXPRESSION: return {
337
+ type: "mdxFlowExpression",
338
+ value: str0 ?? "",
339
+ position
340
+ };
341
+ case KIND_MDX_TEXT_EXPRESSION: return {
342
+ type: "mdxTextExpression",
343
+ value: str0 ?? "",
344
+ position
345
+ };
312
346
  default: throw new Error(`[ox-content] Unsupported mdast raw node kind: ${kind}`);
313
347
  }
314
348
  };
@@ -316,6 +350,17 @@ function deserializeMdastFromRaw(buffer, source) {
316
350
  if (root.type !== "root" || !Array.isArray(root.children)) throw new Error("[ox-content] Native parser returned an invalid mdast root.");
317
351
  return root;
318
352
  }
353
+ function parseMdxAttributes(value) {
354
+ if (value === void 0) return [];
355
+ let attributes;
356
+ try {
357
+ attributes = JSON.parse(value);
358
+ } catch {
359
+ throw new Error("[ox-content] mdast raw transfer contains invalid MDX attributes.");
360
+ }
361
+ if (!Array.isArray(attributes)) throw new Error("[ox-content] mdast raw transfer contains invalid MDX attributes.");
362
+ return attributes;
363
+ }
319
364
  function readSourceOrigin(buffer, view) {
320
365
  const section = parseTransferEnvelope(buffer)?.sections.get(MDAST_SECTION_SOURCE_ORIGIN$1);
321
366
  if (!section) return;
@@ -451,6 +496,7 @@ const require$1 = createRequire(import.meta.url);
451
496
  let cachedNapiBindings$1;
452
497
  const DEFAULT_MDAST_OPTIONS = {
453
498
  gfm: true,
499
+ mdx: false,
454
500
  footnotes: true,
455
501
  taskLists: true,
456
502
  tables: true,
@@ -483,6 +529,7 @@ function parseMarkdownToMdast(source, options = {}) {
483
529
  const resolvedOptions = resolveMdastOptions(options);
484
530
  const parserOptions = {
485
531
  gfm: resolvedOptions.gfm,
532
+ mdx: resolvedOptions.mdx,
486
533
  footnotes: resolvedOptions.footnotes,
487
534
  taskLists: resolvedOptions.taskLists,
488
535
  tables: resolvedOptions.tables,
@@ -550,6 +597,7 @@ function requireNapiMethod$1(method, name) {
550
597
  function resolveMdastOptions(options) {
551
598
  return {
552
599
  gfm: options.gfm ?? DEFAULT_MDAST_OPTIONS.gfm,
600
+ mdx: options.mdx ?? DEFAULT_MDAST_OPTIONS.mdx,
553
601
  footnotes: options.footnotes ?? DEFAULT_MDAST_OPTIONS.footnotes,
554
602
  taskLists: options.taskLists ?? DEFAULT_MDAST_OPTIONS.taskLists,
555
603
  tables: options.tables ?? DEFAULT_MDAST_OPTIONS.tables,
@@ -590,6 +638,21 @@ function slugify$1(text) {
590
638
  return text.toLowerCase().replace(/[^\p{L}\p{N}\s-]+/gu, " ").trim().split(/\s+/).filter(Boolean).join("-");
591
639
  }
592
640
  //#endregion
641
+ //#region src/source-path.ts
642
+ function sourcePathname(id) {
643
+ return id.split("?")[0].split("#")[0];
644
+ }
645
+ function isConfiguredSourceFile(id, extensions) {
646
+ const pathname = sourcePathname(id).toLowerCase();
647
+ return extensions.some((extension) => pathname.endsWith(extension.toLowerCase()));
648
+ }
649
+ function isMdxSourceFile(id) {
650
+ return sourcePathname(id).toLowerCase().endsWith(".mdx");
651
+ }
652
+ function resolveMdxForSourceFile(id, configured) {
653
+ return configured ?? isMdxSourceFile(id);
654
+ }
655
+ //#endregion
593
656
  //#region src/transform.ts
594
657
  /**
595
658
  * Markdown transformation logic for @ox-content/unplugin.
@@ -612,7 +675,7 @@ const PREPARED_SOURCE_SECTION_SOURCE_ORIGIN = 3;
612
675
  * Note: This requires the @ox-content/napi package to be built.
613
676
  */
614
677
  async function transformMarkdown(source, filePath, options) {
615
- const transformed = hasMarkdownItPlugins(options) ? await transformWithMarkdownIt(source, filePath, options) : hasUnifiedPlugins(options) ? await transformWithUnified(source, filePath, options) : transformWithNativePipeline(loadNapiBindings(), source, options);
678
+ const transformed = hasMarkdownItPlugins(options) ? await transformWithMarkdownIt(source, filePath, options) : hasUnifiedPlugins(options) ? await transformWithUnified(source, filePath, options) : transformWithNativePipeline(loadNapiBindings(), source, filePath, options);
616
679
  let nextHtml = transformed.html;
617
680
  for (const plugin of options.plugin.oxContent) nextHtml = await plugin(nextHtml);
618
681
  return {
@@ -633,13 +696,14 @@ function loadNapiBindings() {
633
696
  throw new Error("[ox-content] Failed to load @ox-content/napi. Please ensure the NAPI module is built. Run: mise run build:napi");
634
697
  }
635
698
  }
636
- function createNapiTransformOptions(options) {
699
+ function createNapiTransformOptions(options, filePath) {
637
700
  const codeAnnotations = options.codeAnnotations ?? {
638
701
  enabled: false,
639
702
  metaKey: "annotate"
640
703
  };
641
704
  return {
642
705
  gfm: options.gfm,
706
+ mdx: resolveMdxForSourceFile(filePath, options.mdx),
643
707
  footnotes: options.footnotes,
644
708
  taskLists: options.taskLists,
645
709
  tables: options.tables,
@@ -648,7 +712,8 @@ function createNapiTransformOptions(options) {
648
712
  frontmatter: options.frontmatter,
649
713
  tocMaxDepth: options.tocMaxDepth,
650
714
  codeAnnotations: codeAnnotations.enabled,
651
- codeAnnotationMetaKey: codeAnnotations.metaKey
715
+ codeAnnotationMetaKey: codeAnnotations.metaKey,
716
+ math: options.math
652
717
  };
653
718
  }
654
719
  function parseFrontmatterJson(json) {
@@ -672,8 +737,8 @@ function hasMarkdownItPlugins(options) {
672
737
  function hasMdastOrRemarkPlugins(options) {
673
738
  return options.plugin.mdast.length > 0 || options.plugin.remark.length > 0;
674
739
  }
675
- function transformWithNativePipeline(napi, source, options) {
676
- const result = napi.transform(source, createNapiTransformOptions(options));
740
+ function transformWithNativePipeline(napi, source, filePath, options) {
741
+ const result = napi.transform(source, createNapiTransformOptions(options, filePath));
677
742
  if (result.errors.length > 0) console.warn("[ox-content] Transform warnings:", result.errors);
678
743
  const flatToc = result.toc.map((item) => ({
679
744
  ...item,
@@ -685,8 +750,8 @@ function transformWithNativePipeline(napi, source, options) {
685
750
  toc: options.toc ? buildTocTree(flatToc) : []
686
751
  };
687
752
  }
688
- function transformWithNativeMdastPipeline(napi, source, options) {
689
- return deserializeNativeMdastTransform(requireNapiMethod(napi.transformMdastRaw, "transformMdastRaw")(source, createNapiTransformOptions(options)));
753
+ function transformWithNativeMdastPipeline(napi, source, filePath, options) {
754
+ return deserializeNativeMdastTransform(requireNapiMethod(napi.transformMdastRaw, "transformMdastRaw")(source, createNapiTransformOptions(options, filePath)));
690
755
  }
691
756
  function deserializeNativeMdastTransform(buffer) {
692
757
  const envelope = parseTransferEnvelope(buffer);
@@ -781,7 +846,7 @@ async function transformWithUnified(fullSource, filePath, options) {
781
846
  const { plugins: remarkPlugins, options: remarkRehypeOptions } = extractUnifiedPluginWithOptions(options.plugin.remark, remarkRehype);
782
847
  const { plugins: rehypePlugins, options: rehypeStringifyOptions } = extractUnifiedPluginWithOptions(options.plugin.rehype, rehypeStringify);
783
848
  const parserStrategy = detectUnifiedParserStrategy(fullSource, filePath, options, remarkPlugins);
784
- const nativePayload = parserStrategy === "native" ? transformWithNativeMdastPipeline(loadNapiBindings(), fullSource, options) : null;
849
+ const nativePayload = parserStrategy === "native" ? transformWithNativeMdastPipeline(loadNapiBindings(), fullSource, filePath, options) : null;
785
850
  const preparedInput = parserStrategy === "native" ? null : prepareSourceWithRust(loadNapiBindings(), fullSource, options);
786
851
  const markdownContent = nativePayload?.content ?? preparedInput?.content ?? fullSource;
787
852
  const frontmatter = nativePayload?.frontmatter ?? preparedInput?.frontmatter ?? {};
@@ -790,7 +855,7 @@ async function transformWithUnified(fullSource, filePath, options) {
790
855
  const processor = unified();
791
856
  applyUnifiedPlugins(processor, options.plugin.mdast.map((plugin) => isOxContentMdastPlugin(plugin) ? toUnifiedMdastPlugin(plugin, mdastContext) : plugin));
792
857
  applyUnifiedPlugins(processor, remarkPlugins);
793
- installUnifiedParser(processor, parserStrategy, options, nativePayload?.tree);
858
+ installUnifiedParser(processor, parserStrategy, options, filePath, nativePayload?.tree);
794
859
  let toc = [];
795
860
  processor.use(() => {
796
861
  return (tree) => {
@@ -867,7 +932,7 @@ function applyMarkdownItPlugins(markdownIt, plugins) {
867
932
  function isOxContentMdastPlugin(plugin) {
868
933
  return Boolean(plugin) && typeof plugin === "object" && "transform" in plugin;
869
934
  }
870
- function installUnifiedParser(processor, strategy, options, nativeTree) {
935
+ function installUnifiedParser(processor, strategy, options, filePath, nativeTree) {
871
936
  if (strategy === "custom") return;
872
937
  if (strategy === "remark") {
873
938
  processor.use(remarkParse);
@@ -881,6 +946,7 @@ function installUnifiedParser(processor, strategy, options, nativeTree) {
881
946
  }
882
947
  processor.use(oxContentMdast, {
883
948
  gfm: options.gfm,
949
+ mdx: resolveMdxForSourceFile(filePath, options.mdx),
884
950
  footnotes: options.footnotes,
885
951
  taskLists: options.taskLists,
886
952
  tables: options.tables,
@@ -1222,14 +1288,15 @@ function resolveOptions(options) {
1222
1288
  return {
1223
1289
  srcDir: options.srcDir ?? "docs",
1224
1290
  gfm: options.gfm ?? true,
1291
+ mdx: options.mdx,
1225
1292
  footnotes: options.footnotes ?? true,
1226
1293
  tables: options.tables ?? true,
1227
1294
  taskLists: options.taskLists ?? true,
1228
1295
  strikethrough: options.strikethrough ?? true,
1229
1296
  highlight: options.highlight ?? false,
1230
- highlightTheme: options.highlightTheme ?? "github-dark",
1231
1297
  codeAnnotations: resolveCodeAnnotationsOptions(options.codeAnnotations),
1232
1298
  mermaid: options.mermaid ?? false,
1299
+ math: options.math === true || typeof options.math === "object" && options.math.enabled !== false,
1233
1300
  frontmatter: options.frontmatter ?? true,
1234
1301
  toc: options.toc ?? true,
1235
1302
  tocMaxDepth: options.tocMaxDepth ?? 3,
@@ -1264,7 +1331,7 @@ function resolveCodeAnnotationsOptions(options) {
1264
1331
  * Check if the file should be processed.
1265
1332
  */
1266
1333
  function isMarkdownFile(id, options) {
1267
- return options.extensions.some((ext) => id.endsWith(ext));
1334
+ return isConfiguredSourceFile(id, options.extensions);
1268
1335
  }
1269
1336
  /**
1270
1337
  * The unplugin factory function.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ox-content/unplugin",
3
- "version": "2.90.0",
3
+ "version": "3.0.0-alpha.1",
4
4
  "description": "Universal plugin for Ox Content - Markdown processing for webpack, rollup, esbuild, vite, and more",
5
5
  "keywords": [
6
6
  "esbuild",
@@ -65,11 +65,11 @@
65
65
  "remark-rehype": "^11.1.1",
66
66
  "unified": "^11.0.5",
67
67
  "unplugin": "^3.3.0",
68
- "@ox-content/napi": "2.90.0"
68
+ "@ox-content/napi": "3.0.0-alpha.1"
69
69
  },
70
70
  "devDependencies": {
71
- "@types/markdown-it": "^14.1.2",
72
- "@types/node": "^26.1.2",
71
+ "@types/markdown-it": "^14.2.0",
72
+ "@types/node": "^26.2.0",
73
73
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",
74
74
  "esbuild": "^0.28.1",
75
75
  "rehype-autolink-headings": "^7.1.0",
@@ -84,10 +84,10 @@
84
84
  "remark-math": "^6.0.0",
85
85
  "remark-smartypants": "^3.0.3",
86
86
  "remark-toc": "^9.0.0",
87
- "rollup": "^4.62.4",
87
+ "rollup": "^4.62.5",
88
88
  "typescript": "^7.0.2",
89
89
  "vite": "npm:@voidzero-dev/vite-plus-core@0.2.8",
90
- "vite-plus": "0.2.8",
90
+ "vite-plus": "0.2.9",
91
91
  "webpack": "^5.109.2"
92
92
  },
93
93
  "scripts": {