@ox-content/vite-plugin 3.0.0-alpha.13 → 3.0.0-alpha.14
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 +172 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -15
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +74 -15
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +171 -16
- package/dist/index.mjs.map +1 -1
- package/dist/markdown-tables.cjs.map +1 -1
- package/dist/markdown-tables.mjs.map +1 -1
- package/dist/styles/core.css +16 -16
- package/dist/styles/markdown-tables.css +3 -1
- package/dist/styles/social.css +68 -15
- package/dist/styles/tabs.css +15 -15
- package/dist/theme-tokens.cjs +95 -0
- package/dist/theme-tokens.cjs.map +1 -0
- package/dist/theme-tokens.d.cts +75 -0
- package/dist/theme-tokens.d.cts.map +1 -0
- package/dist/theme-tokens.d.mts +75 -0
- package/dist/theme-tokens.d.mts.map +1 -0
- package/dist/theme-tokens.mjs +91 -0
- package/dist/theme-tokens.mjs.map +1 -0
- package/dist/vitepress.cjs +2 -31
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.mjs +2 -31
- package/dist/vitepress.mjs.map +1 -1
- package/package.json +13 -3
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_vitepress = require("./vitepress.cjs");
|
|
3
|
+
const require_theme_tokens = require("./theme-tokens.cjs");
|
|
3
4
|
const require_jsx_html = require("./jsx-html.cjs");
|
|
4
5
|
const require_markdown_tables = require("./markdown-tables.cjs");
|
|
5
6
|
let path = require("path");
|
|
@@ -686,8 +687,14 @@ let missingWarned = false;
|
|
|
686
687
|
/**
|
|
687
688
|
* Replaces rust `ox-math` placeholders with static KaTeX HTML.
|
|
688
689
|
* Leaves the escaped TeX fallback when `katex` is not installed.
|
|
690
|
+
*
|
|
691
|
+
* `onError` decides what a run KaTeX cannot parse becomes. Prose that
|
|
692
|
+
* quotes math syntax is picked up as math by the `$…$` heuristics, and the
|
|
693
|
+
* default — putting the source back the way it was written — keeps that
|
|
694
|
+
* page readable instead of stamping red error text into the middle of a
|
|
695
|
+
* sentence. Failures are collected either way, so the caller can warn.
|
|
689
696
|
*/
|
|
690
|
-
async function renderKatexMath(html) {
|
|
697
|
+
async function renderKatexMath(html, onError = "literal", failures) {
|
|
691
698
|
if (!html.includes("data-ox-tex")) return html;
|
|
692
699
|
const katex = loadKatex();
|
|
693
700
|
if (!katex) {
|
|
@@ -695,14 +702,39 @@ async function renderKatexMath(html) {
|
|
|
695
702
|
return html;
|
|
696
703
|
}
|
|
697
704
|
return html.replace(MATH_TAG, (_match, tag, kind, encoded) => {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
705
|
+
const block = kind === "block";
|
|
706
|
+
const tex = decodeHtmlAttr$3(encoded);
|
|
707
|
+
const options = {
|
|
708
|
+
displayMode: block,
|
|
701
709
|
trust: false,
|
|
702
710
|
output: "htmlAndMathml"
|
|
703
|
-
}
|
|
711
|
+
};
|
|
712
|
+
let rendered;
|
|
713
|
+
try {
|
|
714
|
+
rendered = katex.renderToString(tex, {
|
|
715
|
+
...options,
|
|
716
|
+
throwOnError: true
|
|
717
|
+
});
|
|
718
|
+
} catch (error) {
|
|
719
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
720
|
+
failures?.push({
|
|
721
|
+
tex,
|
|
722
|
+
block,
|
|
723
|
+
message
|
|
724
|
+
});
|
|
725
|
+
if (onError === "error") throw new Error(`${message} (in ${block ? "$$" : "$"}${tex}${block ? "$$" : "$"})`);
|
|
726
|
+
if (onError === "literal") return escapeHtmlText(block ? `$$${tex}$$` : `$${tex}$`);
|
|
727
|
+
rendered = katex.renderToString(tex, {
|
|
728
|
+
...options,
|
|
729
|
+
throwOnError: false
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
return `<${tag} class="ox-math ox-math-${kind}">${rendered}</${tag}>`;
|
|
704
733
|
});
|
|
705
734
|
}
|
|
735
|
+
function escapeHtmlText(value) {
|
|
736
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
737
|
+
}
|
|
706
738
|
/** Directory that contains `katex.min.css` and `fonts/`, or `null`. */
|
|
707
739
|
function resolveKatexDist() {
|
|
708
740
|
for (const resolver of createKatexResolvers()) try {
|
|
@@ -727,8 +759,34 @@ function createKatexResolvers() {
|
|
|
727
759
|
resolvers.push((0, node_module.createRequire)(require("url").pathToFileURL(__filename).href));
|
|
728
760
|
return resolvers;
|
|
729
761
|
}
|
|
762
|
+
const NAMED_ENTITIES$1 = {
|
|
763
|
+
amp: "&",
|
|
764
|
+
quot: "\"",
|
|
765
|
+
apos: "'",
|
|
766
|
+
lt: "<",
|
|
767
|
+
gt: ">",
|
|
768
|
+
nbsp: "\xA0"
|
|
769
|
+
};
|
|
770
|
+
/**
|
|
771
|
+
* Decodes the attribute back to the TeX the author wrote.
|
|
772
|
+
*
|
|
773
|
+
* The placeholder is escaped by Rust and re-serialized by the rehype passes
|
|
774
|
+
* that run before this one, and those two do not agree on a spelling — an
|
|
775
|
+
* apostrophe leaves Rust untouched and comes back from rehype as `'`.
|
|
776
|
+
* A general decoder covers whichever spelling arrives; chained `replaceAll`
|
|
777
|
+
* calls over a fixed list did not, and the leftover `'` reached KaTeX
|
|
778
|
+
* as five literal characters.
|
|
779
|
+
*
|
|
780
|
+
* One left-to-right pass, so `&lt;` decodes to `<` rather than `<`.
|
|
781
|
+
*/
|
|
730
782
|
function decodeHtmlAttr$3(value) {
|
|
731
|
-
return value.
|
|
783
|
+
return value.replace(/&(#[0-9]+|#[xX][0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (match, body) => {
|
|
784
|
+
if (body.startsWith("#")) {
|
|
785
|
+
const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
|
|
786
|
+
return Number.isFinite(code) && code >= 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
|
|
787
|
+
}
|
|
788
|
+
return NAMED_ENTITIES$1[body.toLowerCase()] ?? match;
|
|
789
|
+
});
|
|
732
790
|
}
|
|
733
791
|
function warnMissingKatexOnce() {
|
|
734
792
|
if (missingWarned) return;
|
|
@@ -1070,12 +1128,27 @@ function citationKeysFromMarkdown(markdown, options, diagnostics) {
|
|
|
1070
1128
|
for (const match of visibleMarkdown.matchAll(BRACKET_RE)) {
|
|
1071
1129
|
const body = (match[1] ?? "").trim();
|
|
1072
1130
|
if (!body.startsWith("@") && !body.startsWith("-@")) continue;
|
|
1131
|
+
if (isLinkLabel(visibleMarkdown, match)) continue;
|
|
1073
1132
|
const parsed = parseCitationGroup(body, options, diagnostics);
|
|
1074
1133
|
if (!parsed) continue;
|
|
1075
1134
|
keys.push(...parsed.map((citation) => citation.key));
|
|
1076
1135
|
}
|
|
1077
1136
|
return keys;
|
|
1078
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* A bracketed span that a destination or reference immediately follows is a
|
|
1140
|
+
* Markdown link label, not a citation group.
|
|
1141
|
+
*
|
|
1142
|
+
* The HTML pass never sees these — by then the label is inside an `<a>` and has
|
|
1143
|
+
* no brackets left — but the search-index pass reads the Markdown source, where
|
|
1144
|
+
* a linked scoped package name is indistinguishable from a citation by its
|
|
1145
|
+
* opening `@` alone. `[@ox-content/vite-plugin](./packages/vite-plugin.md)`
|
|
1146
|
+
* reported a malformed citation and failed the whole index.
|
|
1147
|
+
*/
|
|
1148
|
+
function isLinkLabel(markdown, match) {
|
|
1149
|
+
const end = (match.index ?? 0) + match[0].length;
|
|
1150
|
+
return markdown[end] === "(" || markdown[end] === "[";
|
|
1151
|
+
}
|
|
1079
1152
|
function stripMarkdownCitationProtectedText(markdown) {
|
|
1080
1153
|
return markdown.replace(/^([ \t]*)(`{3,}|~{3,})[^\n]*\n[\s\S]*?^\1\2[ \t]*$/gm, "").replace(/^(?: {4}|\t).+$/gm, "").replace(/<!--[\s\S]*?-->/g, "").replace(/<(pre|code|script|style|textarea|a)\b[\s\S]*?<\/\1>/gi, "").replace(/`+[^`\n]*`+/g, "");
|
|
1081
1154
|
}
|
|
@@ -6918,7 +6991,7 @@ async function transformMarkdown(source, filePath, options, ssgOptions) {
|
|
|
6918
6991
|
markdown: source,
|
|
6919
6992
|
replacements: /* @__PURE__ */ new Map()
|
|
6920
6993
|
};
|
|
6921
|
-
const
|
|
6994
|
+
const napiOptions = {
|
|
6922
6995
|
gfm: options.gfm,
|
|
6923
6996
|
mdx: resolveMdxForFilePath(filePath, options.mdx),
|
|
6924
6997
|
footnotes: options.footnotes,
|
|
@@ -7003,10 +7076,15 @@ async function transformMarkdown(source, filePath, options, ssgOptions) {
|
|
|
7003
7076
|
repoUrl: options.editThisPage.repoUrl,
|
|
7004
7077
|
branch: options.editThisPage.branch,
|
|
7005
7078
|
rootDir: options.editThisPage.rootDir,
|
|
7079
|
+
srcDir: ssgOptions?.srcDir,
|
|
7080
|
+
provider: options.editThisPage.provider,
|
|
7081
|
+
urlPattern: options.editThisPage.urlPattern,
|
|
7006
7082
|
label: options.editThisPage.label
|
|
7007
7083
|
} : void 0,
|
|
7008
7084
|
math: isMathEnabled(options.math)
|
|
7009
|
-
}
|
|
7085
|
+
};
|
|
7086
|
+
const transformers = options.transformers ?? [];
|
|
7087
|
+
const result = transformers.length ? await runTransformers(napi, graphviz.markdown, napiOptions, filePath, options, transformers) : napi.transform(graphviz.markdown, napiOptions);
|
|
7010
7088
|
if (result.errors.length > 0) console.warn("[ox-content] Transform warnings:", result.errors);
|
|
7011
7089
|
let html = normalizeSelfClosingEmbeds(restoreGraphvizPlaceholders(result.html, graphviz.replacements));
|
|
7012
7090
|
const frontmatter = parseFrontmatterJson(result.frontmatter);
|
|
@@ -7030,7 +7108,11 @@ async function transformMarkdown(source, filePath, options, ssgOptions) {
|
|
|
7030
7108
|
const citationResult = await transformCitations(html, options.citations);
|
|
7031
7109
|
html = citationResult.html;
|
|
7032
7110
|
if (options.sanitize?.enabled) html = napi.sanitizeHtml(html, toJsSanitizeOptions(options.sanitize));
|
|
7033
|
-
if (isMathEnabled(options.math))
|
|
7111
|
+
if (isMathEnabled(options.math)) {
|
|
7112
|
+
const failures = [];
|
|
7113
|
+
html = await renderKatexMath(html, options.math?.onError ?? "literal", failures);
|
|
7114
|
+
warnMathFailures(failures, filePath);
|
|
7115
|
+
}
|
|
7034
7116
|
html = await transformBudouxHtml(html, options.budoux);
|
|
7035
7117
|
const imports = result.imports ?? [];
|
|
7036
7118
|
const exports = result.exports ?? [];
|
|
@@ -7086,6 +7168,52 @@ function toJsSanitizeOptions(options) {
|
|
|
7086
7168
|
allowedUrlSchemes: options.allowedUrlSchemes
|
|
7087
7169
|
};
|
|
7088
7170
|
}
|
|
7171
|
+
/**
|
|
7172
|
+
* Runs the configured `transformers` over the parsed tree.
|
|
7173
|
+
*
|
|
7174
|
+
* Markdown never passes through Vite's `transform` hook — the native layer
|
|
7175
|
+
* reads it directly — so this is the only place user config can reach the
|
|
7176
|
+
* AST. The tree is handed over after frontmatter parsing and Markdown
|
|
7177
|
+
* feature expansion, and handed back for rendering, HTML postprocessing,
|
|
7178
|
+
* and sanitization, so a transformer costs a document nothing else.
|
|
7179
|
+
*
|
|
7180
|
+
* A transformer that throws, or returns something that is not a node, is
|
|
7181
|
+
* reported and skipped: one bad hook should not take the page down with it.
|
|
7182
|
+
*/
|
|
7183
|
+
async function runTransformers(napi, markdown, napiOptions, filePath, options, transformers) {
|
|
7184
|
+
const parsed = napi.transformMdast(markdown, napiOptions);
|
|
7185
|
+
if (!parsed.astJson) return {
|
|
7186
|
+
html: "",
|
|
7187
|
+
frontmatter: parsed.frontmatter,
|
|
7188
|
+
toc: [],
|
|
7189
|
+
errors: parsed.errors,
|
|
7190
|
+
imports: [],
|
|
7191
|
+
exports: [],
|
|
7192
|
+
components: []
|
|
7193
|
+
};
|
|
7194
|
+
const errors = [...parsed.errors];
|
|
7195
|
+
const context = {
|
|
7196
|
+
filePath,
|
|
7197
|
+
frontmatter: parseFrontmatterJson(parsed.frontmatter),
|
|
7198
|
+
options
|
|
7199
|
+
};
|
|
7200
|
+
let ast = JSON.parse(parsed.astJson);
|
|
7201
|
+
for (const transformer of transformers) try {
|
|
7202
|
+
const next = await transformer.transform(ast, context);
|
|
7203
|
+
if (!next || typeof next !== "object") {
|
|
7204
|
+
errors.push(`transformer "${transformer.name}" returned ${next === void 0 ? "undefined" : String(next)} instead of a node`);
|
|
7205
|
+
continue;
|
|
7206
|
+
}
|
|
7207
|
+
ast = next;
|
|
7208
|
+
} catch (error) {
|
|
7209
|
+
errors.push(`transformer "${transformer.name}" failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
7210
|
+
}
|
|
7211
|
+
const result = napi.transformFromMdast(JSON.stringify(ast), parsed.frontmatter, napiOptions);
|
|
7212
|
+
return {
|
|
7213
|
+
...result,
|
|
7214
|
+
errors: [...errors, ...result.errors]
|
|
7215
|
+
};
|
|
7216
|
+
}
|
|
7089
7217
|
function parseFrontmatterJson(json) {
|
|
7090
7218
|
if (!json) return {};
|
|
7091
7219
|
try {
|
|
@@ -7185,6 +7313,19 @@ if (import.meta.hot) {
|
|
|
7185
7313
|
}
|
|
7186
7314
|
`;
|
|
7187
7315
|
}
|
|
7316
|
+
/**
|
|
7317
|
+
* Reports every `$…$` run KaTeX refused.
|
|
7318
|
+
*
|
|
7319
|
+
* Under the default policy the page keeps its prose, which is the readable
|
|
7320
|
+
* outcome but also a silent one — a genuine mistake in a formula would
|
|
7321
|
+
* otherwise leave no trace at all.
|
|
7322
|
+
*/
|
|
7323
|
+
function warnMathFailures(failures, filePath) {
|
|
7324
|
+
for (const failure of failures) {
|
|
7325
|
+
const delimiter = failure.block ? "$$" : "$";
|
|
7326
|
+
console.warn(`[ox-content] ${filePath}: math left as written — ${failure.message} (in ${delimiter}${failure.tex}${delimiter})`);
|
|
7327
|
+
}
|
|
7328
|
+
}
|
|
7188
7329
|
function isMathEnabled(math) {
|
|
7189
7330
|
if (math === true) return true;
|
|
7190
7331
|
if (math === false || math == null) return false;
|
|
@@ -17007,7 +17148,8 @@ async function transformSsgPage(context, inputPath) {
|
|
|
17007
17148
|
const result = await transformMarkdown(content, inputPath, context.options, {
|
|
17008
17149
|
convertMdLinks: true,
|
|
17009
17150
|
baseUrl: publicBase(context.base, context.ssgOptions.routePrefix),
|
|
17010
|
-
sourcePath: inputPath
|
|
17151
|
+
sourcePath: inputPath,
|
|
17152
|
+
srcDir: context.srcDir
|
|
17011
17153
|
});
|
|
17012
17154
|
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(result.frontmatter);
|
|
17013
17155
|
const transformedHtml = await transformSsgHtml(result.html, context.options);
|
|
@@ -17296,7 +17438,8 @@ async function transformNotFoundMarkdown(context, inputPath, markdown) {
|
|
|
17296
17438
|
const result = await transformMarkdown(markdown, inputPath, context.options, {
|
|
17297
17439
|
convertMdLinks: true,
|
|
17298
17440
|
baseUrl: context.base,
|
|
17299
|
-
sourcePath: path.join(context.srcDir, "index.md")
|
|
17441
|
+
sourcePath: path.join(context.srcDir, "index.md"),
|
|
17442
|
+
srcDir: context.srcDir
|
|
17300
17443
|
});
|
|
17301
17444
|
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(result.frontmatter);
|
|
17302
17445
|
const transformedHtml = await transformSsgHtml(result.html, context.options);
|
|
@@ -17638,7 +17781,8 @@ async function renderPage$1(filePath, options, navGroups, siteName, base, root,
|
|
|
17638
17781
|
const result = await transformMarkdown(await fs_promises.readFile(filePath, "utf-8"), filePath, options, {
|
|
17639
17782
|
convertMdLinks: true,
|
|
17640
17783
|
baseUrl: base,
|
|
17641
|
-
sourcePath: filePath
|
|
17784
|
+
sourcePath: filePath,
|
|
17785
|
+
srcDir
|
|
17642
17786
|
});
|
|
17643
17787
|
const frontmatter = require_vitepress.normalizeVitePressFrontmatter(result.frontmatter);
|
|
17644
17788
|
let transformedHtml = result.html;
|
|
@@ -18594,9 +18738,18 @@ function resolveEmojiShortcodeOptions(options) {
|
|
|
18594
18738
|
};
|
|
18595
18739
|
}
|
|
18596
18740
|
function resolveMathOptions(options) {
|
|
18597
|
-
if (!options) return {
|
|
18598
|
-
|
|
18599
|
-
|
|
18741
|
+
if (!options) return {
|
|
18742
|
+
enabled: false,
|
|
18743
|
+
onError: "literal"
|
|
18744
|
+
};
|
|
18745
|
+
if (options === true) return {
|
|
18746
|
+
enabled: true,
|
|
18747
|
+
onError: "literal"
|
|
18748
|
+
};
|
|
18749
|
+
return {
|
|
18750
|
+
enabled: options.enabled ?? true,
|
|
18751
|
+
onError: options.onError ?? "literal"
|
|
18752
|
+
};
|
|
18600
18753
|
}
|
|
18601
18754
|
function resolveAttrsOptions(options) {
|
|
18602
18755
|
if (!options) return { enabled: false };
|
|
@@ -18673,6 +18826,8 @@ function resolveEditThisPageOptions(options) {
|
|
|
18673
18826
|
repoUrl: options.repoUrl,
|
|
18674
18827
|
branch: options.branch ?? "main",
|
|
18675
18828
|
rootDir: options.rootDir,
|
|
18829
|
+
provider: options.provider,
|
|
18830
|
+
urlPattern: options.urlPattern,
|
|
18676
18831
|
label: options.label ?? "Edit this page"
|
|
18677
18832
|
};
|
|
18678
18833
|
}
|
|
@@ -20882,6 +21037,7 @@ exports.renderIslandComponentImports = renderIslandComponentImports;
|
|
|
20882
21037
|
exports.renderMarkdown = renderMarkdown;
|
|
20883
21038
|
exports.renderMarkdownStream = renderMarkdownStream;
|
|
20884
21039
|
exports.renderPage = renderPage;
|
|
21040
|
+
exports.renderThemeTokenCss = require_theme_tokens.renderThemeTokenCss;
|
|
20885
21041
|
exports.renderToString = require_jsx_html.renderToString;
|
|
20886
21042
|
exports.resolveAbbreviationsOptions = resolveAbbreviationsOptions;
|
|
20887
21043
|
exports.resolveBadgeOptions = resolveBadgeOptions;
|
|
@@ -20939,6 +21095,7 @@ exports.setRenderContext = setRenderContext;
|
|
|
20939
21095
|
exports.shouldLintMarkdownFile = shouldLintMarkdownFile;
|
|
20940
21096
|
exports.stripMarkdownExtension = stripMarkdownExtension;
|
|
20941
21097
|
exports.stripViteQuery = stripViteQuery;
|
|
21098
|
+
exports.tokensToCss = require_theme_tokens.tokensToCss;
|
|
20942
21099
|
exports.transformAllPlugins = transformAllPlugins;
|
|
20943
21100
|
exports.transformBudouxHtml = transformBudouxHtml;
|
|
20944
21101
|
exports.transformGitHub = transformGitHub;
|