@ox-content/vite-plugin-react 0.17.0 → 1.1.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.
- package/dist/index.cjs +93 -83
- package/dist/index.d.cts +9 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/{index.d.ts → index.d.mts} +10 -2
- package/dist/index.d.mts.map +1 -0
- package/dist/{index.js → index.mjs} +67 -52
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -37
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -6,16 +7,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
19
16
|
}
|
|
20
17
|
return to;
|
|
21
18
|
};
|
|
@@ -23,14 +20,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
20
|
value: mod,
|
|
24
21
|
enumerable: true
|
|
25
22
|
}) : target, mod));
|
|
26
|
-
|
|
27
23
|
//#endregion
|
|
28
24
|
let fs = require("fs");
|
|
29
25
|
fs = __toESM(fs);
|
|
30
|
-
let path
|
|
31
|
-
path
|
|
26
|
+
let path = require("path");
|
|
27
|
+
path = __toESM(path);
|
|
32
28
|
let _ox_content_vite_plugin = require("@ox-content/vite-plugin");
|
|
33
|
-
|
|
34
29
|
//#region src/transform.ts
|
|
35
30
|
const COMPONENT_REGEX = /<([A-Z][a-zA-Z0-9]*)\s*([^>]*?)\s*(?:\/>|>([\s\S]*?)<\/\1>)/g;
|
|
36
31
|
const PROP_REGEX = /([a-zA-Z0-9-]+)(?:=(?:"([^"]*)"|'([^']*)'|{([^}]*)}|\[([^\]]*)\]))?/g;
|
|
@@ -71,50 +66,52 @@ async function transformMarkdownWithReact(code, id, options) {
|
|
|
71
66
|
lastIndex = matchEnd;
|
|
72
67
|
}
|
|
73
68
|
processedContent += markdownContent.slice(lastIndex);
|
|
69
|
+
const baseOptions = {
|
|
70
|
+
srcDir: options.srcDir,
|
|
71
|
+
outDir: options.outDir,
|
|
72
|
+
base: options.base,
|
|
73
|
+
ssg: {
|
|
74
|
+
enabled: false,
|
|
75
|
+
extension: ".html",
|
|
76
|
+
clean: false,
|
|
77
|
+
bare: false,
|
|
78
|
+
generateOgImage: false
|
|
79
|
+
},
|
|
80
|
+
gfm: options.gfm,
|
|
81
|
+
frontmatter: false,
|
|
82
|
+
toc: options.toc,
|
|
83
|
+
tocMaxDepth: options.tocMaxDepth,
|
|
84
|
+
codeAnnotations: options.codeAnnotations,
|
|
85
|
+
footnotes: true,
|
|
86
|
+
tables: true,
|
|
87
|
+
taskLists: true,
|
|
88
|
+
strikethrough: true,
|
|
89
|
+
highlight: false,
|
|
90
|
+
highlightTheme: "github-dark",
|
|
91
|
+
highlightLangs: [],
|
|
92
|
+
mermaid: false,
|
|
93
|
+
ogImage: false,
|
|
94
|
+
ogImageOptions: {
|
|
95
|
+
vuePlugin: "vitejs",
|
|
96
|
+
width: 1200,
|
|
97
|
+
height: 630,
|
|
98
|
+
cache: true,
|
|
99
|
+
concurrency: 1
|
|
100
|
+
},
|
|
101
|
+
transformers: [],
|
|
102
|
+
docs: false,
|
|
103
|
+
ogViewer: false,
|
|
104
|
+
search: {
|
|
105
|
+
enabled: false,
|
|
106
|
+
limit: 10,
|
|
107
|
+
prefix: true,
|
|
108
|
+
placeholder: "Search...",
|
|
109
|
+
hotkey: "k"
|
|
110
|
+
},
|
|
111
|
+
i18n: false
|
|
112
|
+
};
|
|
74
113
|
return {
|
|
75
|
-
code: generateReactModule(injectIslandMarkers((await (0, _ox_content_vite_plugin.transformMarkdown)(processedContent, id,
|
|
76
|
-
srcDir: options.srcDir,
|
|
77
|
-
outDir: options.outDir,
|
|
78
|
-
base: options.base,
|
|
79
|
-
ssg: {
|
|
80
|
-
enabled: false,
|
|
81
|
-
extension: ".html",
|
|
82
|
-
clean: false,
|
|
83
|
-
bare: false,
|
|
84
|
-
generateOgImage: false
|
|
85
|
-
},
|
|
86
|
-
gfm: options.gfm,
|
|
87
|
-
frontmatter: false,
|
|
88
|
-
toc: options.toc,
|
|
89
|
-
tocMaxDepth: options.tocMaxDepth,
|
|
90
|
-
footnotes: true,
|
|
91
|
-
tables: true,
|
|
92
|
-
taskLists: true,
|
|
93
|
-
strikethrough: true,
|
|
94
|
-
highlight: false,
|
|
95
|
-
highlightTheme: "github-dark",
|
|
96
|
-
highlightLangs: [],
|
|
97
|
-
mermaid: false,
|
|
98
|
-
ogImage: false,
|
|
99
|
-
ogImageOptions: {
|
|
100
|
-
vuePlugin: "vitejs",
|
|
101
|
-
width: 1200,
|
|
102
|
-
height: 630,
|
|
103
|
-
cache: true,
|
|
104
|
-
concurrency: 1
|
|
105
|
-
},
|
|
106
|
-
transformers: [],
|
|
107
|
-
docs: false,
|
|
108
|
-
ogViewer: false,
|
|
109
|
-
search: {
|
|
110
|
-
enabled: false,
|
|
111
|
-
limit: 10,
|
|
112
|
-
prefix: true,
|
|
113
|
-
placeholder: "Search...",
|
|
114
|
-
hotkey: "k"
|
|
115
|
-
},
|
|
116
|
-
i18n: false
|
|
117
|
-
})).html, islands), usedComponents, islands, frontmatter, options, id),
|
|
114
|
+
code: generateReactModule(injectIslandMarkers((await (0, _ox_content_vite_plugin.transformMarkdown)(processedContent, id, baseOptions)).html, islands), usedComponents, islands, frontmatter, options, id),
|
|
118
115
|
map: null,
|
|
119
116
|
usedComponents,
|
|
120
117
|
frontmatter
|
|
@@ -225,13 +222,13 @@ function parseProps(propsString) {
|
|
|
225
222
|
return props;
|
|
226
223
|
}
|
|
227
224
|
function generateReactModule(content, usedComponents, islands, frontmatter, options, id) {
|
|
228
|
-
const mdDir = path
|
|
225
|
+
const mdDir = path.dirname(id);
|
|
229
226
|
const root = options.root || process.cwd();
|
|
230
227
|
const imports = usedComponents.map((name) => {
|
|
231
228
|
const componentPath = options.components[name];
|
|
232
229
|
if (!componentPath) return "";
|
|
233
|
-
const absolutePath = path
|
|
234
|
-
const relativePath = path
|
|
230
|
+
const absolutePath = path.resolve(root, componentPath.replace(/^\.\//, ""));
|
|
231
|
+
const relativePath = path.relative(mdDir, absolutePath).replace(/\\/g, "/");
|
|
235
232
|
return `import ${name} from '${relativePath.startsWith(".") ? relativePath : "./" + relativePath}';`;
|
|
236
233
|
}).filter(Boolean).join("\n");
|
|
237
234
|
const componentMap = usedComponents.map((name) => ` ${name},`).join("\n");
|
|
@@ -306,7 +303,6 @@ export default function MarkdownContent() {
|
|
|
306
303
|
}
|
|
307
304
|
`;
|
|
308
305
|
}
|
|
309
|
-
|
|
310
306
|
//#endregion
|
|
311
307
|
//#region src/environment.ts
|
|
312
308
|
function createReactMarkdownEnvironment(mode, options) {
|
|
@@ -331,7 +327,6 @@ function createReactMarkdownEnvironment(mode, options) {
|
|
|
331
327
|
}
|
|
332
328
|
};
|
|
333
329
|
}
|
|
334
|
-
|
|
335
330
|
//#endregion
|
|
336
331
|
//#region src/index.ts
|
|
337
332
|
/**
|
|
@@ -426,7 +421,7 @@ function oxContentReact(options = {}) {
|
|
|
426
421
|
name: "ox-content:react-hmr",
|
|
427
422
|
apply: "serve",
|
|
428
423
|
handleHotUpdate({ file, server, modules }) {
|
|
429
|
-
if (Array.from(componentMap.values()).some((path) => file.endsWith(path.replace(/^\.\//, "")))) {
|
|
424
|
+
if (Array.from(componentMap.values()).some((path$1) => file.endsWith(path$1.replace(/^\.\//, "")))) {
|
|
430
425
|
const mdModules = Array.from(server.moduleGraph.idToModuleMap.values()).filter((mod) => mod.file?.endsWith(".md"));
|
|
431
426
|
if (mdModules.length > 0) {
|
|
432
427
|
server.ws.send({
|
|
@@ -440,13 +435,14 @@ function oxContentReact(options = {}) {
|
|
|
440
435
|
return modules;
|
|
441
436
|
}
|
|
442
437
|
};
|
|
443
|
-
const environmentPlugin = (0, _ox_content_vite_plugin.oxContent)(options).find((
|
|
444
|
-
|
|
438
|
+
const environmentPlugin = (0, _ox_content_vite_plugin.oxContent)(options).flatMap((plugin) => Array.isArray(plugin) ? plugin : [plugin]).find((plugin) => plugin.name === "ox-content:environment");
|
|
439
|
+
const plugins = [
|
|
445
440
|
reactTransformPlugin,
|
|
446
441
|
reactEnvironmentPlugin,
|
|
447
|
-
reactHmrPlugin
|
|
448
|
-
...environmentPlugin ? [environmentPlugin] : []
|
|
442
|
+
reactHmrPlugin
|
|
449
443
|
];
|
|
444
|
+
if (environmentPlugin) plugins.push(environmentPlugin);
|
|
445
|
+
return plugins;
|
|
450
446
|
}
|
|
451
447
|
function resolveReactOptions(options) {
|
|
452
448
|
return {
|
|
@@ -457,9 +453,24 @@ function resolveReactOptions(options) {
|
|
|
457
453
|
frontmatter: options.frontmatter ?? true,
|
|
458
454
|
toc: options.toc ?? true,
|
|
459
455
|
tocMaxDepth: options.tocMaxDepth ?? 3,
|
|
456
|
+
codeAnnotations: resolveCodeAnnotationsOptions(options.codeAnnotations),
|
|
460
457
|
jsxRuntime: options.jsxRuntime ?? "automatic"
|
|
461
458
|
};
|
|
462
459
|
}
|
|
460
|
+
function resolveCodeAnnotationsOptions(options) {
|
|
461
|
+
if (!options) return {
|
|
462
|
+
enabled: false,
|
|
463
|
+
metaKey: "annotate"
|
|
464
|
+
};
|
|
465
|
+
if (options === true) return {
|
|
466
|
+
enabled: true,
|
|
467
|
+
metaKey: "annotate"
|
|
468
|
+
};
|
|
469
|
+
return {
|
|
470
|
+
enabled: true,
|
|
471
|
+
metaKey: options.metaKey ?? "annotate"
|
|
472
|
+
};
|
|
473
|
+
}
|
|
463
474
|
function generateRuntimeModule() {
|
|
464
475
|
return `
|
|
465
476
|
import React, { useState, useEffect } from 'react';
|
|
@@ -500,8 +511,8 @@ export function useOxContent() {
|
|
|
500
511
|
function generateComponentsModule(componentMap) {
|
|
501
512
|
const imports = [];
|
|
502
513
|
const exports = [];
|
|
503
|
-
componentMap.forEach((path, name) => {
|
|
504
|
-
imports.push(`import ${name} from '${path}';`);
|
|
514
|
+
componentMap.forEach((path$2, name) => {
|
|
515
|
+
imports.push(`import ${name} from '${path$2}';`);
|
|
505
516
|
exports.push(` ${name},`);
|
|
506
517
|
});
|
|
507
518
|
return `
|
|
@@ -521,8 +532,8 @@ async function resolveComponentsGlob(componentsOption, root) {
|
|
|
521
532
|
for (const pattern of patterns) {
|
|
522
533
|
const files = await globFiles(pattern, root);
|
|
523
534
|
for (const file of files) {
|
|
524
|
-
const componentName = toPascalCase(path
|
|
525
|
-
result[componentName] = "./" + path
|
|
535
|
+
const componentName = toPascalCase(path.basename(file, path.extname(file)));
|
|
536
|
+
result[componentName] = "./" + path.relative(root, file).replace(/\\/g, "/");
|
|
526
537
|
}
|
|
527
538
|
}
|
|
528
539
|
return result;
|
|
@@ -530,25 +541,25 @@ async function resolveComponentsGlob(componentsOption, root) {
|
|
|
530
541
|
async function globFiles(pattern, root) {
|
|
531
542
|
const files = [];
|
|
532
543
|
if (!pattern.includes("*")) {
|
|
533
|
-
const fullPath = path
|
|
544
|
+
const fullPath = path.resolve(root, pattern);
|
|
534
545
|
if (fs.existsSync(fullPath)) files.push(fullPath);
|
|
535
546
|
return files;
|
|
536
547
|
}
|
|
537
548
|
const parts = pattern.split("*");
|
|
538
|
-
const baseDir = path
|
|
549
|
+
const baseDir = path.resolve(root, parts[0]);
|
|
539
550
|
const ext = parts[1] || "";
|
|
540
551
|
if (!fs.existsSync(baseDir)) return files;
|
|
541
552
|
if (pattern.includes("**")) await walkDir(baseDir, files, ext);
|
|
542
553
|
else {
|
|
543
554
|
const entries = await fs.promises.readdir(baseDir, { withFileTypes: true });
|
|
544
|
-
for (const entry of entries) if (entry.isFile() && entry.name.endsWith(ext)) files.push(path
|
|
555
|
+
for (const entry of entries) if (entry.isFile() && entry.name.endsWith(ext)) files.push(path.join(baseDir, entry.name));
|
|
545
556
|
}
|
|
546
557
|
return files;
|
|
547
558
|
}
|
|
548
559
|
async function walkDir(dir, files, ext) {
|
|
549
560
|
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
550
561
|
for (const entry of entries) {
|
|
551
|
-
const fullPath = path
|
|
562
|
+
const fullPath = path.join(dir, entry.name);
|
|
552
563
|
if (entry.isDirectory()) await walkDir(fullPath, files, ext);
|
|
553
564
|
else if (entry.isFile() && entry.name.endsWith(ext)) files.push(fullPath);
|
|
554
565
|
}
|
|
@@ -556,12 +567,11 @@ async function walkDir(dir, files, ext) {
|
|
|
556
567
|
function toPascalCase(str) {
|
|
557
568
|
return str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase());
|
|
558
569
|
}
|
|
559
|
-
|
|
560
570
|
//#endregion
|
|
561
|
-
Object.defineProperty(exports,
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
571
|
+
Object.defineProperty(exports, "oxContent", {
|
|
572
|
+
enumerable: true,
|
|
573
|
+
get: function() {
|
|
574
|
+
return _ox_content_vite_plugin.oxContent;
|
|
575
|
+
}
|
|
566
576
|
});
|
|
567
|
-
exports.oxContentReact = oxContentReact;
|
|
577
|
+
exports.oxContentReact = oxContentReact;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,13 @@ import { PluginOption } from "vite";
|
|
|
2
2
|
import { OxContentOptions, oxContent } from "@ox-content/vite-plugin";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
|
+
interface CodeAnnotationsOptions {
|
|
6
|
+
metaKey?: string;
|
|
7
|
+
}
|
|
8
|
+
interface ResolvedCodeAnnotationsOptions {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
metaKey: string;
|
|
11
|
+
}
|
|
5
12
|
type ComponentsMap = Record<string, string>;
|
|
6
13
|
/**
|
|
7
14
|
* Component registration options.
|
|
@@ -24,6 +31,7 @@ interface ReactIntegrationOptions extends OxContentOptions {
|
|
|
24
31
|
* ```
|
|
25
32
|
*/
|
|
26
33
|
components?: ComponentsOption;
|
|
34
|
+
codeAnnotations?: boolean | CodeAnnotationsOptions;
|
|
27
35
|
jsxRuntime?: "automatic" | "classic";
|
|
28
36
|
}
|
|
29
37
|
interface ResolvedReactOptions {
|
|
@@ -34,6 +42,7 @@ interface ResolvedReactOptions {
|
|
|
34
42
|
frontmatter: boolean;
|
|
35
43
|
toc: boolean;
|
|
36
44
|
tocMaxDepth: number;
|
|
45
|
+
codeAnnotations: ResolvedCodeAnnotationsOptions;
|
|
37
46
|
components: ComponentsMap;
|
|
38
47
|
jsxRuntime: "automatic" | "classic";
|
|
39
48
|
root?: string;
|
|
@@ -51,7 +60,6 @@ interface ComponentIsland {
|
|
|
51
60
|
id: string;
|
|
52
61
|
content?: string;
|
|
53
62
|
}
|
|
54
|
-
//# sourceMappingURL=types.d.ts.map
|
|
55
63
|
//#endregion
|
|
56
64
|
//#region src/index.d.ts
|
|
57
65
|
/**
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;UAEiB,sBAAA;EACf,OAAA;AAAA;AAAA,UAGe,8BAAA;EACf,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,MAAA;AAL5B;;;;AAAA,KAWY,gBAAA,GAAmB,aAAA;AAAA,UAEd,uBAAA,SAAgC,gBAAA;EARxB;;;;AAMzB;;;;;AAEA;;;;;EAeE,UAAA,GAAa,gBAAA;EACb,eAAA,aAA4B,sBAAA;EAC5B,UAAA;AAAA;AAAA,UAGe,oBAAA;EACf,MAAA;EACA,MAAA;EACA,IAAA;EACA,GAAA;EACA,WAAA;EACA,GAAA;EACA,WAAA;EACA,eAAA,EAAiB,8BAAA;EACjB,UAAA,EAAY,aAAA;EACZ,UAAA;EACA,IAAA;AAAA;AAAA,UAGe,oBAAA;EACf,IAAA;EACA,GAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;AAAA;AAAA,UAGE,eAAA;EACf,IAAA;EACA,KAAA,EAAO,MAAA;EACP,QAAA;EACA,EAAA;EACA,OAAA;AAAA;;;;AA3DF;;;;;AAKA;;;;;AAMA;;;;;AAEA;;;;;;;iBCgCgB,cAAA,CAAe,OAAA,GAAS,uBAAA,GAA+B,YAAA"}
|
|
@@ -2,6 +2,13 @@ import { OxContentOptions, oxContent } from "@ox-content/vite-plugin";
|
|
|
2
2
|
import { PluginOption } from "vite";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
|
+
interface CodeAnnotationsOptions {
|
|
6
|
+
metaKey?: string;
|
|
7
|
+
}
|
|
8
|
+
interface ResolvedCodeAnnotationsOptions {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
metaKey: string;
|
|
11
|
+
}
|
|
5
12
|
type ComponentsMap = Record<string, string>;
|
|
6
13
|
/**
|
|
7
14
|
* Component registration options.
|
|
@@ -24,6 +31,7 @@ interface ReactIntegrationOptions extends OxContentOptions {
|
|
|
24
31
|
* ```
|
|
25
32
|
*/
|
|
26
33
|
components?: ComponentsOption;
|
|
34
|
+
codeAnnotations?: boolean | CodeAnnotationsOptions;
|
|
27
35
|
jsxRuntime?: "automatic" | "classic";
|
|
28
36
|
}
|
|
29
37
|
interface ResolvedReactOptions {
|
|
@@ -34,6 +42,7 @@ interface ResolvedReactOptions {
|
|
|
34
42
|
frontmatter: boolean;
|
|
35
43
|
toc: boolean;
|
|
36
44
|
tocMaxDepth: number;
|
|
45
|
+
codeAnnotations: ResolvedCodeAnnotationsOptions;
|
|
37
46
|
components: ComponentsMap;
|
|
38
47
|
jsxRuntime: "automatic" | "classic";
|
|
39
48
|
root?: string;
|
|
@@ -51,7 +60,6 @@ interface ComponentIsland {
|
|
|
51
60
|
id: string;
|
|
52
61
|
content?: string;
|
|
53
62
|
}
|
|
54
|
-
//# sourceMappingURL=types.d.ts.map
|
|
55
63
|
//#endregion
|
|
56
64
|
//#region src/index.d.ts
|
|
57
65
|
/**
|
|
@@ -80,4 +88,4 @@ interface ComponentIsland {
|
|
|
80
88
|
declare function oxContentReact(options?: ReactIntegrationOptions): PluginOption[];
|
|
81
89
|
//#endregion
|
|
82
90
|
export { type ComponentIsland, type ComponentsMap, type ComponentsOption, type ReactIntegrationOptions, type ReactTransformResult, type ResolvedReactOptions, oxContent, oxContentReact };
|
|
83
|
-
//# sourceMappingURL=index.d.
|
|
91
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;UAEiB,sBAAA;EACf,OAAA;AAAA;AAAA,UAGe,8BAAA;EACf,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,MAAA;AAL5B;;;;AAAA,KAWY,gBAAA,GAAmB,aAAA;AAAA,UAEd,uBAAA,SAAgC,gBAAA;EARxB;;;;AAMzB;;;;;AAEA;;;;;EAeE,UAAA,GAAa,gBAAA;EACb,eAAA,aAA4B,sBAAA;EAC5B,UAAA;AAAA;AAAA,UAGe,oBAAA;EACf,MAAA;EACA,MAAA;EACA,IAAA;EACA,GAAA;EACA,WAAA;EACA,GAAA;EACA,WAAA;EACA,eAAA,EAAiB,8BAAA;EACjB,UAAA,EAAY,aAAA;EACZ,UAAA;EACA,IAAA;AAAA;AAAA,UAGe,oBAAA;EACf,IAAA;EACA,GAAA;EACA,cAAA;EACA,WAAA,EAAa,MAAA;AAAA;AAAA,UAGE,eAAA;EACf,IAAA;EACA,KAAA,EAAO,MAAA;EACP,QAAA;EACA,EAAA;EACA,OAAA;AAAA;;;;AA3DF;;;;;AAKA;;;;;AAMA;;;;;AAEA;;;;;;;iBCgCgB,cAAA,CAAe,OAAA,GAAS,uBAAA,GAA+B,YAAA"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { oxContent, oxContent as oxContent$1, transformMarkdown } from "@ox-content/vite-plugin";
|
|
4
|
-
|
|
5
4
|
//#region src/transform.ts
|
|
6
5
|
const COMPONENT_REGEX = /<([A-Z][a-zA-Z0-9]*)\s*([^>]*?)\s*(?:\/>|>([\s\S]*?)<\/\1>)/g;
|
|
7
6
|
const PROP_REGEX = /([a-zA-Z0-9-]+)(?:=(?:"([^"]*)"|'([^']*)'|{([^}]*)}|\[([^\]]*)\]))?/g;
|
|
@@ -42,50 +41,52 @@ async function transformMarkdownWithReact(code, id, options) {
|
|
|
42
41
|
lastIndex = matchEnd;
|
|
43
42
|
}
|
|
44
43
|
processedContent += markdownContent.slice(lastIndex);
|
|
44
|
+
const baseOptions = {
|
|
45
|
+
srcDir: options.srcDir,
|
|
46
|
+
outDir: options.outDir,
|
|
47
|
+
base: options.base,
|
|
48
|
+
ssg: {
|
|
49
|
+
enabled: false,
|
|
50
|
+
extension: ".html",
|
|
51
|
+
clean: false,
|
|
52
|
+
bare: false,
|
|
53
|
+
generateOgImage: false
|
|
54
|
+
},
|
|
55
|
+
gfm: options.gfm,
|
|
56
|
+
frontmatter: false,
|
|
57
|
+
toc: options.toc,
|
|
58
|
+
tocMaxDepth: options.tocMaxDepth,
|
|
59
|
+
codeAnnotations: options.codeAnnotations,
|
|
60
|
+
footnotes: true,
|
|
61
|
+
tables: true,
|
|
62
|
+
taskLists: true,
|
|
63
|
+
strikethrough: true,
|
|
64
|
+
highlight: false,
|
|
65
|
+
highlightTheme: "github-dark",
|
|
66
|
+
highlightLangs: [],
|
|
67
|
+
mermaid: false,
|
|
68
|
+
ogImage: false,
|
|
69
|
+
ogImageOptions: {
|
|
70
|
+
vuePlugin: "vitejs",
|
|
71
|
+
width: 1200,
|
|
72
|
+
height: 630,
|
|
73
|
+
cache: true,
|
|
74
|
+
concurrency: 1
|
|
75
|
+
},
|
|
76
|
+
transformers: [],
|
|
77
|
+
docs: false,
|
|
78
|
+
ogViewer: false,
|
|
79
|
+
search: {
|
|
80
|
+
enabled: false,
|
|
81
|
+
limit: 10,
|
|
82
|
+
prefix: true,
|
|
83
|
+
placeholder: "Search...",
|
|
84
|
+
hotkey: "k"
|
|
85
|
+
},
|
|
86
|
+
i18n: false
|
|
87
|
+
};
|
|
45
88
|
return {
|
|
46
|
-
code: generateReactModule(injectIslandMarkers((await transformMarkdown(processedContent, id,
|
|
47
|
-
srcDir: options.srcDir,
|
|
48
|
-
outDir: options.outDir,
|
|
49
|
-
base: options.base,
|
|
50
|
-
ssg: {
|
|
51
|
-
enabled: false,
|
|
52
|
-
extension: ".html",
|
|
53
|
-
clean: false,
|
|
54
|
-
bare: false,
|
|
55
|
-
generateOgImage: false
|
|
56
|
-
},
|
|
57
|
-
gfm: options.gfm,
|
|
58
|
-
frontmatter: false,
|
|
59
|
-
toc: options.toc,
|
|
60
|
-
tocMaxDepth: options.tocMaxDepth,
|
|
61
|
-
footnotes: true,
|
|
62
|
-
tables: true,
|
|
63
|
-
taskLists: true,
|
|
64
|
-
strikethrough: true,
|
|
65
|
-
highlight: false,
|
|
66
|
-
highlightTheme: "github-dark",
|
|
67
|
-
highlightLangs: [],
|
|
68
|
-
mermaid: false,
|
|
69
|
-
ogImage: false,
|
|
70
|
-
ogImageOptions: {
|
|
71
|
-
vuePlugin: "vitejs",
|
|
72
|
-
width: 1200,
|
|
73
|
-
height: 630,
|
|
74
|
-
cache: true,
|
|
75
|
-
concurrency: 1
|
|
76
|
-
},
|
|
77
|
-
transformers: [],
|
|
78
|
-
docs: false,
|
|
79
|
-
ogViewer: false,
|
|
80
|
-
search: {
|
|
81
|
-
enabled: false,
|
|
82
|
-
limit: 10,
|
|
83
|
-
prefix: true,
|
|
84
|
-
placeholder: "Search...",
|
|
85
|
-
hotkey: "k"
|
|
86
|
-
},
|
|
87
|
-
i18n: false
|
|
88
|
-
})).html, islands), usedComponents, islands, frontmatter, options, id),
|
|
89
|
+
code: generateReactModule(injectIslandMarkers((await transformMarkdown(processedContent, id, baseOptions)).html, islands), usedComponents, islands, frontmatter, options, id),
|
|
89
90
|
map: null,
|
|
90
91
|
usedComponents,
|
|
91
92
|
frontmatter
|
|
@@ -277,7 +278,6 @@ export default function MarkdownContent() {
|
|
|
277
278
|
}
|
|
278
279
|
`;
|
|
279
280
|
}
|
|
280
|
-
|
|
281
281
|
//#endregion
|
|
282
282
|
//#region src/environment.ts
|
|
283
283
|
function createReactMarkdownEnvironment(mode, options) {
|
|
@@ -302,7 +302,6 @@ function createReactMarkdownEnvironment(mode, options) {
|
|
|
302
302
|
}
|
|
303
303
|
};
|
|
304
304
|
}
|
|
305
|
-
|
|
306
305
|
//#endregion
|
|
307
306
|
//#region src/index.ts
|
|
308
307
|
/**
|
|
@@ -411,13 +410,14 @@ function oxContentReact(options = {}) {
|
|
|
411
410
|
return modules;
|
|
412
411
|
}
|
|
413
412
|
};
|
|
414
|
-
const environmentPlugin = oxContent$1(options).find((
|
|
415
|
-
|
|
413
|
+
const environmentPlugin = oxContent$1(options).flatMap((plugin) => Array.isArray(plugin) ? plugin : [plugin]).find((plugin) => plugin.name === "ox-content:environment");
|
|
414
|
+
const plugins = [
|
|
416
415
|
reactTransformPlugin,
|
|
417
416
|
reactEnvironmentPlugin,
|
|
418
|
-
reactHmrPlugin
|
|
419
|
-
...environmentPlugin ? [environmentPlugin] : []
|
|
417
|
+
reactHmrPlugin
|
|
420
418
|
];
|
|
419
|
+
if (environmentPlugin) plugins.push(environmentPlugin);
|
|
420
|
+
return plugins;
|
|
421
421
|
}
|
|
422
422
|
function resolveReactOptions(options) {
|
|
423
423
|
return {
|
|
@@ -428,9 +428,24 @@ function resolveReactOptions(options) {
|
|
|
428
428
|
frontmatter: options.frontmatter ?? true,
|
|
429
429
|
toc: options.toc ?? true,
|
|
430
430
|
tocMaxDepth: options.tocMaxDepth ?? 3,
|
|
431
|
+
codeAnnotations: resolveCodeAnnotationsOptions(options.codeAnnotations),
|
|
431
432
|
jsxRuntime: options.jsxRuntime ?? "automatic"
|
|
432
433
|
};
|
|
433
434
|
}
|
|
435
|
+
function resolveCodeAnnotationsOptions(options) {
|
|
436
|
+
if (!options) return {
|
|
437
|
+
enabled: false,
|
|
438
|
+
metaKey: "annotate"
|
|
439
|
+
};
|
|
440
|
+
if (options === true) return {
|
|
441
|
+
enabled: true,
|
|
442
|
+
metaKey: "annotate"
|
|
443
|
+
};
|
|
444
|
+
return {
|
|
445
|
+
enabled: true,
|
|
446
|
+
metaKey: options.metaKey ?? "annotate"
|
|
447
|
+
};
|
|
448
|
+
}
|
|
434
449
|
function generateRuntimeModule() {
|
|
435
450
|
return `
|
|
436
451
|
import React, { useState, useEffect } from 'react';
|
|
@@ -527,7 +542,7 @@ async function walkDir(dir, files, ext) {
|
|
|
527
542
|
function toPascalCase(str) {
|
|
528
543
|
return str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase());
|
|
529
544
|
}
|
|
530
|
-
|
|
531
545
|
//#endregion
|
|
532
546
|
export { oxContent, oxContentReact };
|
|
533
|
-
|
|
547
|
+
|
|
548
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["baseTransformMarkdown","oxContent"],"sources":["../src/transform.ts","../src/environment.ts","../src/index.ts"],"sourcesContent":["import * as path from \"path\";\nimport { transformMarkdown as baseTransformMarkdown } from \"@ox-content/vite-plugin\";\nimport type {\n ResolvedReactOptions,\n ReactTransformResult,\n ComponentIsland,\n ComponentsMap,\n} from \"./types\";\n\nconst COMPONENT_REGEX = /<([A-Z][a-zA-Z0-9]*)\\s*([^>]*?)\\s*(?:\\/>|>([\\s\\S]*?)<\\/\\1>)/g;\nconst PROP_REGEX = /([a-zA-Z0-9-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|{([^}]*)}|\\[([^\\]]*)\\]))?/g;\n\nconst ISLAND_MARKER_PREFIX = \"OXCONTENT-ISLAND-\";\nconst ISLAND_MARKER_SUFFIX = \"-PLACEHOLDER\";\n\ninterface Range {\n start: number;\n end: number;\n}\n\nexport async function transformMarkdownWithReact(\n code: string,\n id: string,\n options: ResolvedReactOptions,\n): Promise<ReactTransformResult> {\n const components: ComponentsMap = options.components;\n const usedComponents: string[] = [];\n const islands: ComponentIsland[] = [];\n let islandIndex = 0;\n\n const { content: markdownContent, frontmatter } = extractFrontmatter(code);\n const fenceRanges = collectFenceRanges(markdownContent);\n let processedContent = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n COMPONENT_REGEX.lastIndex = 0;\n while ((match = COMPONENT_REGEX.exec(markdownContent)) !== null) {\n const [fullMatch, componentName, propsString, rawIslandContent] = match;\n const matchStart = match.index;\n const matchEnd = matchStart + fullMatch.length;\n\n if (\n !Object.prototype.hasOwnProperty.call(components, componentName) ||\n isInRanges(matchStart, matchEnd, fenceRanges)\n ) {\n processedContent += markdownContent.slice(lastIndex, matchEnd);\n lastIndex = matchEnd;\n continue;\n }\n\n if (!usedComponents.includes(componentName)) {\n usedComponents.push(componentName);\n }\n\n const props = parseProps(propsString);\n const islandId = `ox-island-${islandIndex++}`;\n const islandContent =\n typeof rawIslandContent === \"string\" ? rawIslandContent.trim() : undefined;\n\n islands.push({\n name: componentName,\n props,\n position: matchStart,\n id: islandId,\n content: islandContent,\n });\n\n processedContent += markdownContent.slice(lastIndex, matchStart) + createIslandMarker(islandId);\n lastIndex = matchEnd;\n }\n processedContent += markdownContent.slice(lastIndex);\n\n const baseOptions = {\n srcDir: options.srcDir,\n outDir: options.outDir,\n base: options.base,\n ssg: {\n enabled: false,\n extension: \".html\",\n clean: false,\n bare: false,\n generateOgImage: false,\n },\n gfm: options.gfm,\n frontmatter: false,\n toc: options.toc,\n tocMaxDepth: options.tocMaxDepth,\n codeAnnotations: options.codeAnnotations,\n footnotes: true,\n tables: true,\n taskLists: true,\n strikethrough: true,\n highlight: false,\n highlightTheme: \"github-dark\",\n highlightLangs: [],\n mermaid: false,\n ogImage: false,\n ogImageOptions: {\n vuePlugin: \"vitejs\",\n width: 1200,\n height: 630,\n cache: true,\n concurrency: 1,\n },\n transformers: [],\n docs: false,\n ogViewer: false,\n search: {\n enabled: false,\n limit: 10,\n prefix: true,\n placeholder: \"Search...\",\n hotkey: \"k\",\n },\n i18n: false,\n } as Parameters<typeof baseTransformMarkdown>[2] & {\n codeAnnotations?: ResolvedReactOptions[\"codeAnnotations\"];\n };\n\n const transformed = await baseTransformMarkdown(processedContent, id, baseOptions);\n\n const htmlWithIslands = injectIslandMarkers(transformed.html, islands);\n const jsxCode = generateReactModule(\n htmlWithIslands,\n usedComponents,\n islands,\n frontmatter,\n options,\n id,\n );\n\n return {\n code: jsxCode,\n map: null,\n usedComponents,\n frontmatter,\n };\n}\n\nfunction createIslandMarker(islandId: string): string {\n return `${ISLAND_MARKER_PREFIX}${islandId}${ISLAND_MARKER_SUFFIX}`;\n}\n\nfunction collectFenceRanges(content: string): Range[] {\n const ranges: Range[] = [];\n let inFence = false;\n let fenceChar = \"\";\n let fenceLength = 0;\n let fenceStart = 0;\n let pos = 0;\n\n while (pos < content.length) {\n const lineEnd = content.indexOf(\"\\n\", pos);\n const next = lineEnd === -1 ? content.length : lineEnd + 1;\n const line = content.slice(pos, lineEnd === -1 ? content.length : lineEnd);\n const fenceMatch = line.match(/^\\s{0,3}([`~]{3,})/);\n\n if (fenceMatch) {\n const marker = fenceMatch[1];\n if (!inFence) {\n inFence = true;\n fenceChar = marker[0];\n fenceLength = marker.length;\n fenceStart = pos;\n } else if (marker[0] === fenceChar && marker.length >= fenceLength) {\n inFence = false;\n ranges.push({ start: fenceStart, end: next });\n fenceChar = \"\";\n fenceLength = 0;\n }\n }\n\n pos = next;\n }\n\n if (inFence) {\n ranges.push({ start: fenceStart, end: content.length });\n }\n\n return ranges;\n}\n\nfunction isInRanges(start: number, end: number, ranges: Range[]): boolean {\n for (const range of ranges) {\n if (start < range.end && end > range.start) {\n return true;\n }\n }\n return false;\n}\n\nfunction injectIslandMarkers(html: string, islands: ComponentIsland[]): string {\n let output = html;\n\n for (const island of islands) {\n const marker = createIslandMarker(island.id);\n const propsAttr =\n Object.keys(island.props).length > 0\n ? ` data-ox-props='${JSON.stringify(island.props).replace(/'/g, \"'\")}'`\n : \"\";\n const contentAttr = island.content\n ? ` data-ox-content='${island.content.replace(/'/g, \"'\")}'`\n : \"\";\n const attrs = `data-ox-island=\"${island.name}\"${propsAttr}${contentAttr}`;\n output = output.replaceAll(`<p>${marker}</p>`, `<div ${attrs}></div>`);\n output = output.replaceAll(marker, `<span ${attrs}></span>`);\n }\n\n return output;\n}\n\nfunction extractFrontmatter(content: string): {\n content: string;\n frontmatter: Record<string, unknown>;\n} {\n const frontmatterRegex = /^---\\n([\\s\\S]*?)\\n---\\n/;\n const match = frontmatterRegex.exec(content);\n\n if (!match) {\n return { content, frontmatter: {} };\n }\n\n const frontmatterStr = match[1];\n const frontmatter: Record<string, unknown> = {};\n\n for (const line of frontmatterStr.split(\"\\n\")) {\n const colonIndex = line.indexOf(\":\");\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n let value: unknown = line.slice(colonIndex + 1).trim();\n try {\n value = JSON.parse(value as string);\n } catch {\n if (\n typeof value === \"string\" &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n }\n frontmatter[key] = value;\n }\n }\n\n return { content: content.slice(match[0].length), frontmatter };\n}\n\nfunction parseProps(propsString: string): Record<string, unknown> {\n const props: Record<string, unknown> = {};\n if (!propsString) return props;\n\n PROP_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = PROP_REGEX.exec(propsString)) !== null) {\n const [, name, doubleQuoted, singleQuoted, braceValue, bracketValue] = match;\n if (name) {\n if (doubleQuoted !== undefined) props[name] = doubleQuoted;\n else if (singleQuoted !== undefined) props[name] = singleQuoted;\n else if (braceValue !== undefined) {\n try {\n props[name] = JSON.parse(braceValue);\n } catch {\n props[name] = braceValue;\n }\n } else if (bracketValue !== undefined) {\n try {\n props[name] = JSON.parse(`[${bracketValue}]`);\n } catch {\n props[name] = bracketValue;\n }\n } else props[name] = true;\n }\n }\n return props;\n}\n\nfunction generateReactModule(\n content: string,\n usedComponents: string[],\n islands: ComponentIsland[],\n frontmatter: Record<string, unknown>,\n options: ResolvedReactOptions & { root?: string },\n id: string,\n): string {\n const mdDir = path.dirname(id);\n const root = options.root || process.cwd();\n\n const imports = usedComponents\n .map((name) => {\n const componentPath = options.components[name];\n if (!componentPath) return \"\";\n const absolutePath = path.resolve(root, componentPath.replace(/^\\.\\//, \"\"));\n const relativePath = path.relative(mdDir, absolutePath).replace(/\\\\/g, \"/\");\n const importPath = relativePath.startsWith(\".\") ? relativePath : \"./\" + relativePath;\n return `import ${name} from '${importPath}';`;\n })\n .filter(Boolean)\n .join(\"\\n\");\n\n const componentMap = usedComponents.map((name) => ` ${name},`).join(\"\\n\");\n\n // If no islands, generate simpler code without island runtime\n if (islands.length === 0) {\n return `\nimport React, { createElement } from 'react';\n\nexport const frontmatter = ${JSON.stringify(frontmatter)};\n\nconst rawHtml = ${JSON.stringify(content)};\n\nexport default function MarkdownContent() {\n return createElement('div', {\n className: 'ox-content',\n dangerouslySetInnerHTML: { __html: rawHtml },\n });\n}\n`;\n }\n\n return `\nimport React, { useEffect, useRef, createElement } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { initIslands } from '@ox-content/islands';\n${imports}\n\nexport const frontmatter = ${JSON.stringify(frontmatter)};\n\nconst rawHtml = ${JSON.stringify(content)};\nconst components = {\n${componentMap}\n};\n\nfunction createReactHydrate() {\n const mountedRoots = [];\n\n return (element, props) => {\n const componentName = element.dataset.oxIsland;\n const Component = components[componentName];\n if (!Component) return;\n\n const islandContent = element.dataset.oxContent || element.innerHTML;\n const vnode = islandContent\n ? createElement(\n Component,\n props,\n createElement('div', { dangerouslySetInnerHTML: { __html: islandContent } })\n )\n : createElement(Component, props);\n\n const root = createRoot(element);\n root.render(vnode);\n mountedRoots.push(root);\n\n return () => root.unmount();\n };\n}\n\nexport default function MarkdownContent() {\n const containerRef = useRef(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n const controller = initIslands(createReactHydrate(), {\n selector: '.ox-content [data-ox-island]',\n });\n return () => controller.destroy();\n }, []);\n\n return createElement('div', {\n className: 'ox-content',\n ref: containerRef,\n dangerouslySetInnerHTML: { __html: rawHtml },\n });\n}\n`;\n}\n","import type { EnvironmentOptions } from \"vite\";\nimport type { ResolvedReactOptions } from \"./types\";\n\nexport function createReactMarkdownEnvironment(\n mode: \"ssr\" | \"client\",\n options: ResolvedReactOptions,\n): EnvironmentOptions {\n const isSSR = mode === \"ssr\";\n\n return {\n build: {\n outDir: isSSR ? `${options.outDir}/.ox-content/ssr` : `${options.outDir}/.ox-content/client`,\n ssr: isSSR,\n rollupOptions: {\n output: {\n format: \"esm\",\n entryFileNames: isSSR ? \"[name].js\" : \"[name].[hash].js\",\n },\n },\n ...(isSSR && { target: \"node18\", minify: false }),\n },\n resolve: {\n conditions: isSSR ? [\"node\", \"import\"] : [\"browser\", \"import\"],\n },\n optimizeDeps: {\n include: isSSR ? [] : [\"react\", \"react-dom\"],\n exclude: [\"@ox-content/vite-plugin\", \"@ox-content/vite-plugin-react\"],\n },\n };\n}\n","/**\n * Vite Plugin for Ox Content React Integration\n *\n * Uses Vite's Environment API to enable embedding React components in Markdown.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { Plugin, PluginOption, ResolvedConfig } from \"vite\";\nimport { oxContent } from \"@ox-content/vite-plugin\";\nimport { transformMarkdownWithReact } from \"./transform\";\nimport { createReactMarkdownEnvironment } from \"./environment\";\nimport type {\n ReactIntegrationOptions,\n ResolvedReactOptions,\n ComponentsMap,\n ComponentsOption,\n} from \"./types\";\n\nexport type {\n ReactIntegrationOptions,\n ResolvedReactOptions,\n ComponentsOption,\n ComponentsMap,\n ReactTransformResult,\n ComponentIsland,\n} from \"./types\";\n\n/**\n * Creates the Ox Content React integration plugin.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import react from '@vitejs/plugin-react';\n * import { oxContentReact } from 'vite-plugin-ox-content-react';\n *\n * export default defineConfig({\n * plugins: [\n * react(),\n * oxContentReact({\n * srcDir: 'docs',\n * components: {\n * Counter: './src/components/Counter.tsx',\n * },\n * }),\n * ],\n * });\n * ```\n */\nexport function oxContentReact(options: ReactIntegrationOptions = {}): PluginOption[] {\n const resolved = resolveReactOptions(options);\n let componentMap = new Map<string, string>();\n let config: ResolvedConfig;\n\n if (typeof options.components === \"object\" && !Array.isArray(options.components)) {\n componentMap = new Map(Object.entries(options.components));\n }\n\n const reactTransformPlugin: Plugin = {\n name: \"ox-content:react-transform\",\n enforce: \"pre\",\n\n async configResolved(resolvedConfig) {\n config = resolvedConfig;\n\n const componentsOption = options.components;\n if (componentsOption) {\n const resolvedComponents = await resolveComponentsGlob(componentsOption, config.root);\n componentMap = new Map(Object.entries(resolvedComponents));\n }\n },\n\n async transform(code, id) {\n if (!id.endsWith(\".md\")) {\n return null;\n }\n\n const result = await transformMarkdownWithReact(code, id, {\n ...resolved,\n components: Object.fromEntries(componentMap),\n root: config.root,\n });\n\n return {\n code: result.code,\n map: result.map,\n };\n },\n };\n\n const reactEnvironmentPlugin: Plugin = {\n name: \"ox-content:react-environment\",\n\n config() {\n const envOptions = {\n ...resolved,\n components: Object.fromEntries(componentMap),\n };\n return {\n environments: {\n oxcontent_ssr: createReactMarkdownEnvironment(\"ssr\", envOptions),\n oxcontent_client: createReactMarkdownEnvironment(\"client\", envOptions),\n },\n };\n },\n\n resolveId(id) {\n if (id === \"virtual:ox-content-react/runtime\") {\n return \"\\0virtual:ox-content-react/runtime\";\n }\n if (id === \"virtual:ox-content-react/components\") {\n return \"\\0virtual:ox-content-react/components\";\n }\n return null;\n },\n\n load(id) {\n if (id === \"\\0virtual:ox-content-react/runtime\") {\n return generateRuntimeModule();\n }\n if (id === \"\\0virtual:ox-content-react/components\") {\n return generateComponentsModule(componentMap);\n }\n return null;\n },\n\n applyToEnvironment(environment) {\n return [\"oxcontent_ssr\", \"oxcontent_client\", \"client\", \"ssr\"].includes(environment.name);\n },\n };\n\n const reactHmrPlugin: Plugin = {\n name: \"ox-content:react-hmr\",\n apply: \"serve\",\n\n handleHotUpdate({ file, server, modules }) {\n const isComponent = Array.from(componentMap.values()).some((path) =>\n file.endsWith(path.replace(/^\\.\\//, \"\")),\n );\n\n if (isComponent) {\n const mdModules = Array.from(server.moduleGraph.idToModuleMap.values()).filter((mod) =>\n mod.file?.endsWith(\".md\"),\n );\n\n if (mdModules.length > 0) {\n server.ws.send({\n type: \"custom\",\n event: \"ox-content:react-update\",\n data: { file },\n });\n return [...modules, ...mdModules];\n }\n }\n\n return modules;\n },\n };\n\n const basePlugins = oxContent(options).flatMap((plugin) =>\n Array.isArray(plugin) ? plugin : [plugin],\n ) as Plugin[];\n const environmentPlugin = basePlugins.find((plugin) => plugin.name === \"ox-content:environment\");\n const plugins: Plugin[] = [reactTransformPlugin, reactEnvironmentPlugin, reactHmrPlugin];\n\n if (environmentPlugin) {\n plugins.push(environmentPlugin);\n }\n\n return plugins;\n}\n\nfunction resolveReactOptions(\n options: ReactIntegrationOptions,\n): Omit<ResolvedReactOptions, \"components\"> {\n return {\n srcDir: options.srcDir ?? \"docs\",\n outDir: options.outDir ?? \"dist\",\n base: options.base ?? \"/\",\n gfm: options.gfm ?? true,\n frontmatter: options.frontmatter ?? true,\n toc: options.toc ?? true,\n tocMaxDepth: options.tocMaxDepth ?? 3,\n codeAnnotations: resolveCodeAnnotationsOptions(options.codeAnnotations),\n jsxRuntime: options.jsxRuntime ?? \"automatic\",\n };\n}\n\nfunction resolveCodeAnnotationsOptions(\n options: ReactIntegrationOptions[\"codeAnnotations\"],\n): ResolvedReactOptions[\"codeAnnotations\"] {\n if (!options) {\n return {\n enabled: false,\n metaKey: \"annotate\",\n };\n }\n\n if (options === true) {\n return {\n enabled: true,\n metaKey: \"annotate\",\n };\n }\n\n return {\n enabled: true,\n metaKey: options.metaKey ?? \"annotate\",\n };\n}\n\nfunction generateRuntimeModule(): string {\n return `\nimport React, { useState, useEffect } from 'react';\n\nexport function OxContentRenderer({ content, components = {} }) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n if (!content) return null;\n\n const { html, frontmatter, islands } = content;\n\n if (!mounted) {\n return React.createElement('div', {\n className: 'ox-content',\n dangerouslySetInnerHTML: { __html: html },\n });\n }\n\n return React.createElement('div', { className: 'ox-content' },\n islands.map((island) => {\n const Component = components[island.name];\n return Component\n ? React.createElement(Component, { key: island.id, ...island.props })\n : null;\n })\n );\n}\n\nexport function useOxContent() {\n return { OxContentRenderer };\n}\n`;\n}\n\nfunction generateComponentsModule(componentMap: Map<string, string>): string {\n const imports: string[] = [];\n const exports: string[] = [];\n\n componentMap.forEach((path, name) => {\n imports.push(`import ${name} from '${path}';`);\n exports.push(` ${name},`);\n });\n\n return `\n${imports.join(\"\\n\")}\n\nexport const components = {\n${exports.join(\"\\n\")}\n};\n\nexport default components;\n`;\n}\n\nasync function resolveComponentsGlob(\n componentsOption: ComponentsOption,\n root: string,\n): Promise<ComponentsMap> {\n if (typeof componentsOption === \"object\" && !Array.isArray(componentsOption)) {\n return componentsOption;\n }\n\n const patterns = Array.isArray(componentsOption) ? componentsOption : [componentsOption];\n\n const result: ComponentsMap = {};\n\n for (const pattern of patterns) {\n const files = await globFiles(pattern, root);\n\n for (const file of files) {\n const baseName = path.basename(file, path.extname(file));\n const componentName = toPascalCase(baseName);\n const relativePath = \"./\" + path.relative(root, file).replace(/\\\\/g, \"/\");\n\n result[componentName] = relativePath;\n }\n }\n\n return result;\n}\n\nasync function globFiles(pattern: string, root: string): Promise<string[]> {\n const files: string[] = [];\n const isGlob = pattern.includes(\"*\");\n\n if (!isGlob) {\n const fullPath = path.resolve(root, pattern);\n if (fs.existsSync(fullPath)) {\n files.push(fullPath);\n }\n return files;\n }\n\n const parts = pattern.split(\"*\");\n const baseDir = path.resolve(root, parts[0]);\n const ext = parts[1] || \"\";\n\n if (!fs.existsSync(baseDir)) {\n return files;\n }\n\n if (pattern.includes(\"**\")) {\n await walkDir(baseDir, files, ext);\n } else {\n const entries = await fs.promises.readdir(baseDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith(ext)) {\n files.push(path.join(baseDir, entry.name));\n }\n }\n }\n\n return files;\n}\n\nasync function walkDir(dir: string, files: string[], ext: string): Promise<void> {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n await walkDir(fullPath, files, ext);\n } else if (entry.isFile() && entry.name.endsWith(ext)) {\n files.push(fullPath);\n }\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str.replace(/[-_](\\w)/g, (_, c) => c.toUpperCase()).replace(/^\\w/, (c) => c.toUpperCase());\n}\n\nexport { oxContent } from \"@ox-content/vite-plugin\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,62 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ox-content/vite-plugin-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "React integration for Ox Content - Embed React components in Markdown",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"markdown",
|
|
7
|
+
"mdx",
|
|
8
|
+
"ox-content",
|
|
9
|
+
"react",
|
|
10
|
+
"vite",
|
|
11
|
+
"vite-plugin"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "ubugeeei",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/ubugeeei/ox-content.git",
|
|
18
|
+
"directory": "npm/vite-plugin-ox-content-react"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
5
23
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.
|
|
7
|
-
"types": "./dist/index.d.
|
|
24
|
+
"main": "./dist/index.cjs",
|
|
25
|
+
"types": "./dist/index.d.mts",
|
|
8
26
|
"exports": {
|
|
9
27
|
".": {
|
|
10
|
-
"import": "./dist/index.
|
|
11
|
-
"
|
|
28
|
+
"import": "./dist/index.mjs",
|
|
29
|
+
"require": "./dist/index.cjs",
|
|
30
|
+
"types": "./dist/index.d.mts"
|
|
12
31
|
}
|
|
13
32
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
"peerDependencies": {
|
|
18
|
-
"react": "^19.0.0",
|
|
19
|
-
"react-dom": "^19.0.0",
|
|
20
|
-
"vite": "^8.0.0"
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"provenance": true
|
|
21
36
|
},
|
|
22
37
|
"dependencies": {
|
|
23
|
-
"@ox-content/islands": "
|
|
24
|
-
"@ox-content/vite-plugin": "
|
|
38
|
+
"@ox-content/islands": "1.1.0",
|
|
39
|
+
"@ox-content/vite-plugin": "1.1.0"
|
|
25
40
|
},
|
|
26
41
|
"devDependencies": {
|
|
27
42
|
"@types/node": "^22.0.0",
|
|
28
43
|
"@types/react": "^19.0.0",
|
|
29
44
|
"@types/react-dom": "^19.0.0",
|
|
45
|
+
"@typescript/native-preview": "^7.0.0-dev.20250601",
|
|
30
46
|
"@vitejs/plugin-react": "^6.0.0",
|
|
31
47
|
"react": "^19.0.0",
|
|
32
48
|
"react-dom": "^19.0.0",
|
|
33
|
-
"tsdown": "^0.12.0",
|
|
34
|
-
"@typescript/native-preview": "^7.0.0-dev.20250601",
|
|
35
49
|
"typescript": "^5.7.0",
|
|
36
|
-
"vite": "
|
|
50
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.1.11",
|
|
51
|
+
"vite-plus": "0.1.11"
|
|
37
52
|
},
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"markdown",
|
|
43
|
-
"ox-content",
|
|
44
|
-
"mdx"
|
|
45
|
-
],
|
|
46
|
-
"license": "MIT",
|
|
47
|
-
"author": "ubugeeei",
|
|
48
|
-
"repository": {
|
|
49
|
-
"type": "git",
|
|
50
|
-
"url": "https://github.com/ubugeeei/ox-content.git",
|
|
51
|
-
"directory": "npm/vite-plugin-ox-content-react"
|
|
52
|
-
},
|
|
53
|
-
"publishConfig": {
|
|
54
|
-
"provenance": true,
|
|
55
|
-
"access": "public"
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"react": "^19.0.0",
|
|
55
|
+
"react-dom": "^19.0.0",
|
|
56
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.1.11"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
|
-
"build": "
|
|
59
|
-
"dev": "
|
|
59
|
+
"build": "vp pack",
|
|
60
|
+
"dev": "vp pack --watch",
|
|
60
61
|
"typecheck": "tsgo --noEmit"
|
|
61
62
|
}
|
|
62
63
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;KAEY,aAAA,GAAgB;;;AAA5B;AAMA;AAEiB,KAFL,gBAAA,GAAmB,aAEU,GAAA,MAAA,GAAA,MAAA,EAAA;AAAA,UAAxB,uBAAA,SAAgC,gBAAR,CAAA;;;;AAmBzC;AAaA;AAOA;;;;ACEA;;;;;eD1Be;;;UAIE,oBAAA;;;;;;;;cAQH;;;;UAKG,oBAAA;;;;eAIF;;UAGE,eAAA;;SAER;;;;;;;;;;;AAtBT;AAaA;AAOA;;;;ACEA;;;;;;;;;;;;;;iBAAgB,cAAA,WAAwB,0BAA+B"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["baseTransformMarkdown","oxContent"],"sources":["../src/transform.ts","../src/environment.ts","../src/index.ts"],"sourcesContent":["import * as path from \"path\";\nimport { transformMarkdown as baseTransformMarkdown } from \"@ox-content/vite-plugin\";\nimport type {\n ResolvedReactOptions,\n ReactTransformResult,\n ComponentIsland,\n ComponentsMap,\n} from \"./types\";\n\nconst COMPONENT_REGEX = /<([A-Z][a-zA-Z0-9]*)\\s*([^>]*?)\\s*(?:\\/>|>([\\s\\S]*?)<\\/\\1>)/g;\nconst PROP_REGEX = /([a-zA-Z0-9-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|{([^}]*)}|\\[([^\\]]*)\\]))?/g;\n\nconst ISLAND_MARKER_PREFIX = \"OXCONTENT-ISLAND-\";\nconst ISLAND_MARKER_SUFFIX = \"-PLACEHOLDER\";\n\ninterface Range {\n start: number;\n end: number;\n}\n\nexport async function transformMarkdownWithReact(\n code: string,\n id: string,\n options: ResolvedReactOptions,\n): Promise<ReactTransformResult> {\n const components: ComponentsMap = options.components;\n const usedComponents: string[] = [];\n const islands: ComponentIsland[] = [];\n let islandIndex = 0;\n\n const { content: markdownContent, frontmatter } = extractFrontmatter(code);\n const fenceRanges = collectFenceRanges(markdownContent);\n let processedContent = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n COMPONENT_REGEX.lastIndex = 0;\n while ((match = COMPONENT_REGEX.exec(markdownContent)) !== null) {\n const [fullMatch, componentName, propsString, rawIslandContent] = match;\n const matchStart = match.index;\n const matchEnd = matchStart + fullMatch.length;\n\n if (\n !Object.prototype.hasOwnProperty.call(components, componentName) ||\n isInRanges(matchStart, matchEnd, fenceRanges)\n ) {\n processedContent += markdownContent.slice(lastIndex, matchEnd);\n lastIndex = matchEnd;\n continue;\n }\n\n if (!usedComponents.includes(componentName)) {\n usedComponents.push(componentName);\n }\n\n const props = parseProps(propsString);\n const islandId = `ox-island-${islandIndex++}`;\n const islandContent =\n typeof rawIslandContent === \"string\" ? rawIslandContent.trim() : undefined;\n\n islands.push({\n name: componentName,\n props,\n position: matchStart,\n id: islandId,\n content: islandContent,\n });\n\n processedContent += markdownContent.slice(lastIndex, matchStart) + createIslandMarker(islandId);\n lastIndex = matchEnd;\n }\n processedContent += markdownContent.slice(lastIndex);\n\n const transformed = await baseTransformMarkdown(processedContent, id, {\n srcDir: options.srcDir,\n outDir: options.outDir,\n base: options.base,\n ssg: {\n enabled: false,\n extension: \".html\",\n clean: false,\n bare: false,\n generateOgImage: false,\n },\n gfm: options.gfm,\n frontmatter: false,\n toc: options.toc,\n tocMaxDepth: options.tocMaxDepth,\n footnotes: true,\n tables: true,\n taskLists: true,\n strikethrough: true,\n highlight: false,\n highlightTheme: \"github-dark\",\n highlightLangs: [],\n mermaid: false,\n ogImage: false,\n ogImageOptions: {\n vuePlugin: \"vitejs\",\n width: 1200,\n height: 630,\n cache: true,\n concurrency: 1,\n },\n transformers: [],\n docs: false,\n ogViewer: false,\n search: {\n enabled: false,\n limit: 10,\n prefix: true,\n placeholder: \"Search...\",\n hotkey: \"k\",\n },\n i18n: false,\n });\n\n const htmlWithIslands = injectIslandMarkers(transformed.html, islands);\n const jsxCode = generateReactModule(\n htmlWithIslands,\n usedComponents,\n islands,\n frontmatter,\n options,\n id,\n );\n\n return {\n code: jsxCode,\n map: null,\n usedComponents,\n frontmatter,\n };\n}\n\nfunction createIslandMarker(islandId: string): string {\n return `${ISLAND_MARKER_PREFIX}${islandId}${ISLAND_MARKER_SUFFIX}`;\n}\n\nfunction collectFenceRanges(content: string): Range[] {\n const ranges: Range[] = [];\n let inFence = false;\n let fenceChar = \"\";\n let fenceLength = 0;\n let fenceStart = 0;\n let pos = 0;\n\n while (pos < content.length) {\n const lineEnd = content.indexOf(\"\\n\", pos);\n const next = lineEnd === -1 ? content.length : lineEnd + 1;\n const line = content.slice(pos, lineEnd === -1 ? content.length : lineEnd);\n const fenceMatch = line.match(/^\\s{0,3}([`~]{3,})/);\n\n if (fenceMatch) {\n const marker = fenceMatch[1];\n if (!inFence) {\n inFence = true;\n fenceChar = marker[0];\n fenceLength = marker.length;\n fenceStart = pos;\n } else if (marker[0] === fenceChar && marker.length >= fenceLength) {\n inFence = false;\n ranges.push({ start: fenceStart, end: next });\n fenceChar = \"\";\n fenceLength = 0;\n }\n }\n\n pos = next;\n }\n\n if (inFence) {\n ranges.push({ start: fenceStart, end: content.length });\n }\n\n return ranges;\n}\n\nfunction isInRanges(start: number, end: number, ranges: Range[]): boolean {\n for (const range of ranges) {\n if (start < range.end && end > range.start) {\n return true;\n }\n }\n return false;\n}\n\nfunction injectIslandMarkers(html: string, islands: ComponentIsland[]): string {\n let output = html;\n\n for (const island of islands) {\n const marker = createIslandMarker(island.id);\n const propsAttr =\n Object.keys(island.props).length > 0\n ? ` data-ox-props='${JSON.stringify(island.props).replace(/'/g, \"'\")}'`\n : \"\";\n const contentAttr = island.content\n ? ` data-ox-content='${island.content.replace(/'/g, \"'\")}'`\n : \"\";\n const attrs = `data-ox-island=\"${island.name}\"${propsAttr}${contentAttr}`;\n output = output.replaceAll(`<p>${marker}</p>`, `<div ${attrs}></div>`);\n output = output.replaceAll(marker, `<span ${attrs}></span>`);\n }\n\n return output;\n}\n\nfunction extractFrontmatter(content: string): {\n content: string;\n frontmatter: Record<string, unknown>;\n} {\n const frontmatterRegex = /^---\\n([\\s\\S]*?)\\n---\\n/;\n const match = frontmatterRegex.exec(content);\n\n if (!match) {\n return { content, frontmatter: {} };\n }\n\n const frontmatterStr = match[1];\n const frontmatter: Record<string, unknown> = {};\n\n for (const line of frontmatterStr.split(\"\\n\")) {\n const colonIndex = line.indexOf(\":\");\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim();\n let value: unknown = line.slice(colonIndex + 1).trim();\n try {\n value = JSON.parse(value as string);\n } catch {\n if (\n typeof value === \"string\" &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n }\n frontmatter[key] = value;\n }\n }\n\n return { content: content.slice(match[0].length), frontmatter };\n}\n\nfunction parseProps(propsString: string): Record<string, unknown> {\n const props: Record<string, unknown> = {};\n if (!propsString) return props;\n\n PROP_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = PROP_REGEX.exec(propsString)) !== null) {\n const [, name, doubleQuoted, singleQuoted, braceValue, bracketValue] = match;\n if (name) {\n if (doubleQuoted !== undefined) props[name] = doubleQuoted;\n else if (singleQuoted !== undefined) props[name] = singleQuoted;\n else if (braceValue !== undefined) {\n try {\n props[name] = JSON.parse(braceValue);\n } catch {\n props[name] = braceValue;\n }\n } else if (bracketValue !== undefined) {\n try {\n props[name] = JSON.parse(`[${bracketValue}]`);\n } catch {\n props[name] = bracketValue;\n }\n } else props[name] = true;\n }\n }\n return props;\n}\n\nfunction generateReactModule(\n content: string,\n usedComponents: string[],\n islands: ComponentIsland[],\n frontmatter: Record<string, unknown>,\n options: ResolvedReactOptions & { root?: string },\n id: string,\n): string {\n const mdDir = path.dirname(id);\n const root = options.root || process.cwd();\n\n const imports = usedComponents\n .map((name) => {\n const componentPath = options.components[name];\n if (!componentPath) return \"\";\n const absolutePath = path.resolve(root, componentPath.replace(/^\\.\\//, \"\"));\n const relativePath = path.relative(mdDir, absolutePath).replace(/\\\\/g, \"/\");\n const importPath = relativePath.startsWith(\".\") ? relativePath : \"./\" + relativePath;\n return `import ${name} from '${importPath}';`;\n })\n .filter(Boolean)\n .join(\"\\n\");\n\n const componentMap = usedComponents.map((name) => ` ${name},`).join(\"\\n\");\n\n // If no islands, generate simpler code without island runtime\n if (islands.length === 0) {\n return `\nimport React, { createElement } from 'react';\n\nexport const frontmatter = ${JSON.stringify(frontmatter)};\n\nconst rawHtml = ${JSON.stringify(content)};\n\nexport default function MarkdownContent() {\n return createElement('div', {\n className: 'ox-content',\n dangerouslySetInnerHTML: { __html: rawHtml },\n });\n}\n`;\n }\n\n return `\nimport React, { useEffect, useRef, createElement } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { initIslands } from '@ox-content/islands';\n${imports}\n\nexport const frontmatter = ${JSON.stringify(frontmatter)};\n\nconst rawHtml = ${JSON.stringify(content)};\nconst components = {\n${componentMap}\n};\n\nfunction createReactHydrate() {\n const mountedRoots = [];\n\n return (element, props) => {\n const componentName = element.dataset.oxIsland;\n const Component = components[componentName];\n if (!Component) return;\n\n const islandContent = element.dataset.oxContent || element.innerHTML;\n const vnode = islandContent\n ? createElement(\n Component,\n props,\n createElement('div', { dangerouslySetInnerHTML: { __html: islandContent } })\n )\n : createElement(Component, props);\n\n const root = createRoot(element);\n root.render(vnode);\n mountedRoots.push(root);\n\n return () => root.unmount();\n };\n}\n\nexport default function MarkdownContent() {\n const containerRef = useRef(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n const controller = initIslands(createReactHydrate(), {\n selector: '.ox-content [data-ox-island]',\n });\n return () => controller.destroy();\n }, []);\n\n return createElement('div', {\n className: 'ox-content',\n ref: containerRef,\n dangerouslySetInnerHTML: { __html: rawHtml },\n });\n}\n`;\n}\n","import type { EnvironmentOptions } from \"vite\";\nimport type { ResolvedReactOptions } from \"./types\";\n\nexport function createReactMarkdownEnvironment(\n mode: \"ssr\" | \"client\",\n options: ResolvedReactOptions,\n): EnvironmentOptions {\n const isSSR = mode === \"ssr\";\n\n return {\n build: {\n outDir: isSSR ? `${options.outDir}/.ox-content/ssr` : `${options.outDir}/.ox-content/client`,\n ssr: isSSR,\n rollupOptions: {\n output: {\n format: \"esm\",\n entryFileNames: isSSR ? \"[name].js\" : \"[name].[hash].js\",\n },\n },\n ...(isSSR && { target: \"node18\", minify: false }),\n },\n resolve: {\n conditions: isSSR ? [\"node\", \"import\"] : [\"browser\", \"import\"],\n },\n optimizeDeps: {\n include: isSSR ? [] : [\"react\", \"react-dom\"],\n exclude: [\"@ox-content/vite-plugin\", \"@ox-content/vite-plugin-react\"],\n },\n };\n}\n","/**\n * Vite Plugin for Ox Content React Integration\n *\n * Uses Vite's Environment API to enable embedding React components in Markdown.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { Plugin, PluginOption, ResolvedConfig } from \"vite\";\nimport { oxContent } from \"@ox-content/vite-plugin\";\nimport { transformMarkdownWithReact } from \"./transform\";\nimport { createReactMarkdownEnvironment } from \"./environment\";\nimport type {\n ReactIntegrationOptions,\n ResolvedReactOptions,\n ComponentsMap,\n ComponentsOption,\n} from \"./types\";\n\nexport type {\n ReactIntegrationOptions,\n ResolvedReactOptions,\n ComponentsOption,\n ComponentsMap,\n ReactTransformResult,\n ComponentIsland,\n} from \"./types\";\n\n/**\n * Creates the Ox Content React integration plugin.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import react from '@vitejs/plugin-react';\n * import { oxContentReact } from 'vite-plugin-ox-content-react';\n *\n * export default defineConfig({\n * plugins: [\n * react(),\n * oxContentReact({\n * srcDir: 'docs',\n * components: {\n * Counter: './src/components/Counter.tsx',\n * },\n * }),\n * ],\n * });\n * ```\n */\nexport function oxContentReact(options: ReactIntegrationOptions = {}): PluginOption[] {\n const resolved = resolveReactOptions(options);\n let componentMap = new Map<string, string>();\n let config: ResolvedConfig;\n\n if (typeof options.components === \"object\" && !Array.isArray(options.components)) {\n componentMap = new Map(Object.entries(options.components));\n }\n\n const reactTransformPlugin: Plugin = {\n name: \"ox-content:react-transform\",\n enforce: \"pre\",\n\n async configResolved(resolvedConfig) {\n config = resolvedConfig;\n\n const componentsOption = options.components;\n if (componentsOption) {\n const resolvedComponents = await resolveComponentsGlob(componentsOption, config.root);\n componentMap = new Map(Object.entries(resolvedComponents));\n }\n },\n\n async transform(code, id) {\n if (!id.endsWith(\".md\")) {\n return null;\n }\n\n const result = await transformMarkdownWithReact(code, id, {\n ...resolved,\n components: Object.fromEntries(componentMap),\n root: config.root,\n });\n\n return {\n code: result.code,\n map: result.map,\n };\n },\n };\n\n const reactEnvironmentPlugin: Plugin = {\n name: \"ox-content:react-environment\",\n\n config() {\n const envOptions = {\n ...resolved,\n components: Object.fromEntries(componentMap),\n };\n return {\n environments: {\n oxcontent_ssr: createReactMarkdownEnvironment(\"ssr\", envOptions),\n oxcontent_client: createReactMarkdownEnvironment(\"client\", envOptions),\n },\n };\n },\n\n resolveId(id) {\n if (id === \"virtual:ox-content-react/runtime\") {\n return \"\\0virtual:ox-content-react/runtime\";\n }\n if (id === \"virtual:ox-content-react/components\") {\n return \"\\0virtual:ox-content-react/components\";\n }\n return null;\n },\n\n load(id) {\n if (id === \"\\0virtual:ox-content-react/runtime\") {\n return generateRuntimeModule();\n }\n if (id === \"\\0virtual:ox-content-react/components\") {\n return generateComponentsModule(componentMap);\n }\n return null;\n },\n\n applyToEnvironment(environment) {\n return [\"oxcontent_ssr\", \"oxcontent_client\", \"client\", \"ssr\"].includes(environment.name);\n },\n };\n\n const reactHmrPlugin: Plugin = {\n name: \"ox-content:react-hmr\",\n apply: \"serve\",\n\n handleHotUpdate({ file, server, modules }) {\n const isComponent = Array.from(componentMap.values()).some((path) =>\n file.endsWith(path.replace(/^\\.\\//, \"\")),\n );\n\n if (isComponent) {\n const mdModules = Array.from(server.moduleGraph.idToModuleMap.values()).filter((mod) =>\n mod.file?.endsWith(\".md\"),\n );\n\n if (mdModules.length > 0) {\n server.ws.send({\n type: \"custom\",\n event: \"ox-content:react-update\",\n data: { file },\n });\n return [...modules, ...mdModules];\n }\n }\n\n return modules;\n },\n };\n\n const basePlugins = oxContent(options);\n const environmentPlugin = basePlugins.find((p) => p.name === \"ox-content:environment\");\n\n return [\n reactTransformPlugin,\n reactEnvironmentPlugin,\n reactHmrPlugin,\n ...(environmentPlugin ? [environmentPlugin] : []),\n ];\n}\n\nfunction resolveReactOptions(\n options: ReactIntegrationOptions,\n): Omit<ResolvedReactOptions, \"components\"> {\n return {\n srcDir: options.srcDir ?? \"docs\",\n outDir: options.outDir ?? \"dist\",\n base: options.base ?? \"/\",\n gfm: options.gfm ?? true,\n frontmatter: options.frontmatter ?? true,\n toc: options.toc ?? true,\n tocMaxDepth: options.tocMaxDepth ?? 3,\n jsxRuntime: options.jsxRuntime ?? \"automatic\",\n };\n}\n\nfunction generateRuntimeModule(): string {\n return `\nimport React, { useState, useEffect } from 'react';\n\nexport function OxContentRenderer({ content, components = {} }) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n if (!content) return null;\n\n const { html, frontmatter, islands } = content;\n\n if (!mounted) {\n return React.createElement('div', {\n className: 'ox-content',\n dangerouslySetInnerHTML: { __html: html },\n });\n }\n\n return React.createElement('div', { className: 'ox-content' },\n islands.map((island) => {\n const Component = components[island.name];\n return Component\n ? React.createElement(Component, { key: island.id, ...island.props })\n : null;\n })\n );\n}\n\nexport function useOxContent() {\n return { OxContentRenderer };\n}\n`;\n}\n\nfunction generateComponentsModule(componentMap: Map<string, string>): string {\n const imports: string[] = [];\n const exports: string[] = [];\n\n componentMap.forEach((path, name) => {\n imports.push(`import ${name} from '${path}';`);\n exports.push(` ${name},`);\n });\n\n return `\n${imports.join(\"\\n\")}\n\nexport const components = {\n${exports.join(\"\\n\")}\n};\n\nexport default components;\n`;\n}\n\nasync function resolveComponentsGlob(\n componentsOption: ComponentsOption,\n root: string,\n): Promise<ComponentsMap> {\n if (typeof componentsOption === \"object\" && !Array.isArray(componentsOption)) {\n return componentsOption;\n }\n\n const patterns = Array.isArray(componentsOption) ? componentsOption : [componentsOption];\n\n const result: ComponentsMap = {};\n\n for (const pattern of patterns) {\n const files = await globFiles(pattern, root);\n\n for (const file of files) {\n const baseName = path.basename(file, path.extname(file));\n const componentName = toPascalCase(baseName);\n const relativePath = \"./\" + path.relative(root, file).replace(/\\\\/g, \"/\");\n\n result[componentName] = relativePath;\n }\n }\n\n return result;\n}\n\nasync function globFiles(pattern: string, root: string): Promise<string[]> {\n const files: string[] = [];\n const isGlob = pattern.includes(\"*\");\n\n if (!isGlob) {\n const fullPath = path.resolve(root, pattern);\n if (fs.existsSync(fullPath)) {\n files.push(fullPath);\n }\n return files;\n }\n\n const parts = pattern.split(\"*\");\n const baseDir = path.resolve(root, parts[0]);\n const ext = parts[1] || \"\";\n\n if (!fs.existsSync(baseDir)) {\n return files;\n }\n\n if (pattern.includes(\"**\")) {\n await walkDir(baseDir, files, ext);\n } else {\n const entries = await fs.promises.readdir(baseDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith(ext)) {\n files.push(path.join(baseDir, entry.name));\n }\n }\n }\n\n return files;\n}\n\nasync function walkDir(dir: string, files: string[], ext: string): Promise<void> {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n await walkDir(fullPath, files, ext);\n } else if (entry.isFile() && entry.name.endsWith(ext)) {\n files.push(fullPath);\n }\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str.replace(/[-_](\\w)/g, (_, c) => c.toUpperCase()).replace(/^\\w/, (c) => c.toUpperCase());\n}\n\nexport { oxContent } from \"@ox-content/vite-plugin\";\n"],"mappings":"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"}
|