@ox-content/vite-plugin 3.0.0-alpha.3 → 3.0.0-alpha.5

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
@@ -140,8 +140,8 @@ function normalizeClassName(className) {
140
140
  * Highlights with the native tree-sitter engine, or `null` when it has no
141
141
  * grammar for `lang`.
142
142
  *
143
- * It emits `--octc-shiki-*` markup (the `shiki` prefix is historical) so
144
- * theme-color packages keep working.
143
+ * It emits `--octc-syntax-*` markup so theme-color packages resolve token
144
+ * colors.
145
145
  */
146
146
  function highlightNatively(code, lang) {
147
147
  try {
@@ -168,8 +168,8 @@ async function highlightDocumentNatively(html) {
168
168
  /**
169
169
  * Syntax highlighting with the native tree-sitter engine.
170
170
  *
171
- * Markup keeps the historical `<pre class="shiki css-variables">` wrapper and
172
- * `--octc-shiki-*` custom properties so theme-color packages keep working.
171
+ * Markup uses `<pre class="ox-highlight css-variables">` and `--octc-syntax-*`
172
+ * custom properties so theme-color packages resolve token colors.
173
173
  */
174
174
  const rehypeParse$3 = require_interop.interopDefault(rehype_parse.default);
175
175
  const rehypeStringify$3 = require_interop.interopDefault(rehype_stringify.default);
@@ -213,7 +213,7 @@ function rehypeNativeHighlight() {
213
213
  highlightedCode.properties.className = [.../* @__PURE__ */ new Set([
214
214
  ...originalCodeClasses,
215
215
  ...highlightedClasses,
216
- "shiki-inline"
216
+ "ox-highlight-inline"
217
217
  ])];
218
218
  highlightedCode.properties["data-language"] = lang;
219
219
  return highlightedCode;
@@ -228,7 +228,7 @@ function rehypeNativeHighlight() {
228
228
  const child = node.children[i];
229
229
  if (child.type === "element" && child.tagName === "pre") {
230
230
  const codeElement = child.children.find((c) => c.type === "element" && c.tagName === "code");
231
- const alreadyHighlighted = normalizeClassName(child.properties?.className).includes("shiki");
231
+ const alreadyHighlighted = normalizeClassName(child.properties?.className).includes("ox-highlight");
232
232
  if (codeElement && !alreadyHighlighted) {
233
233
  const highlightedPre = highlightBlockCode(codeElement);
234
234
  if (highlightedPre) node.children[i] = highlightedPre;
@@ -1762,7 +1762,7 @@ async function transformOgp(html, ogpDataMap, options) {
1762
1762
  const SELF_CLOSING_EMBED_TAG = /<(GitHub|OgCard|Tweet|XPost|Bluesky|Spotify|StackBlitz|WebContainer|YouTube)((?:[^>"']|"[^"]*"|'[^']*')*?)\s*\/>/gi;
1763
1763
  /**
1764
1764
  * Custom embed tags are not HTML void elements, so a self-closing authoring
1765
- * form like `<GitHub ... />` reaches the HTML re-parsers (Shiki highlighting,
1765
+ * form like `<GitHub ... />` reaches the HTML re-parsers (syntax highlighting,
1766
1766
  * embed transforms) as an unclosed element that swallows the rest of the
1767
1767
  * document. Normalize to an explicit open/close pair before any rehype pass
1768
1768
  * runs.
@@ -2210,7 +2210,8 @@ async function applyTypedHover(source, html, options) {
2210
2210
  if (fences.length === 0) return html;
2211
2211
  try {
2212
2212
  return attachTypedHoverPayloads(html, await generateTypedHoverAttachments(fences, options.tsgoCommand));
2213
- } catch {
2213
+ } catch (error) {
2214
+ console.warn("[ox-content] typedHover failed; leaving the fence unannotated.", error);
2214
2215
  return html;
2215
2216
  }
2216
2217
  }
@@ -2302,10 +2303,16 @@ function normalizeFenceText(value) {
2302
2303
  return decodeHtmlEntities(value).replace(/\r\n/g, "\n").trim();
2303
2304
  }
2304
2305
  function decodeHtmlEntities(value) {
2305
- return value.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, "\"").replace(/&#39;/g, "'");
2306
+ return value.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&#39;/g, "'").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => {
2307
+ const code = Number.parseInt(hex, 16);
2308
+ return Number.isFinite(code) ? String.fromCodePoint(code) : "";
2309
+ }).replace(/&#(\d+);/g, (_, dec) => {
2310
+ const code = Number.parseInt(dec, 10);
2311
+ return Number.isFinite(code) ? String.fromCodePoint(code) : "";
2312
+ }).replace(/&amp;/g, "&");
2306
2313
  }
2307
2314
  const TYPED_HOVER_STYLE = `<style data-ox-typed-hover-style>.ox-typed-hover-token{cursor:help;text-decoration:underline dotted}.ox-typed-hover-overlay{position:fixed;z-index:50;max-width:36rem;padding:.35rem .55rem;border:1px solid #444;border-radius:4px;background:#1e1e1e;color:#d4d4d4;font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap;pointer-events:none}</style>`;
2308
- const TYPED_HOVER_CLIENT = `<script data-ox-typed-hover-runtime>(function(){if(window.__oxTypedHover)return;window.__oxTypedHover=1;var tip=document.createElement("div");tip.className="ox-typed-hover-overlay";tip.setAttribute("role","tooltip");tip.hidden=true;document.body.appendChild(tip);function payload(token){var pre=token.closest(".ox-typed-hover");var data=pre&&pre.nextElementSibling;if(!data||!data.classList.contains("ox-typed-hover-data"))return null;try{return JSON.parse(data.textContent||"")}catch(e){return null}}function show(token){var data=payload(token);var item=data&&data.hovers[Number(token.getAttribute("data-ox-typed-hover"))];if(!item)return;tip.textContent=item.type;tip.hidden=false;var box=token.getBoundingClientRect();tip.style.left=Math.max(8,box.left)+"px";tip.style.top=Math.max(8,box.top-tip.offsetHeight-8)+"px"}function hide(){tip.hidden=true}document.addEventListener("mouseover",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t)show(t)});document.addEventListener("mouseout",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t&&!t.contains(e.relatedTarget))hide()});document.addEventListener("focusin",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t)show(t)});document.addEventListener("focusout",function(e){if(!e.relatedTarget||!e.relatedTarget.closest(".ox-typed-hover-token"))hide()});document.addEventListener("keydown",function(e){if(e.key==="Escape")hide()})})();<\/script>`;
2315
+ const TYPED_HOVER_CLIENT = `<script data-ox-typed-hover-runtime>(function(){if(window.__oxTypedHover)return;window.__oxTypedHover=1;var tip=document.createElement("div");tip.className="ox-typed-hover-overlay";tip.setAttribute("role","tooltip");tip.hidden=true;document.body.appendChild(tip);function payload(token){var pre=token.closest(".ox-typed-hover");if(!pre)return null;var host=pre.closest(".ox-code")||pre;var data=host.nextElementSibling;if(!data||!data.classList.contains("ox-typed-hover-data"))return null;try{return JSON.parse(data.textContent||"")}catch(e){return null}}function show(token){var data=payload(token);var item=data&&data.hovers[Number(token.getAttribute("data-ox-typed-hover"))];if(!item)return;tip.textContent=item.type;tip.hidden=false;var box=token.getBoundingClientRect();tip.style.left=Math.max(8,box.left)+"px";tip.style.top=Math.max(8,box.top-tip.offsetHeight-8)+"px"}function hide(){tip.hidden=true}document.addEventListener("mouseover",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t)show(t)});document.addEventListener("mouseout",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t&&!t.contains(e.relatedTarget))hide()});document.addEventListener("focusin",function(e){var t=e.target.closest(".ox-typed-hover-token");if(t)show(t)});document.addEventListener("focusout",function(e){if(!e.relatedTarget||!e.relatedTarget.closest(".ox-typed-hover-token"))hide()});document.addEventListener("keydown",function(e){if(e.key==="Escape")hide()})})();<\/script>`;
2309
2316
  //#endregion
2310
2317
  //#region src/file-tree-options.ts
2311
2318
  const disabled = {
@@ -4131,6 +4138,22 @@ function stripLocalePrefix(sitePath, locales) {
4131
4138
  return normalized;
4132
4139
  }
4133
4140
  //#endregion
4141
+ //#region src/page-head.ts
4142
+ /** Resolve descriptors to escaped `<head>` markup. Build-time only. */
4143
+ function renderHead(input) {
4144
+ return require_vitepress.importNapiModuleSync().renderHead(JSON.stringify(input));
4145
+ }
4146
+ function resolveHeadValidation(value) {
4147
+ if (value === "warn" || value === "strict") return value;
4148
+ return false;
4149
+ }
4150
+ function reportHeadDiagnostics(diagnostics, validation) {
4151
+ if (!validation || diagnostics.length === 0) return;
4152
+ const fatal = diagnostics.filter((item) => item.strict);
4153
+ if (validation === "strict" && fatal.length > 0) throw new Error(`[ox-content] ${fatal[0].message}`);
4154
+ if (validation === "warn") for (const item of diagnostics) console.warn(`[ox-content] ${item.message}`);
4155
+ }
4156
+ //#endregion
4134
4157
  //#region src/page-context.ts
4135
4158
  var page_context_exports = /* @__PURE__ */ require_vitepress.__exportAll({
4136
4159
  clearRenderContext: () => clearRenderContext,
@@ -9250,6 +9273,7 @@ function resolveSsgOptions(ssg) {
9250
9273
  pagination: false,
9251
9274
  breadcrumbs: false,
9252
9275
  jsonLd: false,
9276
+ headValidation: false,
9253
9277
  readerChrome: false,
9254
9278
  localeSwitcher: false,
9255
9279
  a11y: false,
@@ -9270,6 +9294,7 @@ function resolveSsgOptions(ssg) {
9270
9294
  pagination: false,
9271
9295
  breadcrumbs: false,
9272
9296
  jsonLd: false,
9297
+ headValidation: false,
9273
9298
  readerChrome: false,
9274
9299
  localeSwitcher: false,
9275
9300
  a11y: false,
@@ -9298,6 +9323,7 @@ function resolveSsgOptions(ssg) {
9298
9323
  pagination: resolvePaginationOption(ssg.pagination),
9299
9324
  breadcrumbs: resolvePaginationOption(ssg.breadcrumbs),
9300
9325
  jsonLd: resolveJsonLdOption(ssg.jsonLd),
9326
+ headValidation: resolveHeadValidation(ssg.headValidation),
9301
9327
  readerChrome: resolveReaderChromeOption(ssg.readerChrome),
9302
9328
  localeSwitcher: resolveLocaleSwitcherOption(ssg.localeSwitcher),
9303
9329
  a11y: resolveA11yOption(ssg.a11y),
@@ -9329,7 +9355,9 @@ function resolveJsonLdOption(value) {
9329
9355
  const publisher = resolveJsonLdPublisher(value.publisher);
9330
9356
  return {
9331
9357
  breadcrumbs: value.breadcrumbs !== false,
9332
- ...publisher ? { publisher } : {}
9358
+ ...publisher ? { publisher } : {},
9359
+ ...value.type ? { type: value.type } : {},
9360
+ ...value.graph ? { graph: value.graph } : {}
9333
9361
  };
9334
9362
  }
9335
9363
  return false;
@@ -9472,7 +9500,7 @@ function localeCodesFor(locales) {
9472
9500
  async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, theme, locale, availableLocales, pagination = false, readerChrome = false, breadcrumbs = false, localeSwitcher = false, localePaths, a11y = false, team = {
9473
9501
  enabled: false,
9474
9502
  members: []
9475
- }, pageChrome = false, breadcrumbRootHref, jsonLd = false, siteUrl) {
9503
+ }, pageChrome = false, breadcrumbRootHref, jsonLd = false, siteUrl, headValidation = false) {
9476
9504
  const mod = await require_vitepress.importNapiModule();
9477
9505
  const tocForRust = pageData.toc.map(toRustTocEntry);
9478
9506
  const navGroupsForRust = convertNavGroupsForRust(navGroups);
@@ -9508,7 +9536,7 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
9508
9536
  linkText: f.linkText
9509
9537
  }))
9510
9538
  } : void 0;
9511
- return mod.generateSsgHtml({
9539
+ const result = mod.generateSsgHtml({
9512
9540
  title: pageData.title,
9513
9541
  description: pageData.description,
9514
9542
  content: pageData.content,
@@ -9521,12 +9549,16 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
9521
9549
  next: pageData.next,
9522
9550
  breadcrumbs: pageData.breadcrumbs,
9523
9551
  layout: typeof pageData.frontmatter.layout === "string" ? pageData.frontmatter.layout : void 0,
9524
- chrome: pageData.chrome
9552
+ chrome: pageData.chrome,
9553
+ robots: typeof pageData.frontmatter.robots === "string" ? pageData.frontmatter.robots : void 0,
9554
+ canonical: typeof pageData.frontmatter.canonical === "string" ? pageData.frontmatter.canonical : void 0
9525
9555
  }, navGroupsForRust, {
9526
9556
  siteName,
9527
9557
  base,
9528
9558
  breadcrumbRootHref,
9529
9559
  ogImage,
9560
+ siteUrl,
9561
+ headValidation: headValidation || void 0,
9530
9562
  theme: themeForRust,
9531
9563
  locale,
9532
9564
  availableLocales: availableLocales ? toRustLocales(availableLocales) : void 0,
@@ -9545,9 +9577,14 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
9545
9577
  jsonLd: jsonLd ? {
9546
9578
  breadcrumbs: jsonLd.breadcrumbs,
9547
9579
  publisher: jsonLd.publisher,
9548
- siteUrl
9580
+ siteUrl,
9581
+ pageType: jsonLd.type,
9582
+ graph: jsonLd.graph?.map((node) => JSON.stringify(node))
9549
9583
  } : void 0
9550
9584
  });
9585
+ const html = typeof result === "string" ? result : result.html;
9586
+ reportHeadDiagnostics(typeof result === "string" ? [] : result.diagnostics ?? [], headValidation);
9587
+ return html;
9551
9588
  }
9552
9589
  async function externalizeSharedPageAssets(pages, outDir, base) {
9553
9590
  const optimized = (await require_vitepress.importNapiModule()).externalizeSsgAssets(pages, outDir, base);
@@ -9990,7 +10027,7 @@ async function renderSsgPage(context, pageResult, collected, allPageResults) {
9990
10027
  return generateHtmlPage(pageData, navItems, context.siteName, context.base, pageOgImage, theme, locale, i18n ? i18n.locales : void 0, context.ssgOptions.pagination, context.ssgOptions.readerChrome, context.ssgOptions.breadcrumbs, context.ssgOptions.localeSwitcher, localePaths, context.ssgOptions.a11y, context.ssgOptions.team ?? {
9991
10028
  enabled: false,
9992
10029
  members: []
9993
- }, context.ssgOptions.pageChrome, versionNavigation?.root.href, context.ssgOptions.jsonLd, context.ssgOptions.siteUrl);
10030
+ }, context.ssgOptions.pageChrome, versionNavigation?.root.href, context.ssgOptions.jsonLd, context.ssgOptions.siteUrl, context.ssgOptions.headValidation);
9994
10031
  }
9995
10032
  function rewritePagerOverride(pager, context) {
9996
10033
  return pager?.href ? {
@@ -10451,7 +10488,7 @@ async function renderPage$1(filePath, options, navGroups, siteName, base, root,
10451
10488
  let html = await generateHtmlPage(pageData, localizedNav, siteName, base, options.ssg.ogImage, theme, locale, i18n ? i18n.locales : void 0, options.ssg.pagination, options.ssg.readerChrome, options.ssg.breadcrumbs, options.ssg.localeSwitcher, localePaths, options.ssg.a11y, options.ssg.team ?? {
10452
10489
  enabled: false,
10453
10490
  members: []
10454
- }, options.ssg.pageChrome, void 0, options.ssg.jsonLd, options.ssg.siteUrl);
10491
+ }, options.ssg.pageChrome, void 0, options.ssg.jsonLd, options.ssg.siteUrl, options.ssg.headValidation);
10455
10492
  html = injectViteHmrClient(html);
10456
10493
  return html;
10457
10494
  }
@@ -13073,6 +13110,7 @@ exports.prefetchOgpData = prefetchOgpData;
13073
13110
  exports.raw = require_jsx_html.raw;
13074
13111
  exports.readingTimeMinutes = readingTimeMinutes;
13075
13112
  exports.renderAllPages = renderAllPages;
13113
+ exports.renderHead = renderHead;
13076
13114
  exports.renderHtmlToFrameworkCode = renderHtmlToFrameworkCode;
13077
13115
  exports.renderHtmlToReactComponent = renderHtmlToReactComponent;
13078
13116
  exports.renderHtmlToReactCreateElement = renderHtmlToReactCreateElement;
@@ -13095,6 +13133,7 @@ exports.resolveDocsOptions = resolveDocsOptions;
13095
13133
  exports.resolveDocumentComponentImports = resolveDocumentComponentImports;
13096
13134
  exports.resolveFeedsOptions = resolveFeedsOptions;
13097
13135
  exports.resolveFileTreeOptions = resolveFileTreeOptions;
13136
+ exports.resolveHeadValidation = resolveHeadValidation;
13098
13137
  exports.resolveHeaderNavItems = require_vitepress.resolveHeaderNavItems;
13099
13138
  exports.resolveI18nOptions = resolveI18nOptions;
13100
13139
  exports.resolveImageOptions = resolveImageOptions;