@ox-content/vite-plugin 2.86.0 → 2.88.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 CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_vitepress = require("./vitepress.cjs");
3
3
  const require_interop = require("./interop.cjs");
4
4
  const require_tabs = require("./tabs.cjs");
5
+ const require_jsx_html = require("./jsx-html.cjs");
5
6
  let path = require("path");
6
7
  path = require_vitepress.__toESM(path, 1);
7
8
  let unified = require("unified");
@@ -108,6 +109,56 @@ function createMarkdownEnvironment(options) {
108
109
  };
109
110
  }
110
111
  //#endregion
112
+ //#region src/shiki-theme.ts
113
+ /**
114
+ * Name callers pass as `highlightTheme` to render syntax colors as CSS custom
115
+ * properties instead of baked-in hex values.
116
+ */
117
+ const CSS_VARIABLES_THEME = "css-variables";
118
+ /** Prefix for the emitted properties, matching the rest of the design tokens. */
119
+ const VARIABLE_PREFIX = "--octc-shiki-";
120
+ /**
121
+ * Fallbacks baked into each `var()` so a site with no color scheme installed
122
+ * still renders GitHub Dark colors — the previous default — rather than
123
+ * unstyled text. A `@ox-content/theme-color-*` package overrides them by
124
+ * defining the same properties per mode.
125
+ */
126
+ const VARIABLE_DEFAULTS = {
127
+ foreground: "#e6edf3",
128
+ background: "#0d1117",
129
+ "token-constant": "#79c0ff",
130
+ "token-string": "#a5d6ff",
131
+ "token-comment": "#8b949e",
132
+ "token-keyword": "#ff7b72",
133
+ "token-parameter": "#ffa657",
134
+ "token-function": "#d2a8ff",
135
+ "token-string-expression": "#a5d6ff",
136
+ "token-punctuation": "#c9d1d9",
137
+ "token-link": "#a5d6ff"
138
+ };
139
+ let cached;
140
+ /**
141
+ * Shiki theme whose every color is a `--octc-shiki-*` custom property.
142
+ *
143
+ * This is what lets syntax highlighting track the active color scheme in both
144
+ * light and dark from a single build: the HTML is generated once, and the
145
+ * properties resolve per mode. A fixed theme like `github-dark` cannot do that,
146
+ * and lands dark token colors on a light code block.
147
+ */
148
+ function cssVariablesTheme() {
149
+ cached ??= (0, shiki.createCssVariablesTheme)({
150
+ name: CSS_VARIABLES_THEME,
151
+ variablePrefix: VARIABLE_PREFIX,
152
+ variableDefaults: VARIABLE_DEFAULTS,
153
+ fontStyle: true
154
+ });
155
+ return cached;
156
+ }
157
+ /** Resolves the `css-variables` alias; any other value passes through. */
158
+ function resolveHighlightTheme(theme) {
159
+ return theme === "css-variables" ? cssVariablesTheme() : theme;
160
+ }
161
+ //#endregion
111
162
  //#region src/highlight.ts
112
163
  /**
113
164
  * Syntax highlighting with Shiki via rehype.
@@ -160,7 +211,8 @@ async function getHighlighter(theme, customLangs = []) {
160
211
  }
161
212
  return highlighterPromise;
162
213
  }
163
- function normalizeThemeInput(theme) {
214
+ function normalizeThemeInput(input) {
215
+ const theme = resolveHighlightTheme(input);
164
216
  if (typeof theme === "string") return {
165
217
  themeInput: theme,
166
218
  themeName: theme
@@ -269,7 +321,7 @@ function normalizeClassName(className) {
269
321
  /**
270
322
  * Apply syntax highlighting to HTML using Shiki.
271
323
  */
272
- async function highlightCode(html, theme = "github-dark", langs = []) {
324
+ async function highlightCode(html, theme = CSS_VARIABLES_THEME, langs = []) {
273
325
  const result = await (0, unified.unified)().use(rehypeParse$3, { fragment: true }).use(rehypeShikiHighlight, {
274
326
  theme,
275
327
  langs
@@ -584,8 +636,8 @@ function assetRecord(src, media) {
584
636
  //#region src/plugins/twitter/render.ts
585
637
  function renderFetchedTweet(permalink, data, assets, options) {
586
638
  const profile = `https://x.com/${encodeURIComponent(data.user.screen_name)}`;
587
- const author = escapeHtml$3(data.user.name);
588
- const handle = escapeHtml$3(data.user.screen_name);
639
+ const author = escapeHtml$2(data.user.name);
640
+ const handle = escapeHtml$2(data.user.screen_name);
589
641
  const avatar = assets.avatar ? `<img class="ox-tweet__avatar" src="${escapeAttribute(assets.avatar)}" alt="" width="48" height="48" loading="lazy" decoding="async">` : "";
590
642
  const media = renderMedia(assets);
591
643
  const footer = renderFooter(permalink, data.created_at, options.lang);
@@ -615,7 +667,7 @@ function renderTweetText(data) {
615
667
  if (entity.kind === "url") {
616
668
  const href = entity.expanded_url ?? entity.url;
617
669
  const label = entity.display_url ?? href;
618
- output += `<a href="${escapeAttribute(href)}" target="_blank" rel="noopener noreferrer">${escapeHtml$3(label)}</a>`;
670
+ output += `<a href="${escapeAttribute(href)}" target="_blank" rel="noopener noreferrer">${escapeHtml$2(label)}</a>`;
619
671
  }
620
672
  cursor = entityEnd;
621
673
  }
@@ -659,15 +711,15 @@ function renderFooter(permalink, createdAt, lang) {
659
711
  timeZone: "UTC"
660
712
  }).format(date);
661
713
  }
662
- return `<footer class="ox-tweet__footer"><a class="ox-tweet__permalink" href="${escapeAttribute(permalink)}" target="_blank" rel="noopener noreferrer"><time datetime="${iso}">${escapeHtml$3(label)}</time></a></footer>`;
714
+ return `<footer class="ox-tweet__footer"><a class="ox-tweet__permalink" href="${escapeAttribute(permalink)}" target="_blank" rel="noopener noreferrer"><time datetime="${iso}">${escapeHtml$2(label)}</time></a></footer>`;
663
715
  }
664
716
  function escapeText(value) {
665
- return escapeHtml$3(value).replaceAll("\n", "<br>");
717
+ return escapeHtml$2(value).replaceAll("\n", "<br>");
666
718
  }
667
719
  function escapeAttribute(value) {
668
- return escapeHtml$3(value).replaceAll("`", "&#96;");
720
+ return escapeHtml$2(value).replaceAll("`", "&#96;");
669
721
  }
670
- function escapeHtml$3(value) {
722
+ function escapeHtml$2(value) {
671
723
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
672
724
  }
673
725
  //#endregion
@@ -2496,7 +2548,7 @@ function formatChromiumUnavailableDetail(err) {
2496
2548
  /**
2497
2549
  * Escapes HTML special characters.
2498
2550
  */
2499
- function escapeHtml$2(str) {
2551
+ function escapeHtml$1(str) {
2500
2552
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2501
2553
  }
2502
2554
  function normalizeBrandValue(str) {
@@ -2559,12 +2611,12 @@ function getDefaultTemplate() {
2559
2611
  const isBrandCard = normalizeBrandValue(title) === normalizeBrandValue(rawBrand);
2560
2612
  const heroTitle = isBrandCard ? "High-performance Markdown toolkit" : title;
2561
2613
  const heroDescription = isBrandCard ? "Rust-powered docs and high-performance Markdown tooling." : description && description.trim().length > 0 ? description : "Rust-powered docs and Markdown tooling.";
2562
- const descriptionHtml = heroDescription.trim().length > 0 ? `<p style="max-width:760px;font-size:28px;color:#93a4c3;line-height:1.45;margin:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;">${escapeHtml$2(heroDescription)}</p>` : "";
2614
+ const descriptionHtml = heroDescription.trim().length > 0 ? `<p style="max-width:760px;font-size:28px;color:#93a4c3;line-height:1.45;margin:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;">${escapeHtml$1(heroDescription)}</p>` : "";
2563
2615
  return `<div style="width:100%;height:100%;position:relative;overflow:hidden;box-sizing:border-box;padding:56px 64px 52px;background:#0b1220;font-family:'IBM Plex Sans','Avenir Next','Segoe UI',system-ui,sans-serif;color:#eff6ff;border:1px solid #223252;border-top:4px solid #4f6fae;">
2564
2616
  <div style="position:relative;z-index:1;display:flex;flex-direction:column;height:100%;">
2565
2617
  <div style="display:flex;align-items:flex-start;">${renderWordmarkSvg()}</div>
2566
2618
  <div style="display:flex;flex-direction:column;justify-content:center;gap:24px;max-width:860px;flex:1;padding:22px 0 0;">
2567
- <h1 style="font-size:78px;font-weight:700;color:#eff6ff;line-height:1.02;letter-spacing:-0.055em;margin:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;">${escapeHtml$2(heroTitle)}</h1>
2619
+ <h1 style="font-size:78px;font-weight:700;color:#eff6ff;line-height:1.02;letter-spacing:-0.055em;margin:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;">${escapeHtml$1(heroTitle)}</h1>
2568
2620
  ${descriptionHtml}
2569
2621
  </div>
2570
2622
  </div>
@@ -3531,10 +3583,22 @@ async function createBuildSsgContext(options, root, srcDir, outDir, markdownFile
3531
3583
  base,
3532
3584
  navItems: resolveNavigationGroups(ssgOptions.navigation, base, ssgOptions.extension) ?? (ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension)),
3533
3585
  siteName: await resolveSiteName$1(root, ssgOptions),
3534
- shouldGenerateOgImages: (options.ogImage || ssgOptions.generateOgImage) && !ssgOptions.bare,
3586
+ shouldGenerateOgImages: shouldGenerateOgImages(options),
3535
3587
  napi: ssgOptions.lastUpdated ? await require_vitepress.importNapiModule() : void 0
3536
3588
  };
3537
3589
  }
3590
+ /**
3591
+ * Whether this build emits one Open Graph image per page.
3592
+ *
3593
+ * `ssg.bare` deliberately does not turn this off. Bare mode only drops the
3594
+ * generated page shell, and bringing your own shell is exactly the case where
3595
+ * per-page OG images are still wanted — the images are written to the output
3596
+ * tree and the consumer injects the `<meta>` tags itself. Nothing in the bare
3597
+ * HTML references them, because bare output has no `<head>` to put them in.
3598
+ */
3599
+ function shouldGenerateOgImages(options) {
3600
+ return options.ogImage || options.ssg.generateOgImage;
3601
+ }
3538
3602
  async function resolveSiteName$1(root, ssgOptions) {
3539
3603
  if (ssgOptions.siteName) return ssgOptions.siteName;
3540
3604
  try {
@@ -4877,7 +4941,7 @@ function createFrameworkMarkdownOptions(options) {
4877
4941
  strikethrough: true,
4878
4942
  autolinks: options.gfm,
4879
4943
  highlight: false,
4880
- highlightTheme: "github-dark",
4944
+ highlightTheme: CSS_VARIABLES_THEME,
4881
4945
  highlightLangs: [],
4882
4946
  mermaid: false,
4883
4947
  ogImage: false,
@@ -5689,195 +5753,6 @@ function createEmptyLintResult() {
5689
5753
  };
5690
5754
  }
5691
5755
  //#endregion
5692
- //#region src/jsx-runtime.ts
5693
- /**
5694
- * Custom JSX Runtime for Static HTML Generation
5695
- *
5696
- * This module provides a JSX runtime that outputs static HTML strings.
5697
- * No React, no hydration, no client-side JavaScript - just pure HTML.
5698
- *
5699
- * @example
5700
- * ```tsx
5701
- * // tsconfig.json or vite.config.ts
5702
- * {
5703
- * "compilerOptions": {
5704
- * "jsx": "react-jsx",
5705
- * "jsxImportSource": "@ox-content/vite-plugin"
5706
- * }
5707
- * }
5708
- *
5709
- * // MyComponent.tsx
5710
- * export function Hero({ title }: { title: string }) {
5711
- * return (
5712
- * <section class="hero">
5713
- * <h1>{title}</h1>
5714
- * </section>
5715
- * );
5716
- * }
5717
- * ```
5718
- */
5719
- const VOID_ELEMENTS = /* @__PURE__ */ new Set([
5720
- "area",
5721
- "base",
5722
- "br",
5723
- "col",
5724
- "embed",
5725
- "hr",
5726
- "img",
5727
- "input",
5728
- "link",
5729
- "meta",
5730
- "param",
5731
- "source",
5732
- "track",
5733
- "wbr"
5734
- ]);
5735
- const BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
5736
- "allowfullscreen",
5737
- "async",
5738
- "autofocus",
5739
- "autoplay",
5740
- "checked",
5741
- "controls",
5742
- "default",
5743
- "defer",
5744
- "disabled",
5745
- "formnovalidate",
5746
- "hidden",
5747
- "inert",
5748
- "ismap",
5749
- "itemscope",
5750
- "loop",
5751
- "multiple",
5752
- "muted",
5753
- "nomodule",
5754
- "novalidate",
5755
- "open",
5756
- "playsinline",
5757
- "readonly",
5758
- "required",
5759
- "reversed",
5760
- "selected"
5761
- ]);
5762
- /**
5763
- * Escapes HTML special characters to prevent XSS.
5764
- */
5765
- function escapeHtml$1(str) {
5766
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");
5767
- }
5768
- /**
5769
- * Converts a camelCase attribute name to kebab-case for HTML.
5770
- * Special handling for data-* and aria-* attributes.
5771
- */
5772
- function toHtmlAttr(name) {
5773
- if (name === "className") return "class";
5774
- if (name === "htmlFor") return "for";
5775
- if (name.startsWith("data") || name.startsWith("aria")) return name.replace(/([A-Z])/g, "-$1").toLowerCase();
5776
- return name;
5777
- }
5778
- /**
5779
- * Renders an attribute value to a string.
5780
- */
5781
- function renderAttr(name, value) {
5782
- const htmlName = toHtmlAttr(name);
5783
- if (value === void 0 || value === null || value === false) return "";
5784
- if (BOOLEAN_ATTRS.has(htmlName)) return value ? ` ${htmlName}` : "";
5785
- if (name === "style" && typeof value === "object") return ` style="${escapeHtml$1(Object.entries(value).map(([k, v]) => {
5786
- return `${k.replace(/([A-Z])/g, "-$1").toLowerCase()}:${v}`;
5787
- }).join(";"))}"`;
5788
- return ` ${htmlName}="${escapeHtml$1(String(value))}"`;
5789
- }
5790
- /**
5791
- * Renders children to HTML string.
5792
- */
5793
- function renderChildren(children) {
5794
- if (children === null || children === void 0 || children === false) return "";
5795
- if (children === true) return "";
5796
- if (typeof children === "string") return escapeHtml$1(children);
5797
- if (typeof children === "number") return String(children);
5798
- if (Array.isArray(children)) return children.map(renderChildren).join("");
5799
- if (typeof children === "object" && "__html" in children) return children.__html;
5800
- return "";
5801
- }
5802
- /**
5803
- * Creates a JSX element.
5804
- * This is the core function called by the JSX transform.
5805
- */
5806
- function jsx(type, props, _key) {
5807
- const { children, ...restProps } = props;
5808
- if (typeof type === "function") return type({
5809
- ...restProps,
5810
- children
5811
- });
5812
- const tag = type;
5813
- let html = `<${tag}`;
5814
- for (const [name, value] of Object.entries(restProps)) {
5815
- if (name === "key" || name === "ref") continue;
5816
- html += renderAttr(name, value);
5817
- }
5818
- if (VOID_ELEMENTS.has(tag)) {
5819
- html += " />";
5820
- return { __html: html };
5821
- }
5822
- html += ">";
5823
- if (children !== void 0) html += renderChildren(children);
5824
- html += `</${tag}>`;
5825
- return { __html: html };
5826
- }
5827
- /**
5828
- * Creates a JSX element with static children.
5829
- * Called by the JSX transform for elements with multiple children.
5830
- */
5831
- function jsxs(type, props, key) {
5832
- return jsx(type, props, key);
5833
- }
5834
- /**
5835
- * Fragment component - renders children without a wrapper element.
5836
- */
5837
- function Fragment({ children }) {
5838
- return { __html: renderChildren(children) };
5839
- }
5840
- /**
5841
- * Renders a JSX node to an HTML string.
5842
- */
5843
- function renderToString(node) {
5844
- return node.__html;
5845
- }
5846
- /**
5847
- * Creates raw HTML without escaping.
5848
- * Use with caution - only for trusted content.
5849
- *
5850
- * @example
5851
- * ```tsx
5852
- * <div>{raw('<strong>Bold</strong>')}</div>
5853
- * ```
5854
- */
5855
- function raw(html) {
5856
- return { __html: html };
5857
- }
5858
- /**
5859
- * Conditionally renders content.
5860
- *
5861
- * @example
5862
- * ```tsx
5863
- * {when(isLoggedIn, <UserMenu />)}
5864
- * ```
5865
- */
5866
- function when(condition, content) {
5867
- return condition ? content : { __html: "" };
5868
- }
5869
- /**
5870
- * Maps over an array and renders each item.
5871
- *
5872
- * @example
5873
- * ```tsx
5874
- * {each(items, (item) => <li>{item.name}</li>)}
5875
- * ```
5876
- */
5877
- function each(items, render) {
5878
- return { __html: items.map((item, i) => render(item, i).__html).join("") };
5879
- }
5880
- //#endregion
5881
5756
  //#region src/page-context.ts
5882
5757
  var page_context_exports = /* @__PURE__ */ require_vitepress.__exportAll({
5883
5758
  clearRenderContext: () => clearRenderContext,
@@ -6115,7 +5990,8 @@ function renderPage(page, options) {
6115
5990
  }
6116
5991
  });
6117
5992
  try {
6118
- const html = renderToString(theme({ children: raw(page.html) }));
5993
+ const result = theme({ children: require_jsx_html.raw(page.html) });
5994
+ const html = require_jsx_html.renderToString(result);
6119
5995
  if (!html.trimStart().toLowerCase().startsWith("<!doctype")) return `<!DOCTYPE html>\n${html}`;
6120
5996
  return html;
6121
5997
  } finally {
@@ -6512,7 +6388,7 @@ function resolveOptions(options) {
6512
6388
  strikethrough: options.strikethrough ?? true,
6513
6389
  autolinks: options.autolinks ?? options.gfm ?? true,
6514
6390
  highlight: options.highlight ?? false,
6515
- highlightTheme: options.highlightTheme ?? "github-dark",
6391
+ highlightTheme: options.highlightTheme ?? "css-variables",
6516
6392
  highlightLangs: options.highlightLangs ?? [],
6517
6393
  codeAnnotations: resolveCodeAnnotationsOptions(options.codeAnnotations),
6518
6394
  wikiLinks: resolveWikiLinkOptions(options.wikiLinks, options.base ?? "/"),
@@ -6799,7 +6675,7 @@ exports.DEFAULT_HTML_TEMPLATE = DEFAULT_HTML_TEMPLATE;
6799
6675
  exports.DEFAULT_MARKDOWN_EXTENSIONS = DEFAULT_MARKDOWN_EXTENSIONS;
6800
6676
  exports.DefaultTheme = DefaultTheme;
6801
6677
  exports.DocsTestRunError = DocsTestRunError;
6802
- exports.Fragment = Fragment;
6678
+ exports.Fragment = require_jsx_html.Fragment;
6803
6679
  exports.IncrementalMarkdownParser = IncrementalMarkdownParser;
6804
6680
  exports.IncrementalMarkdownRenderer = IncrementalMarkdownRenderer;
6805
6681
  exports.buildCollectionManifest = buildCollectionManifest;
@@ -6822,7 +6698,7 @@ exports.defaultTheme = require_vitepress.defaultTheme;
6822
6698
  exports.defineCollection = defineCollection;
6823
6699
  exports.defineCollections = defineCollections;
6824
6700
  exports.defineTheme = require_vitepress.defineTheme;
6825
- exports.each = each;
6701
+ exports.each = require_jsx_html.each;
6826
6702
  exports.escapeSvelteMarkup = escapeSvelteMarkup;
6827
6703
  exports.extractCodeBlocks = extractCodeBlocks;
6828
6704
  exports.extractDocs = extractDocs;
@@ -6845,8 +6721,8 @@ exports.generateVitePressMigrationConfig = require_vitepress.generateVitePressMi
6845
6721
  exports.hasIslands = hasIslands;
6846
6722
  exports.inferType = inferType;
6847
6723
  exports.isMarkdownFilePath = isMarkdownFilePath;
6848
- exports.jsx = jsx;
6849
- exports.jsxs = jsxs;
6724
+ exports.jsx = require_jsx_html.jsx;
6725
+ exports.jsxs = require_jsx_html.jsxs;
6850
6726
  exports.lintCodeBlocks = lintCodeBlocks;
6851
6727
  exports.lintMarkdown = lintMarkdown;
6852
6728
  exports.lintMarkdownAsync = lintMarkdownAsync;
@@ -6862,7 +6738,7 @@ exports.parseGitHubPermalink = parseGitHubPermalink;
6862
6738
  exports.prefetchGitHubRepos = prefetchGitHubRepos;
6863
6739
  exports.prefetchGitHubSources = prefetchGitHubSources;
6864
6740
  exports.prefetchOgpData = prefetchOgpData;
6865
- exports.raw = raw;
6741
+ exports.raw = require_jsx_html.raw;
6866
6742
  exports.renderAllPages = renderAllPages;
6867
6743
  exports.renderHtmlToFrameworkCode = renderHtmlToFrameworkCode;
6868
6744
  exports.renderHtmlToReactComponent = renderHtmlToReactComponent;
@@ -6872,7 +6748,7 @@ exports.renderHtmlToVueComponent = renderHtmlToVueComponent;
6872
6748
  exports.renderHtmlToVueH = renderHtmlToVueH;
6873
6749
  exports.renderMarkdownStream = renderMarkdownStream;
6874
6750
  exports.renderPage = renderPage;
6875
- exports.renderToString = renderToString;
6751
+ exports.renderToString = require_jsx_html.renderToString;
6876
6752
  exports.resolveBuiltinEmbedOptions = resolveBuiltinEmbedOptions;
6877
6753
  exports.resolveCollectionsOptions = resolveCollectionsOptions;
6878
6754
  exports.resolveDocsOptions = resolveDocsOptions;
@@ -6899,7 +6775,7 @@ exports.useNav = useNav;
6899
6775
  exports.usePageProps = usePageProps;
6900
6776
  exports.useRenderContext = useRenderContext;
6901
6777
  exports.useSiteConfig = useSiteConfig;
6902
- exports.when = when;
6778
+ exports.when = require_jsx_html.when;
6903
6779
  exports.writeDocs = writeDocs;
6904
6780
  exports.writeDocsTestFiles = writeDocsTestFiles;
6905
6781
  exports.writeSearchIndex = writeSearchIndex;