@ox-content/vite-plugin 2.15.0 → 2.25.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/bin/migrate-vitepress.mjs +27 -0
- package/dist/index.cjs +339 -352
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +22 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +339 -352
- package/dist/index.mjs.map +1 -1
- package/dist/mermaid.cjs +19 -48
- package/dist/mermaid.cjs.map +1 -1
- package/dist/mermaid.mjs +2 -109
- package/dist/mermaid2.mjs +92 -2
- package/dist/mermaid2.mjs.map +1 -0
- package/dist/napi.cjs +45 -0
- package/dist/napi.cjs.map +1 -0
- package/dist/napi.mjs +34 -0
- package/dist/napi.mjs.map +1 -0
- package/dist/ogp.cjs +1 -1
- package/dist/ogp.cjs.map +1 -1
- package/dist/ogp2.mjs +1 -1
- package/dist/ogp2.mjs.map +1 -1
- package/dist/vitepress-cli.cjs +1 -1
- package/dist/vitepress-cli.mjs +1 -1
- package/dist/vitepress.cjs +2 -26
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.mjs +2 -26
- package/dist/vitepress.mjs.map +1 -1
- package/package.json +5 -4
- package/dist/mermaid.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as importNapiModuleSync, t as importNapiModule } from "./napi.mjs";
|
|
2
|
+
import { n as transformMermaidStatic, t as mermaidClientScript } from "./mermaid2.mjs";
|
|
2
3
|
import { n as resetTabGroupCounter, r as transformTabs, t as generateTabsCSS } from "./tabs2.mjs";
|
|
3
4
|
import { n as transformYouTube, t as extractVideoId } from "./youtube2.mjs";
|
|
4
5
|
import { a as fetchRepoData, c as parseGitHubPermalink, d as transformGitHub, i as fetchGitHubSource, l as prefetchGitHubRepos, n as collectGitHubSources, s as parseGitHubLineRange, t as collectGitHubRepos, u as prefetchGitHubSources } from "./github2.mjs";
|
|
@@ -12,9 +13,9 @@ import rehypeStringify from "rehype-stringify";
|
|
|
12
13
|
import { createHighlighter } from "shiki";
|
|
13
14
|
import * as path from "node:path";
|
|
14
15
|
import { dirname, join } from "node:path";
|
|
15
|
-
import * as fs$2 from "fs";
|
|
16
|
-
import * as fs$1 from "fs/promises";
|
|
16
|
+
import * as fs$2 from "fs/promises";
|
|
17
17
|
import * as crypto from "crypto";
|
|
18
|
+
import * as fs$1 from "fs";
|
|
18
19
|
import { glob } from "glob";
|
|
19
20
|
import * as fs from "node:fs/promises";
|
|
20
21
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
@@ -322,7 +323,7 @@ async function transformAllPlugins(html, options = {}) {
|
|
|
322
323
|
result = await transformOgp(result, void 0, typeof ogpOptions === "object" ? ogpOptions : {});
|
|
323
324
|
}
|
|
324
325
|
if (mermaid) {
|
|
325
|
-
const { transformMermaidStatic } = await import("./
|
|
326
|
+
const { transformMermaidStatic } = await import("./mermaid.mjs");
|
|
326
327
|
result = await transformMermaidStatic(result);
|
|
327
328
|
}
|
|
328
329
|
return result;
|
|
@@ -565,67 +566,7 @@ if (import.meta.hot) {
|
|
|
565
566
|
`;
|
|
566
567
|
}
|
|
567
568
|
//#endregion
|
|
568
|
-
//#region src/nav-generator.ts
|
|
569
|
-
function generateNavMetadata(docs, basePath = "/api") {
|
|
570
|
-
return importNapiModuleSync().generateDocsNavMetadata(docs.map((doc) => doc.file), basePath);
|
|
571
|
-
}
|
|
572
|
-
function generateNavCode(navItems, exportName = "apiNav") {
|
|
573
|
-
return importNapiModuleSync().generateDocsNavCode(navItems, exportName);
|
|
574
|
-
}
|
|
575
|
-
//#endregion
|
|
576
569
|
//#region src/docs.ts
|
|
577
|
-
/**
|
|
578
|
-
* Source Documentation Extraction and Generation
|
|
579
|
-
*
|
|
580
|
-
* This module provides comprehensive tools for extracting JSDoc/TSDoc comments
|
|
581
|
-
* from TypeScript/JavaScript source files and automatically generating Markdown
|
|
582
|
-
* documentation.
|
|
583
|
-
*
|
|
584
|
-
* ## Features
|
|
585
|
-
*
|
|
586
|
-
* - **Automatic Extraction**: Parses JSDoc comments from functions, classes, interfaces, and types
|
|
587
|
-
* - **Flexible Filtering**: Include/exclude patterns for selective documentation
|
|
588
|
-
* - **Markdown Generation**: Converts extracted docs to organized Markdown files
|
|
589
|
-
* - **Navigation Generation**: Auto-generates sidebar navigation metadata
|
|
590
|
-
* - **GitHub Links**: Includes clickable links to source code on GitHub
|
|
591
|
-
*
|
|
592
|
-
* ## Supported JSDoc Tags
|
|
593
|
-
*
|
|
594
|
-
* - `@param {type} name - description` - Function parameter documentation
|
|
595
|
-
* - `@returns {type} description` - Return value documentation
|
|
596
|
-
* - `@example` - Code examples (multi-line blocks)
|
|
597
|
-
* - `@private` - Mark item as private (excluded from docs if private=false)
|
|
598
|
-
* - `@default value` - Default parameter value
|
|
599
|
-
* - Custom tags are preserved in the `tags` field
|
|
600
|
-
*
|
|
601
|
-
* ## Usage Flow
|
|
602
|
-
*
|
|
603
|
-
* 1. Call `extractDocs()` to parse source files
|
|
604
|
-
* 2. Call `generateMarkdown()` to create Markdown content
|
|
605
|
-
* 3. Call `writeDocs()` to write files to output directory
|
|
606
|
-
* 4. Generated nav.ts can be imported for sidebar navigation
|
|
607
|
-
*
|
|
608
|
-
* @example
|
|
609
|
-
* ```typescript
|
|
610
|
-
* import { extractDocs, generateMarkdown, writeDocs } from './docs';
|
|
611
|
-
*
|
|
612
|
-
* const docsOptions = {
|
|
613
|
-
* enabled: true,
|
|
614
|
-
* src: ['./src'],
|
|
615
|
-
* out: './docs/api',
|
|
616
|
-
* include: ['**\/*.ts'],
|
|
617
|
-
* exclude: ['**\/*.test.ts'],
|
|
618
|
-
* groupBy: 'file',
|
|
619
|
-
* githubUrl: 'https://github.com/user/project',
|
|
620
|
-
* };
|
|
621
|
-
*
|
|
622
|
-
* const extracted = await extractDocs(['./src'], docsOptions);
|
|
623
|
-
* const markdown = generateMarkdown(extracted, docsOptions);
|
|
624
|
-
* await writeDocs(markdown, './docs/api', extracted, docsOptions);
|
|
625
|
-
* ```
|
|
626
|
-
*/
|
|
627
|
-
const DOCS_MANIFEST_FILE = ".ox-content-docs-manifest.json";
|
|
628
|
-
const DOCS_DATA_FILE = "docs.json";
|
|
629
570
|
const DEFAULT_DOCS_INCLUDE = [
|
|
630
571
|
"**/*.ts",
|
|
631
572
|
"**/*.tsx",
|
|
@@ -715,20 +656,12 @@ async function extractDocs(srcDirs, options) {
|
|
|
715
656
|
entries: doc.entries
|
|
716
657
|
}));
|
|
717
658
|
}
|
|
718
|
-
const
|
|
719
|
-
if (!
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const entries = extractFileDocEntries(file, options.private, options.internal);
|
|
725
|
-
if (entries.length > 0) results.push({
|
|
726
|
-
file,
|
|
727
|
-
entries
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
return results;
|
|
659
|
+
const extractDocsFromDirectories = napi.extractDocsFromDirectories;
|
|
660
|
+
if (!extractDocsFromDirectories) throw new Error("[ox-content] extractDocsFromDirectories is not available from @ox-content/napi.");
|
|
661
|
+
return extractDocsFromDirectories(srcDirs, options.include, options.exclude, options.private, options.internal).map((doc) => ({
|
|
662
|
+
file: doc.file,
|
|
663
|
+
entries: doc.entries
|
|
664
|
+
}));
|
|
732
665
|
}
|
|
733
666
|
/**
|
|
734
667
|
* Generates Markdown documentation from extracted docs.
|
|
@@ -738,42 +671,25 @@ function generateMarkdown(docs, options) {
|
|
|
738
671
|
if (typeof napi.generateDocsMarkdown !== "function") throw new Error("[ox-content] generateDocsMarkdown is not available from @ox-content/napi. Please rebuild the NAPI package.");
|
|
739
672
|
return napi.generateDocsMarkdown(toRustDocsModules(docs), {
|
|
740
673
|
groupBy: options.groupBy,
|
|
741
|
-
githubUrl: options.githubUrl
|
|
674
|
+
githubUrl: options.githubUrl,
|
|
675
|
+
linkStyle: options.linkStyle,
|
|
676
|
+
basePath: options.basePath,
|
|
677
|
+
pathStrategy: options.pathStrategy
|
|
742
678
|
});
|
|
743
679
|
}
|
|
744
680
|
/**
|
|
745
681
|
* Writes generated documentation to the output directory.
|
|
746
682
|
*/
|
|
747
683
|
async function writeDocs(docs, outDir, extractedDocs, options) {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
previousFiles = [];
|
|
758
|
-
}
|
|
759
|
-
for (const staleFile of previousFiles) {
|
|
760
|
-
if (generatedFiles.has(staleFile)) continue;
|
|
761
|
-
await fs$2.promises.rm(path$1.join(outDir, staleFile), { force: true });
|
|
762
|
-
}
|
|
763
|
-
for (const [fileName, content] of Object.entries(docs)) {
|
|
764
|
-
const filePath = path$1.join(outDir, fileName);
|
|
765
|
-
await fs$2.promises.writeFile(filePath, content, "utf-8");
|
|
766
|
-
}
|
|
767
|
-
if (extractedDocs && options?.generateNav && options.groupBy === "file") {
|
|
768
|
-
const navCode = generateNavCode(generateNavMetadata(extractedDocs, "/api"), "apiNav");
|
|
769
|
-
const navFilePath = path$1.join(outDir, "nav.ts");
|
|
770
|
-
await fs$2.promises.writeFile(navFilePath, navCode, "utf-8");
|
|
771
|
-
}
|
|
772
|
-
if (extractedDocs) {
|
|
773
|
-
const napi = importNapiModuleSync();
|
|
774
|
-
await fs$2.promises.writeFile(path$1.join(outDir, DOCS_DATA_FILE), napi.generateDocsDataJson(toRustDocsModules(extractedDocs), (/* @__PURE__ */ new Date()).toISOString()), "utf-8");
|
|
775
|
-
}
|
|
776
|
-
await fs$2.promises.writeFile(manifestPath, JSON.stringify([...generatedFiles].sort(), null, 2), "utf-8");
|
|
684
|
+
const napi = importNapiModuleSync();
|
|
685
|
+
if (typeof napi.writeGeneratedDocs !== "function") throw new Error("[ox-content] writeGeneratedDocs is not available from @ox-content/napi. Please rebuild the NAPI package.");
|
|
686
|
+
napi.writeGeneratedDocs(docs, outDir, extractedDocs ? toRustDocsModules(extractedDocs) : void 0, {
|
|
687
|
+
generateNav: options?.generateNav ?? false,
|
|
688
|
+
groupBy: options?.groupBy ?? "file",
|
|
689
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
690
|
+
basePath: options?.basePath,
|
|
691
|
+
pathStrategy: options?.pathStrategy
|
|
692
|
+
});
|
|
777
693
|
}
|
|
778
694
|
function toRustDocsModules(docs) {
|
|
779
695
|
return docs.map((doc) => ({
|
|
@@ -798,9 +714,6 @@ function toRustDocsModules(docs) {
|
|
|
798
714
|
}))
|
|
799
715
|
}));
|
|
800
716
|
}
|
|
801
|
-
/**
|
|
802
|
-
* Resolves docs options with defaults.
|
|
803
|
-
*/
|
|
804
717
|
function resolveDocsOptions(options) {
|
|
805
718
|
if (options === false) return false;
|
|
806
719
|
const opts = options || {};
|
|
@@ -821,6 +734,9 @@ function resolveDocsOptions(options) {
|
|
|
821
734
|
toc: false,
|
|
822
735
|
groupBy: opts.groupBy ?? "file",
|
|
823
736
|
githubUrl: opts.githubUrl,
|
|
737
|
+
linkStyle: opts.linkStyle ?? "markdown",
|
|
738
|
+
basePath: opts.basePath,
|
|
739
|
+
pathStrategy: opts.pathStrategy ?? "flat",
|
|
824
740
|
generateNav: opts.generateNav ?? true
|
|
825
741
|
};
|
|
826
742
|
}
|
|
@@ -908,6 +824,8 @@ async function renderHtmlToPng(page, html, width, height, publicDir) {
|
|
|
908
824
|
}
|
|
909
825
|
//#endregion
|
|
910
826
|
//#region src/og-image/browser.ts
|
|
827
|
+
const PLAYWRIGHT_BROWSER_INSTALL_HINT = "Install Playwright browsers with `npx playwright install chromium` to enable OG image generation.";
|
|
828
|
+
let chromiumUnavailableWarned = false;
|
|
911
829
|
/**
|
|
912
830
|
* Opens a Chromium browser and returns a session for rendering OG images.
|
|
913
831
|
* Returns null if Playwright/Chromium is not available.
|
|
@@ -947,10 +865,20 @@ async function openBrowser() {
|
|
|
947
865
|
}
|
|
948
866
|
};
|
|
949
867
|
} catch (err) {
|
|
950
|
-
|
|
868
|
+
warnChromiumUnavailableOnce(err);
|
|
951
869
|
return null;
|
|
952
870
|
}
|
|
953
871
|
}
|
|
872
|
+
function warnChromiumUnavailableOnce(err) {
|
|
873
|
+
if (chromiumUnavailableWarned) return;
|
|
874
|
+
chromiumUnavailableWarned = true;
|
|
875
|
+
console.warn(`[ox-content:og-image] Chromium not available, skipping OG image generation. ${formatChromiumUnavailableDetail(err)}`);
|
|
876
|
+
}
|
|
877
|
+
function formatChromiumUnavailableDetail(err) {
|
|
878
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
879
|
+
if (message.includes("Executable doesn't exist") || message.includes("Please run the following command to download new browsers")) return PLAYWRIGHT_BROWSER_INSTALL_HINT;
|
|
880
|
+
return message.split(/\r?\n/).find((line) => line.trim())?.trim() ?? "Unknown launch error.";
|
|
881
|
+
}
|
|
954
882
|
//#endregion
|
|
955
883
|
//#region src/og-image/template.ts
|
|
956
884
|
/**
|
|
@@ -1058,7 +986,7 @@ function computeCacheKey(templateSource, props, width, height) {
|
|
|
1058
986
|
async function getCached(cacheDir, key) {
|
|
1059
987
|
const filePath = path$1.join(cacheDir, `${key}.png`);
|
|
1060
988
|
try {
|
|
1061
|
-
return await fs$
|
|
989
|
+
return await fs$2.readFile(filePath);
|
|
1062
990
|
} catch {
|
|
1063
991
|
return null;
|
|
1064
992
|
}
|
|
@@ -1067,9 +995,9 @@ async function getCached(cacheDir, key) {
|
|
|
1067
995
|
* Writes a PNG buffer to the cache.
|
|
1068
996
|
*/
|
|
1069
997
|
async function writeCache(cacheDir, key, png) {
|
|
1070
|
-
await fs$
|
|
998
|
+
await fs$2.mkdir(cacheDir, { recursive: true });
|
|
1071
999
|
const filePath = path$1.join(cacheDir, `${key}.png`);
|
|
1072
|
-
await fs$
|
|
1000
|
+
await fs$2.writeFile(filePath, png);
|
|
1073
1001
|
}
|
|
1074
1002
|
//#endregion
|
|
1075
1003
|
//#region \0@oxc-project+runtime@0.129.0/helpers/usingCtx.js
|
|
@@ -1840,8 +1768,8 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
|
|
|
1840
1768
|
async function externalizeSharedPageAssets(pages, outDir, base) {
|
|
1841
1769
|
const optimized = (await importNapiModule()).externalizeSsgAssets(pages, outDir, base);
|
|
1842
1770
|
await Promise.all(optimized.assets.map(async (asset) => {
|
|
1843
|
-
await fs$
|
|
1844
|
-
await fs$
|
|
1771
|
+
await fs$2.mkdir(path$1.dirname(asset.outputPath), { recursive: true });
|
|
1772
|
+
await fs$2.writeFile(asset.outputPath, asset.content, "utf-8");
|
|
1845
1773
|
}));
|
|
1846
1774
|
return {
|
|
1847
1775
|
pages: optimized.pages,
|
|
@@ -1903,149 +1831,201 @@ async function buildSsg(options, root) {
|
|
|
1903
1831
|
};
|
|
1904
1832
|
const srcDir = path$1.resolve(root, options.srcDir);
|
|
1905
1833
|
const outDir = path$1.resolve(root, options.outDir);
|
|
1906
|
-
const base = options.base.endsWith("/") ? options.base : options.base + "/";
|
|
1907
1834
|
const generatedFiles = [];
|
|
1908
|
-
const generatedPages = [];
|
|
1909
1835
|
const errors = [];
|
|
1910
|
-
|
|
1911
|
-
|
|
1836
|
+
await cleanOutputDirectory(ssgOptions, outDir);
|
|
1837
|
+
const markdownFiles = await collectMarkdownFiles(srcDir, options.extensions);
|
|
1838
|
+
const context = await createBuildSsgContext(options, root, srcDir, outDir, markdownFiles);
|
|
1839
|
+
const collected = await collectPageResults(context, markdownFiles);
|
|
1840
|
+
errors.push(...collected.errors);
|
|
1841
|
+
await generateOgImageAssets(context, collected, generatedFiles, errors);
|
|
1842
|
+
await writeGeneratedPages(await generateHtmlPages(context, collected.pageResults, collected, errors), context, generatedFiles);
|
|
1843
|
+
return {
|
|
1844
|
+
files: generatedFiles,
|
|
1845
|
+
errors
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
async function cleanOutputDirectory(ssgOptions, outDir) {
|
|
1849
|
+
if (!ssgOptions.clean) return;
|
|
1850
|
+
try {
|
|
1851
|
+
await fs$2.rm(outDir, {
|
|
1912
1852
|
recursive: true,
|
|
1913
1853
|
force: true
|
|
1914
1854
|
});
|
|
1915
1855
|
} catch {}
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1856
|
+
}
|
|
1857
|
+
async function createBuildSsgContext(options, root, srcDir, outDir, markdownFiles) {
|
|
1858
|
+
const ssgOptions = options.ssg;
|
|
1859
|
+
const base = options.base.endsWith("/") ? options.base : options.base + "/";
|
|
1860
|
+
return {
|
|
1861
|
+
options,
|
|
1862
|
+
ssgOptions,
|
|
1863
|
+
root,
|
|
1864
|
+
srcDir,
|
|
1865
|
+
outDir,
|
|
1866
|
+
base,
|
|
1867
|
+
navItems: resolveNavigationGroups(ssgOptions.navigation, base, ssgOptions.extension) ?? (ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension)),
|
|
1868
|
+
siteName: await resolveSiteName$1(root, ssgOptions),
|
|
1869
|
+
shouldGenerateOgImages: (options.ogImage || ssgOptions.generateOgImage) && !ssgOptions.bare,
|
|
1870
|
+
napi: ssgOptions.lastUpdated ? await importNapiModule() : void 0
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
async function resolveSiteName$1(root, ssgOptions) {
|
|
1874
|
+
if (ssgOptions.siteName) return ssgOptions.siteName;
|
|
1875
|
+
try {
|
|
1920
1876
|
const pkgPath = path$1.join(root, "package.json");
|
|
1921
|
-
const pkg = JSON.parse(await fs$
|
|
1922
|
-
|
|
1923
|
-
} catch {
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
const
|
|
1929
|
-
|
|
1877
|
+
const pkg = JSON.parse(await fs$2.readFile(pkgPath, "utf-8"));
|
|
1878
|
+
return pkg.name ? formatTitle(pkg.name) : "Documentation";
|
|
1879
|
+
} catch {
|
|
1880
|
+
return "Documentation";
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
async function collectPageResults(context, markdownFiles) {
|
|
1884
|
+
const collected = {
|
|
1885
|
+
pageResults: [],
|
|
1886
|
+
ogImageEntries: [],
|
|
1887
|
+
ogImageInputPaths: [],
|
|
1888
|
+
ogImageUrlMap: /* @__PURE__ */ new Map(),
|
|
1889
|
+
errors: []
|
|
1890
|
+
};
|
|
1930
1891
|
for (const inputPath of markdownFiles) try {
|
|
1931
|
-
const
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
sourcePath: inputPath
|
|
1935
|
-
});
|
|
1936
|
-
const frontmatter = normalizeVitePressFrontmatter(result.frontmatter);
|
|
1937
|
-
let transformedHtml = result.html;
|
|
1938
|
-
const { html: protectedHtml, svgs: mermaidSvgs } = protectMermaidSvgs(transformedHtml);
|
|
1939
|
-
transformedHtml = protectedHtml;
|
|
1940
|
-
const pluginOptions = {
|
|
1941
|
-
tabs: true,
|
|
1942
|
-
youtube: true,
|
|
1943
|
-
github: options.embeds.github,
|
|
1944
|
-
openGraph: options.embeds.openGraph,
|
|
1945
|
-
mermaid: true,
|
|
1946
|
-
githubToken: process.env.GITHUB_TOKEN
|
|
1947
|
-
};
|
|
1948
|
-
transformedHtml = await transformAllPlugins(transformedHtml, pluginOptions);
|
|
1949
|
-
if (hasIslands(transformedHtml)) transformedHtml = (await transformIslands(transformedHtml)).html;
|
|
1950
|
-
transformedHtml = restoreMermaidSvgs(transformedHtml, mermaidSvgs);
|
|
1951
|
-
const title = extractTitle$1(transformedHtml, frontmatter);
|
|
1952
|
-
const description = frontmatter.description;
|
|
1953
|
-
const routePaths = getRoutePaths(inputPath, srcDir, outDir, base, ssgOptions.extension, ssgOptions.siteUrl);
|
|
1954
|
-
pageResults.push({
|
|
1955
|
-
inputPath,
|
|
1956
|
-
routePaths,
|
|
1957
|
-
transformedHtml,
|
|
1958
|
-
title,
|
|
1959
|
-
description,
|
|
1960
|
-
lastUpdated: napi?.getGitLastUpdated(inputPath, root) ?? void 0,
|
|
1961
|
-
frontmatter,
|
|
1962
|
-
toc: result.toc
|
|
1963
|
-
});
|
|
1964
|
-
if (shouldGenerateOgImages) {
|
|
1965
|
-
const { layout: _layout, ...frontmatterRest } = frontmatter;
|
|
1966
|
-
ogImageEntries.push({
|
|
1967
|
-
props: {
|
|
1968
|
-
...frontmatterRest,
|
|
1969
|
-
title,
|
|
1970
|
-
description,
|
|
1971
|
-
siteName
|
|
1972
|
-
},
|
|
1973
|
-
outputPath: routePaths.ogImagePath
|
|
1974
|
-
});
|
|
1975
|
-
ogImageInputPaths.push(inputPath);
|
|
1976
|
-
ogImageUrlMap.set(inputPath, routePaths.ogImageUrl);
|
|
1977
|
-
}
|
|
1892
|
+
const pageResult = await transformSsgPage(context, inputPath);
|
|
1893
|
+
collected.pageResults.push(pageResult);
|
|
1894
|
+
collectOgImageEntry(context, pageResult, collected);
|
|
1978
1895
|
} catch (err) {
|
|
1979
1896
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1980
|
-
errors.push(`Failed to process ${inputPath}: ${errorMessage}`);
|
|
1897
|
+
collected.errors.push(`Failed to process ${inputPath}: ${errorMessage}`);
|
|
1981
1898
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1899
|
+
return collected;
|
|
1900
|
+
}
|
|
1901
|
+
async function transformSsgPage(context, inputPath) {
|
|
1902
|
+
const result = await transformMarkdown(await fs$2.readFile(inputPath, "utf-8"), inputPath, context.options, {
|
|
1903
|
+
convertMdLinks: true,
|
|
1904
|
+
baseUrl: context.base,
|
|
1905
|
+
sourcePath: inputPath
|
|
1906
|
+
});
|
|
1907
|
+
const frontmatter = normalizeVitePressFrontmatter(result.frontmatter);
|
|
1908
|
+
const transformedHtml = await transformSsgHtml(result.html, context.options);
|
|
1909
|
+
const title = extractTitle$1(transformedHtml, frontmatter);
|
|
1910
|
+
return {
|
|
1911
|
+
inputPath,
|
|
1912
|
+
routePaths: getRoutePaths(inputPath, context.srcDir, context.outDir, context.base, context.ssgOptions.extension, context.ssgOptions.siteUrl),
|
|
1913
|
+
transformedHtml,
|
|
1914
|
+
title,
|
|
1915
|
+
description: frontmatter.description,
|
|
1916
|
+
lastUpdated: context.napi?.getGitLastUpdated(inputPath, context.root) ?? void 0,
|
|
1917
|
+
frontmatter,
|
|
1918
|
+
toc: result.toc
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
async function transformSsgHtml(html, options) {
|
|
1922
|
+
const { html: protectedHtml, svgs: mermaidSvgs } = protectMermaidSvgs(html);
|
|
1923
|
+
let transformedHtml = await transformAllPlugins(protectedHtml, {
|
|
1924
|
+
tabs: true,
|
|
1925
|
+
youtube: true,
|
|
1926
|
+
github: options.embeds.github,
|
|
1927
|
+
openGraph: options.embeds.openGraph,
|
|
1928
|
+
mermaid: true,
|
|
1929
|
+
githubToken: process.env.GITHUB_TOKEN
|
|
1930
|
+
});
|
|
1931
|
+
if (hasIslands(transformedHtml)) transformedHtml = (await transformIslands(transformedHtml)).html;
|
|
1932
|
+
return restoreMermaidSvgs(transformedHtml, mermaidSvgs);
|
|
1933
|
+
}
|
|
1934
|
+
function collectOgImageEntry(context, pageResult, collected) {
|
|
1935
|
+
if (!context.shouldGenerateOgImages) return;
|
|
1936
|
+
const { layout: _layout, ...frontmatterRest } = pageResult.frontmatter;
|
|
1937
|
+
collected.ogImageEntries.push({
|
|
1938
|
+
props: {
|
|
1939
|
+
...frontmatterRest,
|
|
1940
|
+
title: pageResult.title,
|
|
1941
|
+
description: pageResult.description,
|
|
1942
|
+
siteName: context.siteName
|
|
1943
|
+
},
|
|
1944
|
+
outputPath: pageResult.routePaths.ogImagePath
|
|
1945
|
+
});
|
|
1946
|
+
collected.ogImageInputPaths.push(pageResult.inputPath);
|
|
1947
|
+
collected.ogImageUrlMap.set(pageResult.inputPath, pageResult.routePaths.ogImageUrl);
|
|
1948
|
+
}
|
|
1949
|
+
async function generateOgImageAssets(context, collected, generatedFiles, errors) {
|
|
1950
|
+
if (!context.shouldGenerateOgImages || collected.ogImageEntries.length === 0) return;
|
|
1951
|
+
try {
|
|
1952
|
+
const ogResults = await generateOgImages(collected.ogImageEntries, context.options.ogImageOptions, context.root);
|
|
1953
|
+
if (clearMissingBrowserOgImages(ogResults, collected)) return;
|
|
1954
|
+
reportOgImageResults(ogResults, collected, generatedFiles, errors);
|
|
1999
1955
|
} catch (err) {
|
|
2000
1956
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
2001
1957
|
console.warn(`[ox-content:og-image] Batch generation failed: ${errorMessage}`);
|
|
2002
|
-
ogImageUrlMap.clear();
|
|
1958
|
+
collected.ogImageUrlMap.clear();
|
|
2003
1959
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
if (
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
toc,
|
|
2021
|
-
lastUpdated,
|
|
2022
|
-
frontmatter,
|
|
2023
|
-
path: routePaths.urlPath,
|
|
2024
|
-
href: routePaths.href,
|
|
2025
|
-
entryPage
|
|
2026
|
-
};
|
|
2027
|
-
html = await generateHtmlPage(pageData, navItems, siteName, base, pageOgImage, ssgOptions.theme, getPageLocale(pageData.path, options.i18n), options.i18n ? options.i18n.locales : void 0);
|
|
1960
|
+
}
|
|
1961
|
+
function clearMissingBrowserOgImages(ogResults, collected) {
|
|
1962
|
+
if (!(ogResults.length > 0 && ogResults.every((result) => result.error === "Chromium not available"))) return false;
|
|
1963
|
+
for (const inputPath of collected.ogImageInputPaths) collected.ogImageUrlMap.delete(inputPath);
|
|
1964
|
+
return true;
|
|
1965
|
+
}
|
|
1966
|
+
function reportOgImageResults(ogResults, collected, generatedFiles, errors) {
|
|
1967
|
+
let ogSuccessCount = 0;
|
|
1968
|
+
for (let i = 0; i < ogResults.length; i++) {
|
|
1969
|
+
const result = ogResults[i];
|
|
1970
|
+
if (result.error) {
|
|
1971
|
+
errors.push(`OG image failed for ${result.outputPath}: ${result.error}`);
|
|
1972
|
+
collected.ogImageUrlMap.delete(collected.ogImageInputPaths[i]);
|
|
1973
|
+
} else {
|
|
1974
|
+
generatedFiles.push(result.outputPath);
|
|
1975
|
+
ogSuccessCount++;
|
|
2028
1976
|
}
|
|
1977
|
+
}
|
|
1978
|
+
if (ogSuccessCount > 0) {
|
|
1979
|
+
const cachedCount = ogResults.filter((result) => result.cached && !result.error).length;
|
|
1980
|
+
console.log(`[ox-content:og-image] Generated ${ogSuccessCount} OG images` + (cachedCount > 0 ? ` (${cachedCount} from cache)` : ""));
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
async function generateHtmlPages(context, pageResults, collected, errors) {
|
|
1984
|
+
const generatedPages = [];
|
|
1985
|
+
for (const pageResult of pageResults) try {
|
|
2029
1986
|
generatedPages.push({
|
|
2030
|
-
inputPath,
|
|
2031
|
-
outputPath: routePaths.outputPath,
|
|
2032
|
-
html
|
|
1987
|
+
inputPath: pageResult.inputPath,
|
|
1988
|
+
outputPath: pageResult.routePaths.outputPath,
|
|
1989
|
+
html: await renderSsgPage(context, pageResult, collected.ogImageUrlMap)
|
|
2033
1990
|
});
|
|
2034
1991
|
} catch (err) {
|
|
2035
1992
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
2036
1993
|
errors.push(`Failed to generate HTML for ${pageResult.inputPath}: ${errorMessage}`);
|
|
2037
1994
|
}
|
|
2038
|
-
|
|
1995
|
+
return generatedPages;
|
|
1996
|
+
}
|
|
1997
|
+
async function renderSsgPage(context, pageResult, ogImageUrlMap) {
|
|
1998
|
+
if (context.ssgOptions.bare) return generateBareHtmlPage(pageResult.transformedHtml, pageResult.title);
|
|
1999
|
+
const pageData = createSsgPageData(pageResult);
|
|
2000
|
+
const pageOgImage = context.shouldGenerateOgImages && ogImageUrlMap.has(pageResult.inputPath) ? ogImageUrlMap.get(pageResult.inputPath) : context.ssgOptions.ogImage;
|
|
2001
|
+
return generateHtmlPage(pageData, context.navItems, context.siteName, context.base, pageOgImage, context.ssgOptions.theme, getPageLocale(pageData.path, context.options.i18n), context.options.i18n ? context.options.i18n.locales : void 0);
|
|
2002
|
+
}
|
|
2003
|
+
function createSsgPageData(pageResult) {
|
|
2004
|
+
const { frontmatter } = pageResult;
|
|
2005
|
+
const entryPage = frontmatter.layout === "entry" ? {
|
|
2006
|
+
hero: frontmatter.hero,
|
|
2007
|
+
features: frontmatter.features
|
|
2008
|
+
} : void 0;
|
|
2009
|
+
return {
|
|
2010
|
+
title: pageResult.title,
|
|
2011
|
+
description: pageResult.description,
|
|
2012
|
+
content: pageResult.transformedHtml,
|
|
2013
|
+
toc: pageResult.toc,
|
|
2014
|
+
lastUpdated: pageResult.lastUpdated,
|
|
2015
|
+
frontmatter,
|
|
2016
|
+
path: pageResult.routePaths.urlPath,
|
|
2017
|
+
href: pageResult.routePaths.href,
|
|
2018
|
+
entryPage
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
async function writeGeneratedPages(generatedPages, context, generatedFiles) {
|
|
2022
|
+
const optimizedOutput = await externalizeSharedPageAssets(generatedPages, context.outDir, context.base);
|
|
2039
2023
|
generatedFiles.push(...optimizedOutput.assets);
|
|
2040
2024
|
for (const page of optimizedOutput.pages) {
|
|
2041
|
-
await fs$
|
|
2042
|
-
await fs$
|
|
2025
|
+
await fs$2.mkdir(path$1.dirname(page.outputPath), { recursive: true });
|
|
2026
|
+
await fs$2.writeFile(page.outputPath, page.html, "utf-8");
|
|
2043
2027
|
generatedFiles.push(page.outputPath);
|
|
2044
2028
|
}
|
|
2045
|
-
return {
|
|
2046
|
-
files: generatedFiles,
|
|
2047
|
-
errors
|
|
2048
|
-
};
|
|
2049
2029
|
}
|
|
2050
2030
|
//#endregion
|
|
2051
2031
|
//#region src/search.ts
|
|
@@ -2179,14 +2159,14 @@ async function resolveMarkdownFile(url, srcDir, extensions) {
|
|
|
2179
2159
|
for (const relativePath of directCandidates) {
|
|
2180
2160
|
const filePath = path$1.join(srcDir, relativePath);
|
|
2181
2161
|
try {
|
|
2182
|
-
await fs$
|
|
2162
|
+
await fs$2.access(filePath);
|
|
2183
2163
|
return filePath;
|
|
2184
2164
|
} catch {}
|
|
2185
2165
|
}
|
|
2186
2166
|
for (const extension of extensions) {
|
|
2187
2167
|
const indexPath = path$1.join(srcDir, routePath, `index${extension}`);
|
|
2188
2168
|
try {
|
|
2189
|
-
await fs$
|
|
2169
|
+
await fs$2.access(indexPath);
|
|
2190
2170
|
return indexPath;
|
|
2191
2171
|
} catch {}
|
|
2192
2172
|
}
|
|
@@ -2228,7 +2208,7 @@ async function resolveSiteName(options, root) {
|
|
|
2228
2208
|
if (options.ssg.siteName) return options.ssg.siteName;
|
|
2229
2209
|
try {
|
|
2230
2210
|
const pkgPath = path$1.join(root, "package.json");
|
|
2231
|
-
const pkg = JSON.parse(await fs$
|
|
2211
|
+
const pkg = JSON.parse(await fs$2.readFile(pkgPath, "utf-8"));
|
|
2232
2212
|
if (pkg.name) return formatTitle(pkg.name);
|
|
2233
2213
|
} catch {}
|
|
2234
2214
|
return "Documentation";
|
|
@@ -2240,7 +2220,7 @@ async function renderPage$1(filePath, options, navGroups, siteName, base, root)
|
|
|
2240
2220
|
const srcDir = path$1.resolve(root, options.srcDir);
|
|
2241
2221
|
resetTabGroupCounter();
|
|
2242
2222
|
resetIslandCounter();
|
|
2243
|
-
const result = await transformMarkdown(await fs$
|
|
2223
|
+
const result = await transformMarkdown(await fs$2.readFile(filePath, "utf-8"), filePath, options, {
|
|
2244
2224
|
convertMdLinks: true,
|
|
2245
2225
|
baseUrl: base,
|
|
2246
2226
|
sourcePath: filePath
|
|
@@ -2396,7 +2376,7 @@ async function collectPages(options, root) {
|
|
|
2396
2376
|
const pages = [];
|
|
2397
2377
|
const generateOgImage = options.ogImage || options.ssg.generateOgImage;
|
|
2398
2378
|
for (const file of files.sort()) {
|
|
2399
|
-
const content = fs$
|
|
2379
|
+
const content = fs$1.readFileSync(file, "utf-8");
|
|
2400
2380
|
const frontmatter = normalizeVitePressFrontmatter(parseFrontmatter(content));
|
|
2401
2381
|
if (frontmatter.layout === "entry") continue;
|
|
2402
2382
|
const title = extractTitle(content, frontmatter);
|
|
@@ -2720,7 +2700,7 @@ function createI18nPlugin(resolvedOptions) {
|
|
|
2720
2700
|
async buildStart() {
|
|
2721
2701
|
if (!i18nOptions || !i18nOptions.check) return;
|
|
2722
2702
|
const dictDir = path$1.resolve(root, i18nOptions.dir);
|
|
2723
|
-
if (!fs$
|
|
2703
|
+
if (!fs$1.existsSync(dictDir)) {
|
|
2724
2704
|
console.warn(`[ox-content:i18n] Dictionary directory not found: ${dictDir}`);
|
|
2725
2705
|
return;
|
|
2726
2706
|
}
|
|
@@ -2736,7 +2716,7 @@ function createI18nPlugin(resolvedOptions) {
|
|
|
2736
2716
|
configureServer(server) {
|
|
2737
2717
|
if (!i18nOptions) return;
|
|
2738
2718
|
const dictDir = path$1.resolve(root, i18nOptions.dir);
|
|
2739
|
-
if (fs$
|
|
2719
|
+
if (fs$1.existsSync(dictDir)) {
|
|
2740
2720
|
server.watcher.add(dictDir);
|
|
2741
2721
|
server.watcher.on("change", (filePath) => {
|
|
2742
2722
|
if (!filePath.startsWith(dictDir)) return;
|
|
@@ -2879,7 +2859,10 @@ function stripMaskedDocument(result) {
|
|
|
2879
2859
|
};
|
|
2880
2860
|
}
|
|
2881
2861
|
function normalizeLintOptions(options) {
|
|
2882
|
-
const
|
|
2862
|
+
const standardDictionary = options.dictionary?.standard && typeof options.dictionary.standard === "object" ? options.dictionary.standard : void 0;
|
|
2863
|
+
const optionLanguages = options.languages?.filter((language) => SUPPORTED_MARKDOWN_LINT_LANGUAGES.includes(language));
|
|
2864
|
+
const standardLanguages = standardDictionary?.languages?.filter((language) => SUPPORTED_MARKDOWN_LINT_LANGUAGES.includes(language));
|
|
2865
|
+
const languages = optionLanguages ?? standardLanguages ?? [...DEFAULT_LANGUAGES];
|
|
2883
2866
|
const standard = normalizeStandardDictionaryOptions(options.dictionary?.standard, languages);
|
|
2884
2867
|
return {
|
|
2885
2868
|
dictionary: {
|
|
@@ -2920,6 +2903,12 @@ async function runStandardSpellcheckDocuments(maskedDocuments, options) {
|
|
|
2920
2903
|
const { spellCheckDocument } = await loadCspellLib();
|
|
2921
2904
|
const locale = standard.languages.join(",");
|
|
2922
2905
|
const settings = createStandardSpellcheckSettings(options, locale);
|
|
2906
|
+
const spellCheckOptions = {
|
|
2907
|
+
generateSuggestions: true,
|
|
2908
|
+
noConfigSearch: true,
|
|
2909
|
+
numSuggestions: 3,
|
|
2910
|
+
resolveImportsRelativeTo: standard.resolveImportsRelativeTo
|
|
2911
|
+
};
|
|
2923
2912
|
return Promise.all(maskedDocuments.map(async (maskedDocument, index) => {
|
|
2924
2913
|
if (maskedDocument.trim().length === 0) return [];
|
|
2925
2914
|
return (await spellCheckDocument({
|
|
@@ -2927,12 +2916,7 @@ async function runStandardSpellcheckDocuments(maskedDocuments, options) {
|
|
|
2927
2916
|
locale,
|
|
2928
2917
|
text: maskedDocument,
|
|
2929
2918
|
uri: `file:///ox-content-lint-${index}.md`
|
|
2930
|
-
},
|
|
2931
|
-
generateSuggestions: true,
|
|
2932
|
-
noConfigSearch: true,
|
|
2933
|
-
numSuggestions: 3,
|
|
2934
|
-
resolveImportsRelativeTo: standard.resolveImportsRelativeTo
|
|
2935
|
-
}, settings)).issues.map((issue) => mapStandardIssueToDiagnostic(issue, standard.languages));
|
|
2919
|
+
}, spellCheckOptions, settings)).issues.map((issue) => mapStandardIssueToDiagnostic(issue, standard.languages, maskedDocument));
|
|
2936
2920
|
}));
|
|
2937
2921
|
} catch (error) {
|
|
2938
2922
|
const imports = standard.imports.join(", ");
|
|
@@ -2953,8 +2937,8 @@ async function loadCspellLib() {
|
|
|
2953
2937
|
cspellLibPromise ??= import("cspell-lib");
|
|
2954
2938
|
return cspellLibPromise;
|
|
2955
2939
|
}
|
|
2956
|
-
function mapStandardIssueToDiagnostic(issue, languages) {
|
|
2957
|
-
const line = issue.line.
|
|
2940
|
+
function mapStandardIssueToDiagnostic(issue, languages, documentText) {
|
|
2941
|
+
const line = getLineNumberAtOffset(documentText, issue.line.offset);
|
|
2958
2942
|
const column = issue.offset - issue.line.offset + 1;
|
|
2959
2943
|
return {
|
|
2960
2944
|
column,
|
|
@@ -2968,6 +2952,11 @@ function mapStandardIssueToDiagnostic(issue, languages) {
|
|
|
2968
2952
|
suggestions: issue.suggestions?.slice(0, 3)
|
|
2969
2953
|
};
|
|
2970
2954
|
}
|
|
2955
|
+
function getLineNumberAtOffset(text, offset) {
|
|
2956
|
+
let line = 1;
|
|
2957
|
+
for (let index = 0; index < offset && index < text.length; index++) if (text.charCodeAt(index) === 10) line++;
|
|
2958
|
+
return line;
|
|
2959
|
+
}
|
|
2971
2960
|
function inferStandardIssueLanguage(word, languages) {
|
|
2972
2961
|
if (/[\p{Script=Hiragana}\p{Script=Katakana}]/u.test(word) && languages.includes("ja")) return "ja";
|
|
2973
2962
|
if (/[\p{Script=Han}]/u.test(word)) {
|
|
@@ -3704,21 +3693,35 @@ init_page_context();
|
|
|
3704
3693
|
function oxContent(options = {}) {
|
|
3705
3694
|
const resolvedOptions = resolveOptions(options);
|
|
3706
3695
|
let config;
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
const outDir = path$1.resolve(root, docsOptions.out);
|
|
3712
|
-
const extracted = await extractDocs(srcDirs, docsOptions);
|
|
3713
|
-
const generated = generateMarkdown(extracted, docsOptions);
|
|
3714
|
-
await writeDocs(generated, outDir, extracted, docsOptions);
|
|
3715
|
-
return Object.keys(generated).length;
|
|
3716
|
-
}
|
|
3717
|
-
const mainPlugin = {
|
|
3718
|
-
name: "ox-content",
|
|
3719
|
-
configResolved(resolvedConfig) {
|
|
3696
|
+
const getRoot = () => config?.root || process.cwd();
|
|
3697
|
+
const ssgDevCache = createDevServerCache();
|
|
3698
|
+
const plugins = [
|
|
3699
|
+
createMainPlugin(resolvedOptions, (resolvedConfig) => {
|
|
3720
3700
|
config = resolvedConfig;
|
|
3721
|
-
},
|
|
3701
|
+
}),
|
|
3702
|
+
createEnvironmentPlugin(resolvedOptions),
|
|
3703
|
+
createDocsPlugin(resolvedOptions, getRoot),
|
|
3704
|
+
createSsgPlugin(resolvedOptions, getRoot, ssgDevCache),
|
|
3705
|
+
createSearchPlugin(resolvedOptions, getRoot)
|
|
3706
|
+
];
|
|
3707
|
+
if (resolvedOptions.i18n) plugins.push(createI18nPlugin(resolvedOptions));
|
|
3708
|
+
if (resolvedOptions.ogViewer) plugins.push(createOgViewerPlugin(resolvedOptions));
|
|
3709
|
+
return plugins;
|
|
3710
|
+
}
|
|
3711
|
+
async function regenerateDocs(resolvedOptions, root) {
|
|
3712
|
+
const docsOptions = resolvedOptions.docs;
|
|
3713
|
+
if (!docsOptions || !docsOptions.enabled) return 0;
|
|
3714
|
+
const srcDirs = docsOptions.src.map((src) => path$1.resolve(root, src));
|
|
3715
|
+
const outDir = path$1.resolve(root, docsOptions.out);
|
|
3716
|
+
const extracted = await extractDocs(srcDirs, docsOptions);
|
|
3717
|
+
const generated = generateMarkdown(extracted, docsOptions);
|
|
3718
|
+
await writeDocs(generated, outDir, extracted, docsOptions);
|
|
3719
|
+
return Object.keys(generated).length;
|
|
3720
|
+
}
|
|
3721
|
+
function createMainPlugin(resolvedOptions, setConfig) {
|
|
3722
|
+
return {
|
|
3723
|
+
name: "ox-content",
|
|
3724
|
+
configResolved: setConfig,
|
|
3722
3725
|
configureServer(devServer) {
|
|
3723
3726
|
devServer.middlewares.use(async (req, res, next) => {
|
|
3724
3727
|
const url = req.url;
|
|
@@ -3743,31 +3746,33 @@ function oxContent(options = {}) {
|
|
|
3743
3746
|
};
|
|
3744
3747
|
},
|
|
3745
3748
|
async handleHotUpdate({ file, server }) {
|
|
3746
|
-
if (isMarkdownFilePath(file, resolvedOptions.extensions))
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
}
|
|
3749
|
+
if (!isMarkdownFilePath(file, resolvedOptions.extensions)) return;
|
|
3750
|
+
server.ws.send({
|
|
3751
|
+
type: "custom",
|
|
3752
|
+
event: "ox-content:update",
|
|
3753
|
+
data: { file }
|
|
3754
|
+
});
|
|
3755
|
+
const modules = server.moduleGraph.getModulesByFile(file);
|
|
3756
|
+
return modules ? Array.from(modules) : [];
|
|
3755
3757
|
}
|
|
3756
3758
|
};
|
|
3757
|
-
|
|
3759
|
+
}
|
|
3760
|
+
function createEnvironmentPlugin(resolvedOptions) {
|
|
3761
|
+
return {
|
|
3758
3762
|
name: "ox-content:environment",
|
|
3759
3763
|
config() {
|
|
3760
3764
|
return { environments: { markdown: createMarkdownEnvironment(resolvedOptions) } };
|
|
3761
3765
|
}
|
|
3762
3766
|
};
|
|
3763
|
-
|
|
3767
|
+
}
|
|
3768
|
+
function createDocsPlugin(resolvedOptions, getRoot) {
|
|
3769
|
+
return {
|
|
3764
3770
|
name: "ox-content:docs",
|
|
3765
3771
|
async buildStart() {
|
|
3766
3772
|
const docsOptions = resolvedOptions.docs;
|
|
3767
3773
|
if (!docsOptions || !docsOptions.enabled) return;
|
|
3768
|
-
const root = config?.root || process.cwd();
|
|
3769
3774
|
try {
|
|
3770
|
-
const count = await regenerateDocs(
|
|
3775
|
+
const count = await regenerateDocs(resolvedOptions, getRoot());
|
|
3771
3776
|
console.log(`[ox-content] Generated ${count} documentation files to ${docsOptions.out}`);
|
|
3772
3777
|
} catch (err) {
|
|
3773
3778
|
console.warn("[ox-content] Failed to generate documentation:", err);
|
|
@@ -3776,50 +3781,32 @@ function oxContent(options = {}) {
|
|
|
3776
3781
|
configureServer(devServer) {
|
|
3777
3782
|
const docsOptions = resolvedOptions.docs;
|
|
3778
3783
|
if (!docsOptions || !docsOptions.enabled) return;
|
|
3779
|
-
const root =
|
|
3784
|
+
const root = getRoot();
|
|
3780
3785
|
const srcDirs = docsOptions.src.map((src) => path$1.resolve(root, src));
|
|
3781
3786
|
for (const srcDir of srcDirs) devServer.watcher.add(srcDir);
|
|
3782
3787
|
devServer.watcher.on("all", async (event, file) => {
|
|
3783
3788
|
if (event !== "add" && event !== "change" && event !== "unlink") return;
|
|
3784
|
-
if (srcDirs.some((srcDir) => file.startsWith(srcDir) && (file.endsWith(".ts") || file.endsWith(".tsx"))))
|
|
3785
|
-
|
|
3789
|
+
if (!srcDirs.some((srcDir) => file.startsWith(srcDir) && (file.endsWith(".ts") || file.endsWith(".tsx")))) return;
|
|
3790
|
+
try {
|
|
3791
|
+
await regenerateDocs(resolvedOptions, root);
|
|
3786
3792
|
} catch {}
|
|
3787
3793
|
});
|
|
3788
3794
|
}
|
|
3789
3795
|
};
|
|
3790
|
-
|
|
3791
|
-
|
|
3796
|
+
}
|
|
3797
|
+
function createSsgPlugin(resolvedOptions, getRoot, ssgDevCache) {
|
|
3798
|
+
return {
|
|
3792
3799
|
name: "ox-content:ssg",
|
|
3793
3800
|
configureServer(devServer) {
|
|
3794
3801
|
if (!resolvedOptions.ssg.enabled) return;
|
|
3795
|
-
const root =
|
|
3802
|
+
const root = getRoot();
|
|
3796
3803
|
const srcDir = path$1.resolve(root, resolvedOptions.srcDir);
|
|
3797
3804
|
devServer.middlewares.use(createDevServerMiddleware(resolvedOptions, root, ssgDevCache));
|
|
3798
3805
|
devServer.watcher.on("add", (file) => {
|
|
3799
|
-
|
|
3800
|
-
invalidateNavCache(ssgDevCache);
|
|
3801
|
-
devServer.ws.send({
|
|
3802
|
-
type: "custom",
|
|
3803
|
-
event: "ox-content:update",
|
|
3804
|
-
data: {
|
|
3805
|
-
file,
|
|
3806
|
-
type: "add"
|
|
3807
|
-
}
|
|
3808
|
-
});
|
|
3809
|
-
}
|
|
3806
|
+
notifySsgFileAddedOrRemoved(devServer, resolvedOptions, ssgDevCache, srcDir, file, "add");
|
|
3810
3807
|
});
|
|
3811
3808
|
devServer.watcher.on("unlink", (file) => {
|
|
3812
|
-
|
|
3813
|
-
invalidateNavCache(ssgDevCache);
|
|
3814
|
-
devServer.ws.send({
|
|
3815
|
-
type: "custom",
|
|
3816
|
-
event: "ox-content:update",
|
|
3817
|
-
data: {
|
|
3818
|
-
file,
|
|
3819
|
-
type: "unlink"
|
|
3820
|
-
}
|
|
3821
|
-
});
|
|
3822
|
-
}
|
|
3809
|
+
notifySsgFileAddedOrRemoved(devServer, resolvedOptions, ssgDevCache, srcDir, file, "unlink");
|
|
3823
3810
|
});
|
|
3824
3811
|
devServer.watcher.on("change", (file) => {
|
|
3825
3812
|
if (file.startsWith(srcDir) && isMarkdownFilePath(file, resolvedOptions.extensions)) invalidatePageCache(ssgDevCache, file);
|
|
@@ -3827,63 +3814,63 @@ function oxContent(options = {}) {
|
|
|
3827
3814
|
},
|
|
3828
3815
|
async closeBundle() {
|
|
3829
3816
|
if (!resolvedOptions.ssg.enabled) return;
|
|
3830
|
-
const root = config?.root || process.cwd();
|
|
3831
3817
|
try {
|
|
3832
|
-
const result = await buildSsg(resolvedOptions,
|
|
3818
|
+
const result = await buildSsg(resolvedOptions, getRoot());
|
|
3833
3819
|
if (result.files.length > 0) console.log(`[ox-content] Generated ${result.files.length} output files`);
|
|
3834
|
-
|
|
3820
|
+
for (const error of result.errors) console.warn(`[ox-content] ${error}`);
|
|
3835
3821
|
} catch (err) {
|
|
3836
3822
|
console.error("[ox-content] SSG build failed:", err);
|
|
3837
3823
|
}
|
|
3838
3824
|
}
|
|
3839
3825
|
};
|
|
3826
|
+
}
|
|
3827
|
+
function notifySsgFileAddedOrRemoved(devServer, resolvedOptions, ssgDevCache, srcDir, file, type) {
|
|
3828
|
+
if (!file.startsWith(srcDir) || !isMarkdownFilePath(file, resolvedOptions.extensions)) return;
|
|
3829
|
+
invalidateNavCache(ssgDevCache);
|
|
3830
|
+
devServer.ws.send({
|
|
3831
|
+
type: "custom",
|
|
3832
|
+
event: "ox-content:update",
|
|
3833
|
+
data: {
|
|
3834
|
+
file,
|
|
3835
|
+
type
|
|
3836
|
+
}
|
|
3837
|
+
});
|
|
3838
|
+
}
|
|
3839
|
+
function createSearchPlugin(resolvedOptions, getRoot) {
|
|
3840
3840
|
let searchIndexJson = "";
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
}
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
async closeBundle() {
|
|
3872
|
-
if (!resolvedOptions.search.enabled || !searchIndexJson) return;
|
|
3873
|
-
const root = config?.root || process.cwd();
|
|
3874
|
-
const outDir = path$1.resolve(root, resolvedOptions.outDir);
|
|
3875
|
-
try {
|
|
3876
|
-
await writeSearchIndex(searchIndexJson, outDir);
|
|
3877
|
-
console.log("[ox-content] Search index written to", path$1.join(outDir, "search-index.json"));
|
|
3878
|
-
} catch (err) {
|
|
3879
|
-
console.warn("[ox-content] Failed to write search index:", err);
|
|
3880
|
-
}
|
|
3841
|
+
return {
|
|
3842
|
+
name: "ox-content:search",
|
|
3843
|
+
resolveId(id) {
|
|
3844
|
+
if (id === "virtual:ox-content/search") return "\0virtual:ox-content/search";
|
|
3845
|
+
return null;
|
|
3846
|
+
},
|
|
3847
|
+
async load(id) {
|
|
3848
|
+
if (id !== "\0virtual:ox-content/search") return null;
|
|
3849
|
+
const searchOptions = resolvedOptions.search;
|
|
3850
|
+
if (!searchOptions.enabled) return "export const search = () => []; export const searchOptions = { enabled: false }; export default { search, searchOptions };";
|
|
3851
|
+
return generateSearchModule(searchOptions, resolvedOptions.base + "search-index.json");
|
|
3852
|
+
},
|
|
3853
|
+
async buildStart() {
|
|
3854
|
+
if (!resolvedOptions.search.enabled) return;
|
|
3855
|
+
const srcDir = path$1.resolve(getRoot(), resolvedOptions.srcDir);
|
|
3856
|
+
try {
|
|
3857
|
+
searchIndexJson = await buildSearchIndex(srcDir, resolvedOptions.base, resolvedOptions.extensions);
|
|
3858
|
+
console.log("[ox-content] Search index built");
|
|
3859
|
+
} catch (err) {
|
|
3860
|
+
console.warn("[ox-content] Failed to build search index:", err);
|
|
3861
|
+
}
|
|
3862
|
+
},
|
|
3863
|
+
async closeBundle() {
|
|
3864
|
+
if (!resolvedOptions.search.enabled || !searchIndexJson) return;
|
|
3865
|
+
const outDir = path$1.resolve(getRoot(), resolvedOptions.outDir);
|
|
3866
|
+
try {
|
|
3867
|
+
await writeSearchIndex(searchIndexJson, outDir);
|
|
3868
|
+
console.log("[ox-content] Search index written to", path$1.join(outDir, "search-index.json"));
|
|
3869
|
+
} catch (err) {
|
|
3870
|
+
console.warn("[ox-content] Failed to write search index:", err);
|
|
3881
3871
|
}
|
|
3882
3872
|
}
|
|
3883
|
-
|
|
3884
|
-
if (resolvedOptions.i18n) plugins.push(createI18nPlugin(resolvedOptions));
|
|
3885
|
-
if (resolvedOptions.ogViewer) plugins.push(createOgViewerPlugin(resolvedOptions));
|
|
3886
|
-
return plugins;
|
|
3873
|
+
};
|
|
3887
3874
|
}
|
|
3888
3875
|
/**
|
|
3889
3876
|
* Resolves plugin options with defaults.
|