@temelj/mdx 0.12.0 → 0.14.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/compiler.d.mts +2 -2
- package/dist/compiler.d.mts.map +1 -1
- package/dist/compiler.mjs +7 -3
- package/dist/compiler.mjs.map +1 -1
- package/dist/mod.d.mts +3 -1
- package/dist/mod.mjs +2 -1
- package/dist/plugins/heading-id/plugin.d.mts +0 -1
- package/dist/plugins/heading-id/plugin.d.mts.map +1 -1
- package/dist/plugins/katex/plugin.d.mts +39 -0
- package/dist/plugins/katex/plugin.d.mts.map +1 -0
- package/dist/plugins/katex/plugin.mjs +107 -0
- package/dist/plugins/katex/plugin.mjs.map +1 -0
- package/dist/plugins/mod.d.mts +2 -1
- package/dist/plugins/mod.mjs +2 -1
- package/dist/plugins/remove-imports-exports.d.mts +0 -1
- package/dist/plugins/remove-imports-exports.d.mts.map +1 -1
- package/dist/plugins/syntax-highlight/code-meta.d.mts +0 -1
- package/dist/plugins/syntax-highlight/code-meta.d.mts.map +1 -1
- package/dist/plugins/syntax-highlight/code-meta.mjs.map +1 -1
- package/dist/plugins/syntax-highlight/plugin.d.mts +0 -1
- package/dist/plugins/syntax-highlight/plugin.d.mts.map +1 -1
- package/dist/plugins/syntax-highlight/plugin.mjs.map +1 -1
- package/dist/plugins/tree-processor/plugin.d.mts +2 -2
- package/dist/plugins/tree-processor/plugin.d.mts.map +1 -1
- package/package.json +13 -10
package/dist/compiler.d.mts
CHANGED
|
@@ -4,7 +4,6 @@ import remarkFrontmatterPlugin from "remark-frontmatter";
|
|
|
4
4
|
import remarkGfmPlugin from "remark-gfm";
|
|
5
5
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
6
|
import { Plugin } from "unified";
|
|
7
|
-
|
|
8
7
|
//#region src/compiler.d.ts
|
|
9
8
|
/**
|
|
10
9
|
* Represents the source content for an MDX document.
|
|
@@ -78,7 +77,8 @@ declare class MdxCompileError extends Error {
|
|
|
78
77
|
causeMessage?: string | undefined;
|
|
79
78
|
diagnostics?: MdxMessage[] | undefined;
|
|
80
79
|
cause?: unknown;
|
|
81
|
-
});
|
|
80
|
+
}, context?: Function);
|
|
81
|
+
static create(this: void, reason: string, options?: ConstructorParameters<typeof MdxCompileError>[1]): MdxCompileError;
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
84
|
* A reusable compiler for compiling MDX.
|
package/dist/compiler.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.mts","names":[],"sources":["../src/compiler.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"compiler.d.mts","names":[],"sources":["../src/compiler.ts"],"mappings":";;;;;;;;;;KAiBY,qBAAqB;;;;UAKhB;EACf;EACA,aAAa;;UAGE;EACf;EACA;EACA;;UAGe;EACf,QAAQ;EACR,MAAM;;UAGS;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;IACE;IACA;;;;;;;UAea,YAAY,eAAe;EAC1C;EACA,aAAa;EACb,UAAU;;cAGC,wBAAwB;WACnB;WACA;WACA;WACA;WACA;WACA,QAAQ;WACR;WACA;WACA;WACA;WACA,aAAa;EAE7B,YACE,gBACA;IACE;IACA;IACA;IACA;IACA,QAAQ;IACR;IACA;IACA;IACA;IACA;IACA,cAAc;IACd;KAEF,UAAU;SAmCL,OACL,YACA,gBACA,UAAS,6BAA6B,sBACrC;;;;;cAQQ;mBACM;mBACA;mBACA;EAEjB,YAAmB,aAAY;EAMxB,iBAAiB,UACtB,QAAQ,QAAQ,YAAY,MAAU,OACtC,UAAU,WACT;EASI,iBAAiB,UACtB,QAAQ,QAAQ,YAAY,MAAU,OACtC,UAAU,WACT;EASU,QACX,QAAQ,WACR,UAAU,oBACT,QAAQ,YAAY;EACV,QAAQ,2BAA2B,kBAC9C,QAAQ,WACR,SAAS,+BACT,mBAAmB,qBAClB,QAAQ,YAAY,iBAAiB,YAAY"}
|
package/dist/compiler.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import remarkGfmPlugin from "remark-gfm";
|
|
|
5
5
|
import { VFile } from "vfile";
|
|
6
6
|
import { matter } from "vfile-matter";
|
|
7
7
|
//#region src/compiler.ts
|
|
8
|
-
var MdxCompileError = class extends Error {
|
|
8
|
+
var MdxCompileError = class MdxCompileError extends Error {
|
|
9
9
|
reason;
|
|
10
10
|
source;
|
|
11
11
|
ruleId;
|
|
@@ -17,7 +17,7 @@ var MdxCompileError = class extends Error {
|
|
|
17
17
|
sourcePointer;
|
|
18
18
|
hint;
|
|
19
19
|
diagnostics;
|
|
20
|
-
constructor(reason, options = {}) {
|
|
20
|
+
constructor(reason, options = {}, context) {
|
|
21
21
|
super(formatDiagnosticMessage(reason, {
|
|
22
22
|
source: options.source,
|
|
23
23
|
ruleId: options.ruleId,
|
|
@@ -41,6 +41,10 @@ var MdxCompileError = class extends Error {
|
|
|
41
41
|
this.sourcePointer = options.sourcePointer;
|
|
42
42
|
this.hint = options.hint;
|
|
43
43
|
this.diagnostics = options.diagnostics ?? [];
|
|
44
|
+
if (Error.captureStackTrace !== void 0) Error.captureStackTrace(this, context ?? this.constructor);
|
|
45
|
+
}
|
|
46
|
+
static create(reason, options = {}) {
|
|
47
|
+
return new MdxCompileError(reason, options, MdxCompileError.create);
|
|
44
48
|
}
|
|
45
49
|
};
|
|
46
50
|
/**
|
|
@@ -107,7 +111,7 @@ var MdxCompiler = class {
|
|
|
107
111
|
function toMdxCompileError(error, sourceContext, diagnostics) {
|
|
108
112
|
const details = getDiagnosticDetails(sourceContext, getErrorPlace(error), error);
|
|
109
113
|
const cause = getErrorCause(error);
|
|
110
|
-
return
|
|
114
|
+
return MdxCompileError.create(getErrorReason(error), {
|
|
111
115
|
source: getErrorField(error, "source"),
|
|
112
116
|
ruleId: getErrorField(error, "ruleId"),
|
|
113
117
|
line: details.line,
|
package/dist/compiler.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.mjs","names":["compileMdxJs"],"sources":["../src/compiler.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { Pluggable, PluggableList, Plugin } from \"unified\";\n\nimport { compile as compileMdxJs, type CompileOptions as MdxJsCompileOptions } from \"@mdx-js/mdx\";\nimport { validateStandardSchema } from \"@temelj/standard-schema\";\nimport remarkFrontmatterPlugin from \"remark-frontmatter\";\nimport remarkGfmPlugin from \"remark-gfm\";\nimport { VFile } from \"vfile\";\nimport { matter } from \"vfile-matter\";\n\nimport type { HastNode } from \"./types\";\n\nexport { remarkFrontmatterPlugin, remarkGfmPlugin };\n\n/**\n * Represents the source content for an MDX document.\n */\nexport type MdxSource = string | Uint8Array;\n\n/**\n * Options for compiling an MDX document.\n */\nexport interface MdxCompileOptions {\n frontmatterOnly?: boolean | undefined;\n mdxOptions?: MdxJsCompileOptions;\n}\n\nexport interface MdxMessagePoint {\n line?: number | undefined;\n column?: number | undefined;\n offset?: number | undefined;\n}\n\nexport interface MdxMessagePlace {\n start?: MdxMessagePoint | undefined;\n end?: MdxMessagePoint | undefined;\n}\n\nexport interface MdxMessage {\n message: string;\n reason: string;\n source?: string | undefined;\n ruleId?: string | undefined;\n fatal?: boolean | undefined;\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n cause?: {\n name?: string | undefined;\n message: string;\n };\n}\n\ntype VFileLikeMessage = VFile[\"messages\"][number];\n\ninterface MdxDiagnosticSourceContext {\n originalSourceText: string;\n lineOffset: number;\n}\n\n/**\n * The result of compiling an MDX document.\n * Compiled content is optional, because sometimes we only need the frontmatter.\n */\nexport interface MdxArtifact<TFrontmatter = Record<string, unknown>> {\n compiled?: string | undefined;\n frontmatter: TFrontmatter;\n messages: MdxMessage[];\n}\n\nexport class MdxCompileError extends Error {\n public readonly reason: string;\n public readonly source?: string | undefined;\n public readonly ruleId?: string | undefined;\n public readonly line?: number | undefined;\n public readonly column?: number | undefined;\n public readonly place?: MdxMessagePlace | undefined;\n public readonly sourceLine?: string | undefined;\n public readonly snippet?: string | undefined;\n public readonly sourcePointer?: string | undefined;\n public readonly hint?: string | undefined;\n public readonly diagnostics: MdxMessage[];\n\n public constructor(\n reason: string,\n options: {\n source?: string | undefined;\n ruleId?: string | undefined;\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n causeMessage?: string | undefined;\n diagnostics?: MdxMessage[] | undefined;\n cause?: unknown;\n } = {},\n ) {\n super(\n formatDiagnosticMessage(reason, {\n source: options.source,\n ruleId: options.ruleId,\n line: options.line,\n column: options.column,\n sourceLine: options.sourceLine,\n snippet: options.snippet,\n sourcePointer: options.sourcePointer,\n hint: options.hint,\n causeMessage: options.causeMessage,\n }),\n options.cause === undefined ? undefined : { cause: options.cause },\n );\n\n this.name = \"MdxCompileError\";\n this.reason = reason;\n this.source = options.source;\n this.ruleId = options.ruleId;\n this.line = options.line;\n this.column = options.column;\n this.place = options.place;\n this.sourceLine = options.sourceLine;\n this.snippet = options.snippet;\n this.sourcePointer = options.sourcePointer;\n this.hint = options.hint;\n this.diagnostics = options.diagnostics ?? [];\n }\n}\n\n/**\n * A reusable compiler for compiling MDX.\n */\nexport class MdxCompiler {\n private readonly mdxOptions: MdxJsCompileOptions;\n private readonly remarkPlugins: PluggableList;\n private readonly rehypePlugins: PluggableList;\n\n public constructor(mdxOptions: MdxJsCompileOptions = {}) {\n this.mdxOptions = mdxOptions;\n this.remarkPlugins = [remarkFrontmatterPlugin, remarkGfmPlugin];\n this.rehypePlugins = [];\n }\n\n public withRemarkPlugin<TOptions>(\n plugin: Plugin<[TOptions?], HastNode, HastNode>,\n options?: TOptions,\n ): MdxCompiler {\n if (options === undefined) {\n this.remarkPlugins.push(plugin as Pluggable);\n } else {\n this.remarkPlugins.push([plugin, options] as Pluggable);\n }\n return this;\n }\n\n public withRehypePlugin<TOptions>(\n plugin: Plugin<[TOptions?], HastNode, HastNode>,\n options?: TOptions,\n ): MdxCompiler {\n if (options === undefined) {\n this.rehypePlugins.push(plugin as Pluggable);\n } else {\n this.rehypePlugins.push([plugin, options] as Pluggable);\n }\n return this;\n }\n\n public async compile(\n source: MdxSource,\n options?: MdxCompileOptions,\n ): Promise<MdxArtifact<Record<string, unknown>>>;\n public async compile<TFrontmatterSchema extends StandardSchemaV1>(\n source: MdxSource,\n options: MdxCompileOptions | undefined,\n frontmatterSchema: TFrontmatterSchema,\n ): Promise<MdxArtifact<StandardSchemaV1.InferOutput<TFrontmatterSchema>>>;\n public async compile<TFrontmatterSchema extends StandardSchemaV1>(\n source: MdxSource,\n { frontmatterOnly = false, mdxOptions }: MdxCompileOptions = {},\n frontmatterSchema?: TFrontmatterSchema,\n ): Promise<\n MdxArtifact<\n TFrontmatterSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TFrontmatterSchema>\n : Record<string, unknown>\n >\n > {\n const sourceText = toSourceText(source);\n const vfile = new VFile({\n value: source,\n // Needed so vfile doesn't need to access fs.\n cwd: \"/\",\n path: \"/source.mdx\",\n });\n matter(vfile, { strip: true });\n const compileSourceText = toSourceText(vfile.value as MdxSource);\n const sourceContext = createDiagnosticSourceContext(sourceText, compileSourceText);\n\n const remarkPlugins = [\n ...this.remarkPlugins,\n ...(this.mdxOptions?.remarkPlugins ?? []),\n ...(mdxOptions?.remarkPlugins ?? []),\n ];\n const rehypePlugins = [\n ...this.rehypePlugins,\n ...(this.mdxOptions?.rehypePlugins ?? []),\n ...(mdxOptions?.rehypePlugins ?? []),\n ];\n\n let compiled: string | undefined;\n if (!frontmatterOnly) {\n try {\n const compiledFile = await compileMdxJs(vfile, {\n outputFormat: \"function-body\",\n ...this.mdxOptions,\n ...mdxOptions,\n remarkPlugins,\n rehypePlugins,\n });\n compiled = compiledFile.value.toString();\n } catch (error) {\n throw toMdxCompileError(error, sourceContext, vfile.messages);\n }\n }\n\n const frontmatter =\n frontmatterSchema === undefined\n ? (vfile.data.matter ?? {})\n : await validateStandardSchema(\n frontmatterSchema,\n vfile.data.matter ?? {},\n \"Frontmatter validation failed\",\n );\n\n return {\n compiled,\n frontmatter: frontmatter as TFrontmatterSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TFrontmatterSchema>\n : Record<string, unknown>,\n messages: normalizeMessages(vfile.messages, sourceContext),\n };\n }\n}\n\nfunction toMdxCompileError(\n error: unknown,\n sourceContext: MdxDiagnosticSourceContext,\n diagnostics: readonly VFileLikeMessage[],\n): MdxCompileError {\n const details = getDiagnosticDetails(sourceContext, getErrorPlace(error), error);\n const cause = getErrorCause(error);\n\n return new MdxCompileError(getErrorReason(error), {\n source: getErrorField(error, \"source\"),\n ruleId: getErrorField(error, \"ruleId\"),\n line: details.line,\n column: details.column,\n place: details.place,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n causeMessage: cause?.message,\n diagnostics: normalizeMessages(diagnostics, sourceContext),\n cause: error,\n });\n}\n\nfunction normalizeMessages(\n messages: readonly VFileLikeMessage[],\n sourceContext: MdxDiagnosticSourceContext,\n): MdxMessage[] {\n return messages.map((message) => {\n const details = getDiagnosticDetails(sourceContext, toMessagePlace(message), message);\n const reason = getErrorReason(message);\n const source = getErrorField(message, \"source\");\n const ruleId = getErrorField(message, \"ruleId\");\n const cause = getErrorCause(message);\n\n return {\n message: formatDiagnosticMessage(reason, {\n source,\n ruleId,\n line: details.line,\n column: details.column,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n causeMessage: cause?.message,\n }),\n reason,\n source,\n ruleId,\n fatal: typeof message.fatal === \"boolean\" ? message.fatal : undefined,\n line: details.line,\n column: details.column,\n place: details.place,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n cause,\n };\n });\n}\n\nfunction formatDiagnosticMessage(\n reason: string,\n options: {\n source?: string | undefined;\n ruleId?: string | undefined;\n line?: number | undefined;\n column?: number | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n causeMessage?: string | undefined;\n },\n): string {\n const origin =\n options.source === undefined\n ? undefined\n : options.ruleId === undefined\n ? options.source\n : `${options.source}:${options.ruleId}`;\n const location =\n options.line === undefined\n ? undefined\n : options.column === undefined\n ? `at ${options.line}`\n : `at ${options.line}:${options.column}`;\n\n const lines = [[reason, origin, location].filter(Boolean).join(\" \")];\n\n if (options.snippet !== undefined) {\n lines.push(`Source: ${options.snippet}`);\n }\n if (options.sourceLine !== undefined && options.sourceLine !== options.snippet) {\n lines.push(`Line: ${options.sourceLine}`);\n if (options.sourcePointer !== undefined) {\n lines.push(` ${options.sourcePointer}`);\n }\n }\n if (\n options.causeMessage !== undefined &&\n options.causeMessage !== \"\" &&\n options.causeMessage !== reason\n ) {\n lines.push(`Cause: ${options.causeMessage}`);\n }\n if (options.hint !== undefined) {\n lines.push(`Hint: ${options.hint}`);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction getDiagnosticDetails(\n sourceContext: MdxDiagnosticSourceContext,\n place: MdxMessagePlace | undefined,\n error: unknown,\n): {\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n} {\n const compileLine = place?.start?.line ?? getErrorNumberField(error, \"line\");\n let line = compileLine === undefined ? undefined : compileLine + sourceContext.lineOffset;\n let column = place?.start?.column ?? getErrorNumberField(error, \"column\");\n let normalizedPlace = mapPlaceToOriginalSource(\n place === undefined && compileLine === undefined && column === undefined\n ? undefined\n : {\n start: {\n line: compileLine,\n column,\n offset: place?.start?.offset,\n },\n end:\n place?.end === undefined\n ? undefined\n : {\n line: place.end.line,\n column: place.end.column,\n offset: place.end.offset,\n },\n },\n sourceContext.lineOffset,\n );\n let sourceLine = getSourceLine(sourceContext.originalSourceText, line);\n let snippet = getSourceSnippet(sourceContext.originalSourceText, normalizedPlace);\n let sourcePointer = getSourcePointer(column);\n let hint: string | undefined;\n\n const refinedExpressionContext = getMdxExpressionContext(sourceContext.originalSourceText, {\n line,\n column,\n sourceLine,\n snippet,\n error,\n });\n\n if (refinedExpressionContext !== undefined) {\n line = refinedExpressionContext.line;\n column = refinedExpressionContext.column;\n sourceLine = refinedExpressionContext.sourceLine;\n snippet = refinedExpressionContext.snippet;\n sourcePointer = refinedExpressionContext.sourcePointer;\n hint = refinedExpressionContext.hint;\n normalizedPlace = {\n start: {\n line,\n column,\n offset: undefined,\n },\n end: undefined,\n };\n }\n\n return {\n line,\n column,\n place: normalizedPlace,\n sourceLine,\n snippet,\n sourcePointer,\n hint,\n };\n}\n\nfunction getMdxExpressionContext(\n sourceText: string,\n options: {\n line?: number | undefined;\n column?: number | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n error: unknown;\n },\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n sourcePointer: string;\n hint?: string | undefined;\n }\n | undefined {\n if (!shouldRefineMdxExpressionContext(options)) {\n return undefined;\n }\n\n const candidate = findSuspiciousBraceExpression(sourceText, options.line, options.column);\n if (candidate === undefined) {\n return undefined;\n }\n\n return {\n line: candidate.line,\n column: candidate.column,\n sourceLine: candidate.sourceLine,\n snippet: candidate.snippet,\n sourcePointer: getSourcePointer(candidate.column) ?? \"^\",\n hint:\n getErrorCause(options.error)?.message === \"Unexpected content after expression\"\n ? \"MDX treats `{...}` as JavaScript. If you meant literal braces in text, escape them or wrap the text in code.\"\n : undefined,\n };\n}\n\nfunction shouldRefineMdxExpressionContext(options: {\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n error: unknown;\n}): boolean {\n const trimmedSourceLine = options.sourceLine?.trim();\n\n return (\n isMdxExpressionError(options.error) &&\n getErrorCause(options.error)?.message === \"Unexpected content after expression\" &&\n (options.sourceLine === undefined ||\n options.sourceLine.trim() === \"\" ||\n options.snippet === undefined) &&\n !(trimmedSourceLine?.startsWith(\"{\") && trimmedSourceLine.endsWith(\"}\"))\n );\n}\n\nfunction getSourceLine(sourceText: string, line: number | undefined): string | undefined {\n if (line === undefined || line < 1) {\n return undefined;\n }\n return sourceText.split(/\\r?\\n/u)[line - 1];\n}\n\nfunction getSourceSnippet(\n sourceText: string,\n place: MdxMessagePlace | undefined,\n): string | undefined {\n if (place?.start?.offset !== undefined && place.end?.offset !== undefined) {\n return sourceText.slice(place.start.offset, place.end.offset) || undefined;\n }\n\n if (place?.start?.line === undefined || place.start.column === undefined) {\n return undefined;\n }\n\n if (place.end === undefined) {\n const lines = sourceText.split(/\\r?\\n/u);\n const line = lines[place.start.line - 1];\n if (line === undefined) {\n return undefined;\n }\n\n const character = line.at(place.start.column - 1);\n return character === undefined || character.trim() === \"\" ? undefined : character;\n }\n\n const lines = sourceText.split(/\\r?\\n/u);\n const startLineIndex = place.start.line - 1;\n const endLineIndex = (place.end?.line ?? place.start.line) - 1;\n\n if (startLineIndex < 0 || startLineIndex >= lines.length) {\n return undefined;\n }\n\n const selectedLines = lines.slice(startLineIndex, endLineIndex + 1);\n if (selectedLines.length === 0) {\n return undefined;\n }\n\n selectedLines[0] = selectedLines[0].slice(place.start.column - 1);\n\n const endColumn = place.end?.column;\n if (endColumn !== undefined) {\n const lastIndex = selectedLines.length - 1;\n selectedLines[lastIndex] = selectedLines[lastIndex].slice(0, endColumn - 1);\n }\n\n return selectedLines.join(\"\\n\") || undefined;\n}\n\nfunction getSourcePointer(column: number | undefined): string | undefined {\n if (column === undefined || column < 1) {\n return undefined;\n }\n\n return `${\" \".repeat(column - 1)}^`;\n}\n\nfunction mapPlaceToOriginalSource(\n place: MdxMessagePlace | undefined,\n lineOffset: number,\n): MdxMessagePlace | undefined {\n if (place === undefined) {\n return undefined;\n }\n\n return {\n start: mapPointToOriginalSource(place.start, lineOffset),\n end: mapPointToOriginalSource(place.end, lineOffset),\n };\n}\n\nfunction mapPointToOriginalSource(\n point: MdxMessagePoint | undefined,\n lineOffset: number,\n): MdxMessagePoint | undefined {\n if (point === undefined) {\n return undefined;\n }\n\n return {\n line: point.line === undefined ? undefined : point.line + lineOffset,\n column: point.column,\n offset: lineOffset === 0 ? point.offset : undefined,\n };\n}\n\nfunction findSuspiciousBraceExpression(\n sourceText: string,\n line: number | undefined,\n column: number | undefined,\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n }\n | undefined {\n const lines = sourceText.split(/\\r?\\n/u);\n const searchLines = getNearbyLineNumbers(line, lines.length, 2);\n let bestMatch:\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n score: number;\n }\n | undefined;\n\n for (const lineNumber of searchLines) {\n const sourceLine = lines[lineNumber - 1];\n if (sourceLine === undefined || sourceLine.trim() === \"\") {\n continue;\n }\n\n const expression = findLineBraceExpression(sourceLine, lineNumber, column);\n if (expression === undefined) {\n continue;\n }\n\n const lineDistance = line === undefined ? 0 : Math.abs(lineNumber - line);\n const score = lineDistance * 10 + expression.distance;\n\n if (bestMatch === undefined || score < bestMatch.score) {\n bestMatch = {\n ...expression,\n score,\n };\n }\n }\n\n return bestMatch;\n}\n\nfunction getNearbyLineNumbers(\n line: number | undefined,\n totalLines: number,\n radius: number,\n): number[] {\n if (line === undefined) {\n return Array.from({ length: totalLines }, (_, index) => index + 1);\n }\n\n const lineNumbers: number[] = [];\n for (let distance = 0; distance <= radius; distance++) {\n const before = line - distance;\n if (before >= 1) {\n lineNumbers.push(before);\n }\n\n if (distance === 0) {\n continue;\n }\n\n const after = line + distance;\n if (after <= totalLines) {\n lineNumbers.push(after);\n }\n }\n\n return lineNumbers;\n}\n\nfunction findLineBraceExpression(\n sourceLine: string,\n line: number,\n column: number | undefined,\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n distance: number;\n }\n | undefined {\n let bestMatch:\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n distance: number;\n }\n | undefined;\n\n for (const match of sourceLine.matchAll(/\\{[^{}\\n]+\\}/gu)) {\n const braceStart = match.index;\n if (braceStart === undefined) {\n continue;\n }\n\n const expanded = expandBraceExpression(sourceLine, braceStart);\n if (expanded === undefined) {\n continue;\n }\n\n const distance = column === undefined ? 0 : Math.abs(braceStart + 1 - column);\n if (bestMatch === undefined || distance < bestMatch.distance) {\n bestMatch = {\n line,\n column: braceStart + 1,\n sourceLine,\n snippet: expanded,\n distance,\n };\n }\n }\n\n return bestMatch;\n}\n\nfunction expandBraceExpression(sourceLine: string, braceStart: number): string | undefined {\n const braceEnd = sourceLine.indexOf(\"}\", braceStart);\n if (braceEnd === -1) {\n return undefined;\n }\n\n let start = braceStart;\n while (start > 0 && /[A-Za-z0-9_]/u.test(sourceLine[start - 1])) {\n start--;\n }\n\n let end = braceEnd + 1;\n while (end < sourceLine.length) {\n while (end < sourceLine.length && /[A-Za-z0-9_]/u.test(sourceLine[end])) {\n end++;\n }\n\n if (sourceLine[end] !== \"{\") {\n break;\n }\n\n const chainedEnd = sourceLine.indexOf(\"}\", end);\n if (chainedEnd === -1) {\n break;\n }\n end = chainedEnd + 1;\n }\n\n return sourceLine.slice(start, end) || undefined;\n}\n\nfunction isMdxExpressionError(error: unknown): boolean {\n return (\n getErrorField(error, \"source\") === \"micromark-extension-mdx-expression\" &&\n getErrorField(error, \"ruleId\") === \"acorn\"\n );\n}\n\nfunction createDiagnosticSourceContext(\n originalSourceText: string,\n compileSourceText: string,\n): MdxDiagnosticSourceContext {\n return {\n originalSourceText,\n lineOffset: getSourceLineOffset(originalSourceText, compileSourceText),\n };\n}\n\nfunction getSourceLineOffset(originalSourceText: string, compileSourceText: string): number {\n const originalLines = originalSourceText.split(/\\r?\\n/u);\n const compileLines = compileSourceText.split(/\\r?\\n/u);\n const maxOffset = originalLines.length - compileLines.length;\n\n for (let offset = 0; offset <= maxOffset; offset++) {\n let isMatch = true;\n for (let index = 0; index < compileLines.length; index++) {\n if (originalLines[offset + index] !== compileLines[index]) {\n isMatch = false;\n break;\n }\n }\n\n if (isMatch) {\n return offset;\n }\n }\n\n return maxOffset > 0 ? maxOffset : 0;\n}\n\nfunction getErrorPlace(error: unknown): MdxMessagePlace | undefined {\n if (typeof error !== \"object\" || error === null) {\n return undefined;\n }\n\n const candidate = error as {\n place?: unknown;\n position?: unknown;\n };\n\n return toPlace(candidate.place) ?? toPlace(candidate.position);\n}\n\nfunction toMessagePlace(message: VFileLikeMessage): MdxMessagePlace | undefined {\n return toPlace(message.place);\n}\n\nfunction toPlace(value: unknown): MdxMessagePlace | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const candidate = value as {\n start?: unknown;\n end?: unknown;\n line?: unknown;\n column?: unknown;\n offset?: unknown;\n };\n\n if (candidate.start !== undefined || candidate.end !== undefined) {\n return {\n start: toPoint(candidate.start),\n end: toPoint(candidate.end),\n };\n }\n\n const point = toPoint(candidate);\n return point === undefined ? undefined : { start: point };\n}\n\nfunction toPoint(value: unknown): MdxMessagePoint | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const candidate = value as {\n line?: unknown;\n column?: unknown;\n offset?: unknown;\n };\n const line = typeof candidate.line === \"number\" ? candidate.line : undefined;\n const column = typeof candidate.column === \"number\" ? candidate.column : undefined;\n const offset = typeof candidate.offset === \"number\" ? candidate.offset : undefined;\n\n if (line === undefined && column === undefined && offset === undefined) {\n return undefined;\n }\n\n return { line, column, offset };\n}\n\nfunction getErrorReason(error: unknown): string {\n if (error instanceof Error && error.message !== \"\") {\n return error.message;\n }\n\n const reason = getErrorField(error, \"reason\");\n if (reason !== undefined && reason !== \"\") {\n return reason;\n }\n\n return String(error);\n}\n\nfunction getErrorCause(error: unknown): { name?: string | undefined; message: string } | undefined {\n if (typeof error !== \"object\" || error === null || !(\"cause\" in error)) {\n return undefined;\n }\n\n const cause = (error as { cause?: unknown }).cause;\n if (cause instanceof Error) {\n return {\n name: cause.name,\n message: cause.message,\n };\n }\n if (typeof cause === \"string\" && cause !== \"\") {\n return {\n message: cause,\n };\n }\n\n return undefined;\n}\n\nfunction getErrorField(error: unknown, field: \"source\" | \"ruleId\" | \"reason\"): string | undefined {\n if (typeof error !== \"object\" || error === null || !(field in error)) {\n return undefined;\n }\n\n const value = (error as Record<string, unknown>)[field];\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\nfunction getErrorNumberField(error: unknown, field: \"line\" | \"column\"): number | undefined {\n if (typeof error !== \"object\" || error === null || !(field in error)) {\n return undefined;\n }\n\n const value = (error as Record<string, unknown>)[field];\n return typeof value === \"number\" ? value : undefined;\n}\n\nfunction toSourceText(source: MdxSource): string {\n return typeof source === \"string\" ? source : new TextDecoder().decode(source);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compiler.mjs","names":["compileMdxJs"],"sources":["../src/compiler.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { Pluggable, PluggableList, Plugin } from \"unified\";\n\nimport { compile as compileMdxJs, type CompileOptions as MdxJsCompileOptions } from \"@mdx-js/mdx\";\nimport { validateStandardSchema } from \"@temelj/standard-schema\";\nimport remarkFrontmatterPlugin from \"remark-frontmatter\";\nimport remarkGfmPlugin from \"remark-gfm\";\nimport { VFile } from \"vfile\";\nimport { matter } from \"vfile-matter\";\n\nimport type { HastNode } from \"./types\";\n\nexport { remarkFrontmatterPlugin, remarkGfmPlugin };\n\n/**\n * Represents the source content for an MDX document.\n */\nexport type MdxSource = string | Uint8Array;\n\n/**\n * Options for compiling an MDX document.\n */\nexport interface MdxCompileOptions {\n frontmatterOnly?: boolean | undefined;\n mdxOptions?: MdxJsCompileOptions;\n}\n\nexport interface MdxMessagePoint {\n line?: number | undefined;\n column?: number | undefined;\n offset?: number | undefined;\n}\n\nexport interface MdxMessagePlace {\n start?: MdxMessagePoint | undefined;\n end?: MdxMessagePoint | undefined;\n}\n\nexport interface MdxMessage {\n message: string;\n reason: string;\n source?: string | undefined;\n ruleId?: string | undefined;\n fatal?: boolean | undefined;\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n cause?: {\n name?: string | undefined;\n message: string;\n };\n}\n\ntype VFileLikeMessage = VFile[\"messages\"][number];\n\ninterface MdxDiagnosticSourceContext {\n originalSourceText: string;\n lineOffset: number;\n}\n\n/**\n * The result of compiling an MDX document.\n * Compiled content is optional, because sometimes we only need the frontmatter.\n */\nexport interface MdxArtifact<TFrontmatter = Record<string, unknown>> {\n compiled?: string | undefined;\n frontmatter: TFrontmatter;\n messages: MdxMessage[];\n}\n\nexport class MdxCompileError extends Error {\n public readonly reason: string;\n public readonly source?: string | undefined;\n public readonly ruleId?: string | undefined;\n public readonly line?: number | undefined;\n public readonly column?: number | undefined;\n public readonly place?: MdxMessagePlace | undefined;\n public readonly sourceLine?: string | undefined;\n public readonly snippet?: string | undefined;\n public readonly sourcePointer?: string | undefined;\n public readonly hint?: string | undefined;\n public readonly diagnostics: MdxMessage[];\n\n public constructor(\n reason: string,\n options: {\n source?: string | undefined;\n ruleId?: string | undefined;\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n causeMessage?: string | undefined;\n diagnostics?: MdxMessage[] | undefined;\n cause?: unknown;\n } = {},\n context?: Function,\n ) {\n super(\n formatDiagnosticMessage(reason, {\n source: options.source,\n ruleId: options.ruleId,\n line: options.line,\n column: options.column,\n sourceLine: options.sourceLine,\n snippet: options.snippet,\n sourcePointer: options.sourcePointer,\n hint: options.hint,\n causeMessage: options.causeMessage,\n }),\n options.cause === undefined ? undefined : { cause: options.cause },\n );\n\n this.name = \"MdxCompileError\";\n this.reason = reason;\n this.source = options.source;\n this.ruleId = options.ruleId;\n this.line = options.line;\n this.column = options.column;\n this.place = options.place;\n this.sourceLine = options.sourceLine;\n this.snippet = options.snippet;\n this.sourcePointer = options.sourcePointer;\n this.hint = options.hint;\n this.diagnostics = options.diagnostics ?? [];\n\n if (Error.captureStackTrace !== undefined) {\n Error.captureStackTrace(this, context ?? this.constructor);\n }\n }\n\n static create(\n this: void,\n reason: string,\n options: ConstructorParameters<typeof MdxCompileError>[1] = {},\n ): MdxCompileError {\n return new MdxCompileError(reason, options, MdxCompileError.create);\n }\n}\n\n/**\n * A reusable compiler for compiling MDX.\n */\nexport class MdxCompiler {\n private readonly mdxOptions: MdxJsCompileOptions;\n private readonly remarkPlugins: PluggableList;\n private readonly rehypePlugins: PluggableList;\n\n public constructor(mdxOptions: MdxJsCompileOptions = {}) {\n this.mdxOptions = mdxOptions;\n this.remarkPlugins = [remarkFrontmatterPlugin, remarkGfmPlugin];\n this.rehypePlugins = [];\n }\n\n public withRemarkPlugin<TOptions>(\n plugin: Plugin<[TOptions?], HastNode, HastNode>,\n options?: TOptions,\n ): MdxCompiler {\n if (options === undefined) {\n this.remarkPlugins.push(plugin as Pluggable);\n } else {\n this.remarkPlugins.push([plugin, options] as Pluggable);\n }\n return this;\n }\n\n public withRehypePlugin<TOptions>(\n plugin: Plugin<[TOptions?], HastNode, HastNode>,\n options?: TOptions,\n ): MdxCompiler {\n if (options === undefined) {\n this.rehypePlugins.push(plugin as Pluggable);\n } else {\n this.rehypePlugins.push([plugin, options] as Pluggable);\n }\n return this;\n }\n\n public async compile(\n source: MdxSource,\n options?: MdxCompileOptions,\n ): Promise<MdxArtifact<Record<string, unknown>>>;\n public async compile<TFrontmatterSchema extends StandardSchemaV1>(\n source: MdxSource,\n options: MdxCompileOptions | undefined,\n frontmatterSchema: TFrontmatterSchema,\n ): Promise<MdxArtifact<StandardSchemaV1.InferOutput<TFrontmatterSchema>>>;\n public async compile<TFrontmatterSchema extends StandardSchemaV1>(\n source: MdxSource,\n { frontmatterOnly = false, mdxOptions }: MdxCompileOptions = {},\n frontmatterSchema?: TFrontmatterSchema,\n ): Promise<\n MdxArtifact<\n TFrontmatterSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TFrontmatterSchema>\n : Record<string, unknown>\n >\n > {\n const sourceText = toSourceText(source);\n const vfile = new VFile({\n value: source,\n // Needed so vfile doesn't need to access fs.\n cwd: \"/\",\n path: \"/source.mdx\",\n });\n matter(vfile, { strip: true });\n const compileSourceText = toSourceText(vfile.value as MdxSource);\n const sourceContext = createDiagnosticSourceContext(sourceText, compileSourceText);\n\n const remarkPlugins = [\n ...this.remarkPlugins,\n ...(this.mdxOptions?.remarkPlugins ?? []),\n ...(mdxOptions?.remarkPlugins ?? []),\n ];\n const rehypePlugins = [\n ...this.rehypePlugins,\n ...(this.mdxOptions?.rehypePlugins ?? []),\n ...(mdxOptions?.rehypePlugins ?? []),\n ];\n\n let compiled: string | undefined;\n if (!frontmatterOnly) {\n try {\n const compiledFile = await compileMdxJs(vfile, {\n outputFormat: \"function-body\",\n ...this.mdxOptions,\n ...mdxOptions,\n remarkPlugins,\n rehypePlugins,\n });\n compiled = compiledFile.value.toString();\n } catch (error) {\n throw toMdxCompileError(error, sourceContext, vfile.messages);\n }\n }\n\n const frontmatter =\n frontmatterSchema === undefined\n ? (vfile.data.matter ?? {})\n : await validateStandardSchema(\n frontmatterSchema,\n vfile.data.matter ?? {},\n \"Frontmatter validation failed\",\n );\n\n return {\n compiled,\n frontmatter: frontmatter as TFrontmatterSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TFrontmatterSchema>\n : Record<string, unknown>,\n messages: normalizeMessages(vfile.messages, sourceContext),\n };\n }\n}\n\nfunction toMdxCompileError(\n error: unknown,\n sourceContext: MdxDiagnosticSourceContext,\n diagnostics: readonly VFileLikeMessage[],\n): MdxCompileError {\n const details = getDiagnosticDetails(sourceContext, getErrorPlace(error), error);\n const cause = getErrorCause(error);\n\n return MdxCompileError.create(getErrorReason(error), {\n source: getErrorField(error, \"source\"),\n ruleId: getErrorField(error, \"ruleId\"),\n line: details.line,\n column: details.column,\n place: details.place,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n causeMessage: cause?.message,\n diagnostics: normalizeMessages(diagnostics, sourceContext),\n cause: error,\n });\n}\n\nfunction normalizeMessages(\n messages: readonly VFileLikeMessage[],\n sourceContext: MdxDiagnosticSourceContext,\n): MdxMessage[] {\n return messages.map((message) => {\n const details = getDiagnosticDetails(sourceContext, toMessagePlace(message), message);\n const reason = getErrorReason(message);\n const source = getErrorField(message, \"source\");\n const ruleId = getErrorField(message, \"ruleId\");\n const cause = getErrorCause(message);\n\n return {\n message: formatDiagnosticMessage(reason, {\n source,\n ruleId,\n line: details.line,\n column: details.column,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n causeMessage: cause?.message,\n }),\n reason,\n source,\n ruleId,\n fatal: typeof message.fatal === \"boolean\" ? message.fatal : undefined,\n line: details.line,\n column: details.column,\n place: details.place,\n sourceLine: details.sourceLine,\n snippet: details.snippet,\n sourcePointer: details.sourcePointer,\n hint: details.hint,\n cause,\n };\n });\n}\n\nfunction formatDiagnosticMessage(\n reason: string,\n options: {\n source?: string | undefined;\n ruleId?: string | undefined;\n line?: number | undefined;\n column?: number | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n causeMessage?: string | undefined;\n },\n): string {\n const origin =\n options.source === undefined\n ? undefined\n : options.ruleId === undefined\n ? options.source\n : `${options.source}:${options.ruleId}`;\n const location =\n options.line === undefined\n ? undefined\n : options.column === undefined\n ? `at ${options.line}`\n : `at ${options.line}:${options.column}`;\n\n const lines = [[reason, origin, location].filter(Boolean).join(\" \")];\n\n if (options.snippet !== undefined) {\n lines.push(`Source: ${options.snippet}`);\n }\n if (options.sourceLine !== undefined && options.sourceLine !== options.snippet) {\n lines.push(`Line: ${options.sourceLine}`);\n if (options.sourcePointer !== undefined) {\n lines.push(` ${options.sourcePointer}`);\n }\n }\n if (\n options.causeMessage !== undefined &&\n options.causeMessage !== \"\" &&\n options.causeMessage !== reason\n ) {\n lines.push(`Cause: ${options.causeMessage}`);\n }\n if (options.hint !== undefined) {\n lines.push(`Hint: ${options.hint}`);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction getDiagnosticDetails(\n sourceContext: MdxDiagnosticSourceContext,\n place: MdxMessagePlace | undefined,\n error: unknown,\n): {\n line?: number | undefined;\n column?: number | undefined;\n place?: MdxMessagePlace | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n sourcePointer?: string | undefined;\n hint?: string | undefined;\n} {\n const compileLine = place?.start?.line ?? getErrorNumberField(error, \"line\");\n let line = compileLine === undefined ? undefined : compileLine + sourceContext.lineOffset;\n let column = place?.start?.column ?? getErrorNumberField(error, \"column\");\n let normalizedPlace = mapPlaceToOriginalSource(\n place === undefined && compileLine === undefined && column === undefined\n ? undefined\n : {\n start: {\n line: compileLine,\n column,\n offset: place?.start?.offset,\n },\n end:\n place?.end === undefined\n ? undefined\n : {\n line: place.end.line,\n column: place.end.column,\n offset: place.end.offset,\n },\n },\n sourceContext.lineOffset,\n );\n let sourceLine = getSourceLine(sourceContext.originalSourceText, line);\n let snippet = getSourceSnippet(sourceContext.originalSourceText, normalizedPlace);\n let sourcePointer = getSourcePointer(column);\n let hint: string | undefined;\n\n const refinedExpressionContext = getMdxExpressionContext(sourceContext.originalSourceText, {\n line,\n column,\n sourceLine,\n snippet,\n error,\n });\n\n if (refinedExpressionContext !== undefined) {\n line = refinedExpressionContext.line;\n column = refinedExpressionContext.column;\n sourceLine = refinedExpressionContext.sourceLine;\n snippet = refinedExpressionContext.snippet;\n sourcePointer = refinedExpressionContext.sourcePointer;\n hint = refinedExpressionContext.hint;\n normalizedPlace = {\n start: {\n line,\n column,\n offset: undefined,\n },\n end: undefined,\n };\n }\n\n return {\n line,\n column,\n place: normalizedPlace,\n sourceLine,\n snippet,\n sourcePointer,\n hint,\n };\n}\n\nfunction getMdxExpressionContext(\n sourceText: string,\n options: {\n line?: number | undefined;\n column?: number | undefined;\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n error: unknown;\n },\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n sourcePointer: string;\n hint?: string | undefined;\n }\n | undefined {\n if (!shouldRefineMdxExpressionContext(options)) {\n return undefined;\n }\n\n const candidate = findSuspiciousBraceExpression(sourceText, options.line, options.column);\n if (candidate === undefined) {\n return undefined;\n }\n\n return {\n line: candidate.line,\n column: candidate.column,\n sourceLine: candidate.sourceLine,\n snippet: candidate.snippet,\n sourcePointer: getSourcePointer(candidate.column) ?? \"^\",\n hint:\n getErrorCause(options.error)?.message === \"Unexpected content after expression\"\n ? \"MDX treats `{...}` as JavaScript. If you meant literal braces in text, escape them or wrap the text in code.\"\n : undefined,\n };\n}\n\nfunction shouldRefineMdxExpressionContext(options: {\n sourceLine?: string | undefined;\n snippet?: string | undefined;\n error: unknown;\n}): boolean {\n const trimmedSourceLine = options.sourceLine?.trim();\n\n return (\n isMdxExpressionError(options.error) &&\n getErrorCause(options.error)?.message === \"Unexpected content after expression\" &&\n (options.sourceLine === undefined ||\n options.sourceLine.trim() === \"\" ||\n options.snippet === undefined) &&\n !(trimmedSourceLine?.startsWith(\"{\") && trimmedSourceLine.endsWith(\"}\"))\n );\n}\n\nfunction getSourceLine(sourceText: string, line: number | undefined): string | undefined {\n if (line === undefined || line < 1) {\n return undefined;\n }\n return sourceText.split(/\\r?\\n/u)[line - 1];\n}\n\nfunction getSourceSnippet(\n sourceText: string,\n place: MdxMessagePlace | undefined,\n): string | undefined {\n if (place?.start?.offset !== undefined && place.end?.offset !== undefined) {\n return sourceText.slice(place.start.offset, place.end.offset) || undefined;\n }\n\n if (place?.start?.line === undefined || place.start.column === undefined) {\n return undefined;\n }\n\n if (place.end === undefined) {\n const lines = sourceText.split(/\\r?\\n/u);\n const line = lines[place.start.line - 1];\n if (line === undefined) {\n return undefined;\n }\n\n const character = line.at(place.start.column - 1);\n return character === undefined || character.trim() === \"\" ? undefined : character;\n }\n\n const lines = sourceText.split(/\\r?\\n/u);\n const startLineIndex = place.start.line - 1;\n const endLineIndex = (place.end?.line ?? place.start.line) - 1;\n\n if (startLineIndex < 0 || startLineIndex >= lines.length) {\n return undefined;\n }\n\n const selectedLines = lines.slice(startLineIndex, endLineIndex + 1);\n if (selectedLines.length === 0) {\n return undefined;\n }\n\n selectedLines[0] = selectedLines[0].slice(place.start.column - 1);\n\n const endColumn = place.end?.column;\n if (endColumn !== undefined) {\n const lastIndex = selectedLines.length - 1;\n selectedLines[lastIndex] = selectedLines[lastIndex].slice(0, endColumn - 1);\n }\n\n return selectedLines.join(\"\\n\") || undefined;\n}\n\nfunction getSourcePointer(column: number | undefined): string | undefined {\n if (column === undefined || column < 1) {\n return undefined;\n }\n\n return `${\" \".repeat(column - 1)}^`;\n}\n\nfunction mapPlaceToOriginalSource(\n place: MdxMessagePlace | undefined,\n lineOffset: number,\n): MdxMessagePlace | undefined {\n if (place === undefined) {\n return undefined;\n }\n\n return {\n start: mapPointToOriginalSource(place.start, lineOffset),\n end: mapPointToOriginalSource(place.end, lineOffset),\n };\n}\n\nfunction mapPointToOriginalSource(\n point: MdxMessagePoint | undefined,\n lineOffset: number,\n): MdxMessagePoint | undefined {\n if (point === undefined) {\n return undefined;\n }\n\n return {\n line: point.line === undefined ? undefined : point.line + lineOffset,\n column: point.column,\n offset: lineOffset === 0 ? point.offset : undefined,\n };\n}\n\nfunction findSuspiciousBraceExpression(\n sourceText: string,\n line: number | undefined,\n column: number | undefined,\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n }\n | undefined {\n const lines = sourceText.split(/\\r?\\n/u);\n const searchLines = getNearbyLineNumbers(line, lines.length, 2);\n let bestMatch:\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n score: number;\n }\n | undefined;\n\n for (const lineNumber of searchLines) {\n const sourceLine = lines[lineNumber - 1];\n if (sourceLine === undefined || sourceLine.trim() === \"\") {\n continue;\n }\n\n const expression = findLineBraceExpression(sourceLine, lineNumber, column);\n if (expression === undefined) {\n continue;\n }\n\n const lineDistance = line === undefined ? 0 : Math.abs(lineNumber - line);\n const score = lineDistance * 10 + expression.distance;\n\n if (bestMatch === undefined || score < bestMatch.score) {\n bestMatch = {\n ...expression,\n score,\n };\n }\n }\n\n return bestMatch;\n}\n\nfunction getNearbyLineNumbers(\n line: number | undefined,\n totalLines: number,\n radius: number,\n): number[] {\n if (line === undefined) {\n return Array.from({ length: totalLines }, (_, index) => index + 1);\n }\n\n const lineNumbers: number[] = [];\n for (let distance = 0; distance <= radius; distance++) {\n const before = line - distance;\n if (before >= 1) {\n lineNumbers.push(before);\n }\n\n if (distance === 0) {\n continue;\n }\n\n const after = line + distance;\n if (after <= totalLines) {\n lineNumbers.push(after);\n }\n }\n\n return lineNumbers;\n}\n\nfunction findLineBraceExpression(\n sourceLine: string,\n line: number,\n column: number | undefined,\n):\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n distance: number;\n }\n | undefined {\n let bestMatch:\n | {\n line: number;\n column: number;\n sourceLine: string;\n snippet: string;\n distance: number;\n }\n | undefined;\n\n for (const match of sourceLine.matchAll(/\\{[^{}\\n]+\\}/gu)) {\n const braceStart = match.index;\n if (braceStart === undefined) {\n continue;\n }\n\n const expanded = expandBraceExpression(sourceLine, braceStart);\n if (expanded === undefined) {\n continue;\n }\n\n const distance = column === undefined ? 0 : Math.abs(braceStart + 1 - column);\n if (bestMatch === undefined || distance < bestMatch.distance) {\n bestMatch = {\n line,\n column: braceStart + 1,\n sourceLine,\n snippet: expanded,\n distance,\n };\n }\n }\n\n return bestMatch;\n}\n\nfunction expandBraceExpression(sourceLine: string, braceStart: number): string | undefined {\n const braceEnd = sourceLine.indexOf(\"}\", braceStart);\n if (braceEnd === -1) {\n return undefined;\n }\n\n let start = braceStart;\n while (start > 0 && /[A-Za-z0-9_]/u.test(sourceLine[start - 1])) {\n start--;\n }\n\n let end = braceEnd + 1;\n while (end < sourceLine.length) {\n while (end < sourceLine.length && /[A-Za-z0-9_]/u.test(sourceLine[end])) {\n end++;\n }\n\n if (sourceLine[end] !== \"{\") {\n break;\n }\n\n const chainedEnd = sourceLine.indexOf(\"}\", end);\n if (chainedEnd === -1) {\n break;\n }\n end = chainedEnd + 1;\n }\n\n return sourceLine.slice(start, end) || undefined;\n}\n\nfunction isMdxExpressionError(error: unknown): boolean {\n return (\n getErrorField(error, \"source\") === \"micromark-extension-mdx-expression\" &&\n getErrorField(error, \"ruleId\") === \"acorn\"\n );\n}\n\nfunction createDiagnosticSourceContext(\n originalSourceText: string,\n compileSourceText: string,\n): MdxDiagnosticSourceContext {\n return {\n originalSourceText,\n lineOffset: getSourceLineOffset(originalSourceText, compileSourceText),\n };\n}\n\nfunction getSourceLineOffset(originalSourceText: string, compileSourceText: string): number {\n const originalLines = originalSourceText.split(/\\r?\\n/u);\n const compileLines = compileSourceText.split(/\\r?\\n/u);\n const maxOffset = originalLines.length - compileLines.length;\n\n for (let offset = 0; offset <= maxOffset; offset++) {\n let isMatch = true;\n for (let index = 0; index < compileLines.length; index++) {\n if (originalLines[offset + index] !== compileLines[index]) {\n isMatch = false;\n break;\n }\n }\n\n if (isMatch) {\n return offset;\n }\n }\n\n return maxOffset > 0 ? maxOffset : 0;\n}\n\nfunction getErrorPlace(error: unknown): MdxMessagePlace | undefined {\n if (typeof error !== \"object\" || error === null) {\n return undefined;\n }\n\n const candidate = error as {\n place?: unknown;\n position?: unknown;\n };\n\n return toPlace(candidate.place) ?? toPlace(candidate.position);\n}\n\nfunction toMessagePlace(message: VFileLikeMessage): MdxMessagePlace | undefined {\n return toPlace(message.place);\n}\n\nfunction toPlace(value: unknown): MdxMessagePlace | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const candidate = value as {\n start?: unknown;\n end?: unknown;\n line?: unknown;\n column?: unknown;\n offset?: unknown;\n };\n\n if (candidate.start !== undefined || candidate.end !== undefined) {\n return {\n start: toPoint(candidate.start),\n end: toPoint(candidate.end),\n };\n }\n\n const point = toPoint(candidate);\n return point === undefined ? undefined : { start: point };\n}\n\nfunction toPoint(value: unknown): MdxMessagePoint | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const candidate = value as {\n line?: unknown;\n column?: unknown;\n offset?: unknown;\n };\n const line = typeof candidate.line === \"number\" ? candidate.line : undefined;\n const column = typeof candidate.column === \"number\" ? candidate.column : undefined;\n const offset = typeof candidate.offset === \"number\" ? candidate.offset : undefined;\n\n if (line === undefined && column === undefined && offset === undefined) {\n return undefined;\n }\n\n return { line, column, offset };\n}\n\nfunction getErrorReason(error: unknown): string {\n if (error instanceof Error && error.message !== \"\") {\n return error.message;\n }\n\n const reason = getErrorField(error, \"reason\");\n if (reason !== undefined && reason !== \"\") {\n return reason;\n }\n\n return String(error);\n}\n\nfunction getErrorCause(error: unknown): { name?: string | undefined; message: string } | undefined {\n if (typeof error !== \"object\" || error === null || !(\"cause\" in error)) {\n return undefined;\n }\n\n const cause = (error as { cause?: unknown }).cause;\n if (cause instanceof Error) {\n return {\n name: cause.name,\n message: cause.message,\n };\n }\n if (typeof cause === \"string\" && cause !== \"\") {\n return {\n message: cause,\n };\n }\n\n return undefined;\n}\n\nfunction getErrorField(error: unknown, field: \"source\" | \"ruleId\" | \"reason\"): string | undefined {\n if (typeof error !== \"object\" || error === null || !(field in error)) {\n return undefined;\n }\n\n const value = (error as Record<string, unknown>)[field];\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\nfunction getErrorNumberField(error: unknown, field: \"line\" | \"column\"): number | undefined {\n if (typeof error !== \"object\" || error === null || !(field in error)) {\n return undefined;\n }\n\n const value = (error as Record<string, unknown>)[field];\n return typeof value === \"number\" ? value : undefined;\n}\n\nfunction toSourceText(source: MdxSource): string {\n return typeof source === \"string\" ? source : new TextDecoder().decode(source);\n}\n"],"mappings":"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"}
|
package/dist/mod.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { HastElement as Element, HastNode as Node } from "./types.mjs";
|
|
2
2
|
import { MdxArtifact, MdxCompileError, MdxCompileOptions, MdxCompiler, MdxMessage, MdxMessagePlace, MdxMessagePoint, MdxSource, remarkFrontmatterPlugin, remarkGfmPlugin } from "./compiler.mjs";
|
|
3
3
|
import { HeadingIdPluginOptions, headingIdPlugin } from "./plugins/heading-id/plugin.mjs";
|
|
4
|
+
import { InlineMathStyle, KatexPluginOptions, katexPlugin } from "./plugins/katex/plugin.mjs";
|
|
4
5
|
import { removeImportsExportsPlugin } from "./plugins/remove-imports-exports.mjs";
|
|
5
6
|
import { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from "./plugins/syntax-highlight/plugin.mjs";
|
|
6
7
|
import { MdxTreeProcessor, treeProcessorPlugin } from "./plugins/tree-processor/plugin.mjs";
|
|
7
|
-
|
|
8
|
+
import "./plugins/mod.mjs";
|
|
9
|
+
export { type Element as HastElement, type Node as HastNode, HeadingIdPluginOptions, InlineMathStyle, KatexPluginOptions, MdxArtifact, MdxCompileError, MdxCompileOptions, MdxCompiler, MdxMessage, MdxMessagePlace, MdxMessagePoint, MdxSource, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, katexPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
package/dist/mod.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { MdxCompileError, MdxCompiler, remarkFrontmatterPlugin, remarkGfmPlugin } from "./compiler.mjs";
|
|
2
2
|
import { headingIdPlugin } from "./plugins/heading-id/plugin.mjs";
|
|
3
|
+
import { katexPlugin } from "./plugins/katex/plugin.mjs";
|
|
3
4
|
import { removeImportsExportsPlugin } from "./plugins/remove-imports-exports.mjs";
|
|
4
5
|
import { syntaxHighlightPlugin } from "./plugins/syntax-highlight/plugin.mjs";
|
|
5
6
|
import { treeProcessorPlugin } from "./plugins/tree-processor/plugin.mjs";
|
|
6
7
|
import "./plugins/mod.mjs";
|
|
7
|
-
export { MdxCompileError, MdxCompiler, headingIdPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
|
8
|
+
export { MdxCompileError, MdxCompiler, headingIdPlugin, katexPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/heading-id/plugin.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/heading-id/plugin.ts"],"mappings":";;;;;;UAWiB;;EAEf;;;;;cAMW,iBAAiB,QAAQ,0BAA0B,MAAU"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { HastNode as Node } from "../../types.mjs";
|
|
2
|
+
import { KatexOptions } from "katex";
|
|
3
|
+
import { Plugin } from "unified";
|
|
4
|
+
//#region src/plugins/katex/plugin.d.ts
|
|
5
|
+
declare const inlineMathStyleCommands: {
|
|
6
|
+
readonly display: string;
|
|
7
|
+
readonly script: string;
|
|
8
|
+
readonly scriptscript: string;
|
|
9
|
+
readonly text: string;
|
|
10
|
+
};
|
|
11
|
+
type KatexRenderOptions = Omit<KatexOptions, "displayMode" | "throwOnError">;
|
|
12
|
+
/**
|
|
13
|
+
* TeX math style applied to inline math.
|
|
14
|
+
*
|
|
15
|
+
* `"auto"` preserves the source and KaTeX's default style.
|
|
16
|
+
*/
|
|
17
|
+
type InlineMathStyle = "auto" | keyof typeof inlineMathStyleCommands;
|
|
18
|
+
/**
|
|
19
|
+
* KaTeX options controlled by callers. Rendering mode and error handling are
|
|
20
|
+
* inferred and enforced by the plugin.
|
|
21
|
+
*/
|
|
22
|
+
type KatexPluginOptions = KatexRenderOptions & {
|
|
23
|
+
/**
|
|
24
|
+
* TeX math style applied to inline-math nodes.
|
|
25
|
+
*
|
|
26
|
+
* Display and fenced math are not affected.
|
|
27
|
+
*
|
|
28
|
+
* @default "auto"
|
|
29
|
+
*/
|
|
30
|
+
inlineMathStyle?: InlineMathStyle;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Renders HAST elements marked as inline, display, or fenced-code math with
|
|
34
|
+
* KaTeX.
|
|
35
|
+
*/
|
|
36
|
+
declare const katexPlugin: Plugin<[Readonly<KatexPluginOptions>?], Node, Node>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { InlineMathStyle, KatexPluginOptions, katexPlugin };
|
|
39
|
+
//# sourceMappingURL=plugin.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/katex/plugin.ts"],"mappings":";;;;cAgBM;WACJ;WACA;WACA;WACA;;KAGG,qBAAqB,KAAK;;;;;;KAOnB,wCAAwC;;;;;KAMxC,qBAAqB;;;;;;;;EAQ/B,kBAAkB;;;;;;cAOP,aAAa,QAAQ,SAAS,uBAAuB,MAAU"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { fromHtmlIsomorphic } from "hast-util-from-html-isomorphic";
|
|
2
|
+
import { toText } from "hast-util-to-text";
|
|
3
|
+
import katex from "katex";
|
|
4
|
+
import { SKIP, visitParents } from "unist-util-visit-parents";
|
|
5
|
+
//#region src/plugins/katex/plugin.ts
|
|
6
|
+
const mathClasses = {
|
|
7
|
+
display: "math-display",
|
|
8
|
+
inline: "math-inline",
|
|
9
|
+
language: "language-math"
|
|
10
|
+
};
|
|
11
|
+
const inlineMathStyleCommands = {
|
|
12
|
+
display: String.raw`\displaystyle`,
|
|
13
|
+
script: String.raw`\scriptstyle`,
|
|
14
|
+
scriptscript: String.raw`\scriptscriptstyle`,
|
|
15
|
+
text: String.raw`\textstyle`
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Renders HAST elements marked as inline, display, or fenced-code math with
|
|
19
|
+
* KaTeX.
|
|
20
|
+
*/
|
|
21
|
+
const katexPlugin = (options = {}) => {
|
|
22
|
+
const { inlineMathStyle = "auto", ...katexOptions } = options;
|
|
23
|
+
return (tree, file) => {
|
|
24
|
+
visitParents(tree, "element", (element, ancestors) => {
|
|
25
|
+
const classes = Array.isArray(element.properties.className) ? element.properties.className : [];
|
|
26
|
+
const isLanguageMath = classes.includes(mathClasses.language);
|
|
27
|
+
const isDisplayMath = classes.includes(mathClasses.display);
|
|
28
|
+
const isInlineMath = classes.includes(mathClasses.inline);
|
|
29
|
+
if (!isLanguageMath && !isDisplayMath && !isInlineMath) return;
|
|
30
|
+
let scope = element;
|
|
31
|
+
let parent = ancestors.at(-1);
|
|
32
|
+
let displayMode = isDisplayMath;
|
|
33
|
+
if (element.tagName === "code" && isLanguageMath && parent?.type === "element" && parent.tagName === "pre") {
|
|
34
|
+
scope = parent;
|
|
35
|
+
parent = ancestors.at(-2);
|
|
36
|
+
displayMode = true;
|
|
37
|
+
}
|
|
38
|
+
if (parent === void 0 || parent.type !== "element" && parent.type !== "root") return;
|
|
39
|
+
const value = toText(scope, { whitespace: "pre" });
|
|
40
|
+
const renderedValue = isInlineMath && !displayMode ? applyInlineMathStyle(value, inlineMathStyle) : value;
|
|
41
|
+
let result;
|
|
42
|
+
try {
|
|
43
|
+
result = renderMath(renderedValue, katexOptions, displayMode);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const cause = getOriginalRenderError(value, katexOptions, displayMode, error);
|
|
46
|
+
file.message("Could not render math with KaTeX", {
|
|
47
|
+
ancestors: [...ancestors, element],
|
|
48
|
+
cause,
|
|
49
|
+
place: element.position,
|
|
50
|
+
ruleId: cause.name.toLowerCase(),
|
|
51
|
+
source: "rehype-katex"
|
|
52
|
+
});
|
|
53
|
+
try {
|
|
54
|
+
result = renderMath(value, {
|
|
55
|
+
...katexOptions,
|
|
56
|
+
strict: "ignore"
|
|
57
|
+
}, displayMode, false);
|
|
58
|
+
} catch {
|
|
59
|
+
result = [{
|
|
60
|
+
type: "element",
|
|
61
|
+
tagName: "span",
|
|
62
|
+
properties: {
|
|
63
|
+
className: ["katex-error"],
|
|
64
|
+
style: `color:${katexOptions.errorColor ?? "#cc0000"}`,
|
|
65
|
+
title: String(cause)
|
|
66
|
+
},
|
|
67
|
+
children: [{
|
|
68
|
+
type: "text",
|
|
69
|
+
value
|
|
70
|
+
}]
|
|
71
|
+
}];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const index = parent.children.indexOf(scope);
|
|
75
|
+
if (index !== -1) parent.children.splice(index, 1, ...result);
|
|
76
|
+
return SKIP;
|
|
77
|
+
});
|
|
78
|
+
return tree;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
function getOriginalRenderError(value, options, displayMode, styledError) {
|
|
82
|
+
try {
|
|
83
|
+
katex.renderToString(value, {
|
|
84
|
+
...options,
|
|
85
|
+
displayMode,
|
|
86
|
+
throwOnError: true
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
90
|
+
}
|
|
91
|
+
return styledError instanceof Error ? styledError : new Error(String(styledError));
|
|
92
|
+
}
|
|
93
|
+
function applyInlineMathStyle(value, style) {
|
|
94
|
+
if (style === "auto") return value;
|
|
95
|
+
return `{${inlineMathStyleCommands[style]} ${value}}`;
|
|
96
|
+
}
|
|
97
|
+
function renderMath(value, options, displayMode, throwOnError = true) {
|
|
98
|
+
return fromHtmlIsomorphic(katex.renderToString(value, {
|
|
99
|
+
...options,
|
|
100
|
+
displayMode,
|
|
101
|
+
throwOnError
|
|
102
|
+
}), { fragment: true }).children;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { katexPlugin };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/plugins/katex/plugin.ts"],"sourcesContent":["import type { Element, ElementContent, Root } from \"hast\";\nimport type { Plugin } from \"unified\";\n\nimport { fromHtmlIsomorphic } from \"hast-util-from-html-isomorphic\";\nimport { toText } from \"hast-util-to-text\";\nimport katex, { type KatexOptions } from \"katex\";\nimport { SKIP, visitParents } from \"unist-util-visit-parents\";\n\nimport type { HastNode } from \"../../types\";\n\nconst mathClasses = {\n display: \"math-display\",\n inline: \"math-inline\",\n language: \"language-math\",\n} as const;\n\nconst inlineMathStyleCommands = {\n display: String.raw`\\displaystyle`,\n script: String.raw`\\scriptstyle`,\n scriptscript: String.raw`\\scriptscriptstyle`,\n text: String.raw`\\textstyle`,\n} as const;\n\ntype KatexRenderOptions = Omit<KatexOptions, \"displayMode\" | \"throwOnError\">;\n\n/**\n * TeX math style applied to inline math.\n *\n * `\"auto\"` preserves the source and KaTeX's default style.\n */\nexport type InlineMathStyle = \"auto\" | keyof typeof inlineMathStyleCommands;\n\n/**\n * KaTeX options controlled by callers. Rendering mode and error handling are\n * inferred and enforced by the plugin.\n */\nexport type KatexPluginOptions = KatexRenderOptions & {\n /**\n * TeX math style applied to inline-math nodes.\n *\n * Display and fenced math are not affected.\n *\n * @default \"auto\"\n */\n inlineMathStyle?: InlineMathStyle;\n};\n\n/**\n * Renders HAST elements marked as inline, display, or fenced-code math with\n * KaTeX.\n */\nexport const katexPlugin: Plugin<[Readonly<KatexPluginOptions>?], HastNode, HastNode> = (\n options = {},\n) => {\n const { inlineMathStyle = \"auto\", ...katexOptions } = options;\n\n return (tree, file) => {\n visitParents(tree as Root, \"element\", (element, ancestors) => {\n const classes = Array.isArray(element.properties.className)\n ? element.properties.className\n : [];\n const isLanguageMath = classes.includes(mathClasses.language);\n const isDisplayMath = classes.includes(mathClasses.display);\n const isInlineMath = classes.includes(mathClasses.inline);\n\n if (!isLanguageMath && !isDisplayMath && !isInlineMath) {\n return;\n }\n\n let scope: Element = element;\n let parent = ancestors.at(-1);\n let displayMode = isDisplayMath;\n\n if (\n element.tagName === \"code\" &&\n isLanguageMath &&\n parent?.type === \"element\" &&\n parent.tagName === \"pre\"\n ) {\n scope = parent;\n parent = ancestors.at(-2);\n displayMode = true;\n }\n\n if (parent === undefined || (parent.type !== \"element\" && parent.type !== \"root\")) {\n return;\n }\n\n const value = toText(scope, { whitespace: \"pre\" });\n const renderedValue =\n isInlineMath && !displayMode ? applyInlineMathStyle(value, inlineMathStyle) : value;\n let result: ElementContent[];\n\n try {\n result = renderMath(renderedValue, katexOptions, displayMode);\n } catch (error) {\n const cause = getOriginalRenderError(value, katexOptions, displayMode, error);\n\n file.message(\"Could not render math with KaTeX\", {\n ancestors: [...ancestors, element],\n cause,\n place: element.position,\n ruleId: cause.name.toLowerCase(),\n source: \"rehype-katex\",\n });\n\n try {\n result = renderMath(value, { ...katexOptions, strict: \"ignore\" }, displayMode, false);\n } catch {\n result = [\n {\n type: \"element\",\n tagName: \"span\",\n properties: {\n className: [\"katex-error\"],\n style: `color:${katexOptions.errorColor ?? \"#cc0000\"}`,\n title: String(cause),\n },\n children: [{ type: \"text\", value }],\n },\n ];\n }\n }\n\n const index = parent.children.indexOf(scope);\n if (index !== -1) {\n parent.children.splice(index, 1, ...result);\n }\n\n return SKIP;\n });\n\n return tree;\n };\n};\n\nfunction getOriginalRenderError(\n value: string,\n options: Readonly<KatexRenderOptions>,\n displayMode: boolean,\n styledError: unknown,\n): Error {\n try {\n katex.renderToString(value, {\n ...options,\n displayMode,\n throwOnError: true,\n });\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n\n return styledError instanceof Error ? styledError : new Error(String(styledError));\n}\n\nfunction applyInlineMathStyle(value: string, style: InlineMathStyle): string {\n if (style === \"auto\") {\n return value;\n }\n\n return `{${inlineMathStyleCommands[style]} ${value}}`;\n}\n\nfunction renderMath(\n value: string,\n options: Readonly<KatexRenderOptions>,\n displayMode: boolean,\n throwOnError = true,\n): ElementContent[] {\n const html = katex.renderToString(value, {\n ...options,\n displayMode,\n throwOnError,\n });\n const root = fromHtmlIsomorphic(html, { fragment: true });\n\n // KaTeX emits an HTML fragment and therefore cannot produce doctypes.\n return root.children as ElementContent[];\n}\n"],"mappings":";;;;;AAUA,MAAM,cAAc;CAClB,SAAS;CACT,QAAQ;CACR,UAAU;AACZ;AAEA,MAAM,0BAA0B;CAC9B,SAAS,OAAO,GAAG;CACnB,QAAQ,OAAO,GAAG;CAClB,cAAc,OAAO,GAAG;CACxB,MAAM,OAAO,GAAG;AAClB;;;;;AA8BA,MAAa,eACX,UAAU,CAAC,MACR;CACH,MAAM,EAAE,kBAAkB,QAAQ,GAAG,iBAAiB;CAEtD,QAAQ,MAAM,SAAS;EACrB,aAAa,MAAc,YAAY,SAAS,cAAc;GAC5D,MAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,SAAS,IACtD,QAAQ,WAAW,YACnB,CAAC;GACL,MAAM,iBAAiB,QAAQ,SAAS,YAAY,QAAQ;GAC5D,MAAM,gBAAgB,QAAQ,SAAS,YAAY,OAAO;GAC1D,MAAM,eAAe,QAAQ,SAAS,YAAY,MAAM;GAExD,IAAI,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,cACxC;GAGF,IAAI,QAAiB;GACrB,IAAI,SAAS,UAAU,GAAG,EAAE;GAC5B,IAAI,cAAc;GAElB,IACE,QAAQ,YAAY,UACpB,kBACA,QAAQ,SAAS,aACjB,OAAO,YAAY,OACnB;IACA,QAAQ;IACR,SAAS,UAAU,GAAG,EAAE;IACxB,cAAc;GAChB;GAEA,IAAI,WAAW,KAAA,KAAc,OAAO,SAAS,aAAa,OAAO,SAAS,QACxE;GAGF,MAAM,QAAQ,OAAO,OAAO,EAAE,YAAY,MAAM,CAAC;GACjD,MAAM,gBACJ,gBAAgB,CAAC,cAAc,qBAAqB,OAAO,eAAe,IAAI;GAChF,IAAI;GAEJ,IAAI;IACF,SAAS,WAAW,eAAe,cAAc,WAAW;GAC9D,SAAS,OAAO;IACd,MAAM,QAAQ,uBAAuB,OAAO,cAAc,aAAa,KAAK;IAE5E,KAAK,QAAQ,oCAAoC;KAC/C,WAAW,CAAC,GAAG,WAAW,OAAO;KACjC;KACA,OAAO,QAAQ;KACf,QAAQ,MAAM,KAAK,YAAY;KAC/B,QAAQ;IACV,CAAC;IAED,IAAI;KACF,SAAS,WAAW,OAAO;MAAE,GAAG;MAAc,QAAQ;KAAS,GAAG,aAAa,KAAK;IACtF,QAAQ;KACN,SAAS,CACP;MACE,MAAM;MACN,SAAS;MACT,YAAY;OACV,WAAW,CAAC,aAAa;OACzB,OAAO,SAAS,aAAa,cAAc;OAC3C,OAAO,OAAO,KAAK;MACrB;MACA,UAAU,CAAC;OAAE,MAAM;OAAQ;MAAM,CAAC;KACpC,CACF;IACF;GACF;GAEA,MAAM,QAAQ,OAAO,SAAS,QAAQ,KAAK;GAC3C,IAAI,UAAU,IACZ,OAAO,SAAS,OAAO,OAAO,GAAG,GAAG,MAAM;GAG5C,OAAO;EACT,CAAC;EAED,OAAO;CACT;AACF;AAEA,SAAS,uBACP,OACA,SACA,aACA,aACO;CACP,IAAI;EACF,MAAM,eAAe,OAAO;GAC1B,GAAG;GACH;GACA,cAAc;EAChB,CAAC;CACH,SAAS,OAAO;EACd,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;CACjE;CAEA,OAAO,uBAAuB,QAAQ,cAAc,IAAI,MAAM,OAAO,WAAW,CAAC;AACnF;AAEA,SAAS,qBAAqB,OAAe,OAAgC;CAC3E,IAAI,UAAU,QACZ,OAAO;CAGT,OAAO,IAAI,wBAAwB,OAAO,GAAG,MAAM;AACrD;AAEA,SAAS,WACP,OACA,SACA,aACA,eAAe,MACG;CASlB,OAHa,mBALA,MAAM,eAAe,OAAO;EACvC,GAAG;EACH;EACA;CACF,CACmC,GAAG,EAAE,UAAU,KAAK,CAG7C,CAAC,CAAC;AACd"}
|
package/dist/plugins/mod.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HeadingIdPluginOptions, headingIdPlugin } from "./heading-id/plugin.mjs";
|
|
2
|
+
import { InlineMathStyle, KatexPluginOptions, katexPlugin } from "./katex/plugin.mjs";
|
|
2
3
|
import { removeImportsExportsPlugin } from "./remove-imports-exports.mjs";
|
|
3
4
|
import { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from "./syntax-highlight/plugin.mjs";
|
|
4
5
|
import { MdxTreeProcessor, treeProcessorPlugin } from "./tree-processor/plugin.mjs";
|
|
5
|
-
export { HeadingIdPluginOptions, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
|
6
|
+
export { HeadingIdPluginOptions, InlineMathStyle, KatexPluginOptions, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, katexPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
package/dist/plugins/mod.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { headingIdPlugin } from "./heading-id/plugin.mjs";
|
|
2
|
+
import { katexPlugin } from "./katex/plugin.mjs";
|
|
2
3
|
import { removeImportsExportsPlugin } from "./remove-imports-exports.mjs";
|
|
3
4
|
import { syntaxHighlightPlugin } from "./syntax-highlight/plugin.mjs";
|
|
4
5
|
import { treeProcessorPlugin } from "./tree-processor/plugin.mjs";
|
|
5
|
-
export { headingIdPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
|
6
|
+
export { headingIdPlugin, katexPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-imports-exports.d.mts","names":[],"sources":["../../src/plugins/remove-imports-exports.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"remove-imports-exports.d.mts","names":[],"sources":["../../src/plugins/remove-imports-exports.ts"],"mappings":";;;;;;cASa,4BAA4B,kBAAkB,MAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-meta.d.mts","names":[],"sources":["../../../src/plugins/syntax-highlight/code-meta.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"code-meta.d.mts","names":[],"sources":["../../../src/plugins/syntax-highlight/code-meta.ts"],"mappings":";;;UAKiB;EACf,YAAY;EACZ,kBAAkB;EAClB,cAAc;EACd;;KAGU;EACV,WAAW;;KAGD;EACV,WAAW;;KAGD;EACV,cAAc;;iBAGA,gBAAgB,MAAM,UAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-meta.mjs","names":[],"sources":["../../../src/plugins/syntax-highlight/code-meta.ts"],"sourcesContent":["import { type NumericRange, parseNumericRange } from \"@temelj/iterator\";\nimport { ss, validateStandardSchemaSync } from \"@temelj/standard-schema\";\n\nimport type { HastElement } from \"../../types\";\n\nexport interface MdxCodeMeta {\n highlight?: MdxCodeMetaHighlightLine;\n showLineNumbers?: MdxCodeMetaLineNumbers;\n commandLine?: MdxCodeMetaCommandLine;\n fileName?: string;\n}\n\nexport type MdxCodeMetaHighlightLine = {\n lineRange: NumericRange;\n};\n\nexport type MdxCodeMetaLineNumbers = {\n lineRange: NumericRange;\n};\n\nexport type MdxCodeMetaCommandLine = {\n commandRange: NumericRange;\n};\n\nexport function extractCodeMeta(node: HastElement): MdxCodeMeta {\n const meta = node?.data?.meta ?? node?.properties?.metastring ?? \"\";\n return parseMetaString(meta as string);\n}\n\nconst stringOrBoolean = ss.union(\n [ss.string(\"Expected string or boolean\"), ss.boolean(\"Expected string or boolean\")],\n \"Expected string or boolean\",\n);\n\nconst metaSchema = ss.object(\n {\n highlight: ss.optional(ss.string(\"Expected string\")),\n showLineNumbers: ss.optional(stringOrBoolean),\n commandLine: ss.optional(stringOrBoolean),\n fileName: ss.optional(ss.string(\"Expected string\")),\n },\n \"Expected object\",\n);\n\nfunction parseMetaString(meta: string): MdxCodeMeta {\n let raw: unknown;\n try {\n raw = JSON.parse(meta.trim());\n } catch {\n return {};\n }\n const parsed = validateStandardSchemaSync(metaSchema, raw, \"Code metadata validation failed\");\n const options: MdxCodeMeta = {};\n\n if (parsed.highlight !== undefined) {\n options.highlight = { lineRange: parseNumericRange(parsed.highlight) };\n }\n\n if (parsed.showLineNumbers !== undefined) {\n if (typeof parsed.showLineNumbers === \"string\") {\n options.showLineNumbers = {\n lineRange: parseNumericRange(parsed.showLineNumbers),\n };\n } else if (parsed.showLineNumbers) {\n options.showLineNumbers = { lineRange: [] };\n }\n }\n\n if (parsed.commandLine !== undefined) {\n if (typeof parsed.commandLine === \"string\") {\n options.commandLine = {\n commandRange: parseNumericRange(parsed.commandLine),\n };\n } else if (parsed.commandLine) {\n options.commandLine = { commandRange: [] };\n }\n }\n\n if (parsed.fileName !== undefined) {\n options.fileName = parsed.fileName.trim();\n }\n\n return options;\n}\n"],"mappings":";;;AAwBA,SAAgB,gBAAgB,MAAgC;CAE9D,OAAO,gBADM,MAAM,MAAM,QAAQ,MAAM,YAAY,cAAc,EAC5B;AACvC;AAEA,MAAM,kBAAkB,GAAG,MACzB,CAAC,GAAG,OAAO,4BAA4B,GAAG,GAAG,QAAQ,4BAA4B,CAAC,GAClF,4BACF;AAEA,MAAM,aAAa,GAAG,OACpB;CACE,WAAW,GAAG,SAAS,GAAG,OAAO,iBAAiB,CAAC;CACnD,iBAAiB,GAAG,SAAS,eAAe;CAC5C,aAAa,GAAG,SAAS,eAAe;CACxC,UAAU,GAAG,SAAS,GAAG,OAAO,iBAAiB,CAAC;AACpD,GACA,iBACF;AAEA,SAAS,gBAAgB,MAA2B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,KAAK,MAAM,KAAK,KAAK,CAAC;CAC9B,QAAQ;EACN,OAAO,CAAC;CACV;CACA,MAAM,SAAS,2BAA2B,YAAY,KAAK,iCAAiC;CAC5F,MAAM,UAAuB,CAAC;CAE9B,IAAI,OAAO,cAAc,KAAA,GACvB,QAAQ,YAAY,EAAE,WAAW,kBAAkB,OAAO,SAAS,EAAE;CAGvE,IAAI,OAAO,oBAAoB,KAAA;
|
|
1
|
+
{"version":3,"file":"code-meta.mjs","names":[],"sources":["../../../src/plugins/syntax-highlight/code-meta.ts"],"sourcesContent":["import { type NumericRange, parseNumericRange } from \"@temelj/iterator\";\nimport { ss, validateStandardSchemaSync } from \"@temelj/standard-schema\";\n\nimport type { HastElement } from \"../../types\";\n\nexport interface MdxCodeMeta {\n highlight?: MdxCodeMetaHighlightLine;\n showLineNumbers?: MdxCodeMetaLineNumbers;\n commandLine?: MdxCodeMetaCommandLine;\n fileName?: string;\n}\n\nexport type MdxCodeMetaHighlightLine = {\n lineRange: NumericRange;\n};\n\nexport type MdxCodeMetaLineNumbers = {\n lineRange: NumericRange;\n};\n\nexport type MdxCodeMetaCommandLine = {\n commandRange: NumericRange;\n};\n\nexport function extractCodeMeta(node: HastElement): MdxCodeMeta {\n const meta = node?.data?.meta ?? node?.properties?.metastring ?? \"\";\n return parseMetaString(meta as string);\n}\n\nconst stringOrBoolean = ss.union(\n [ss.string(\"Expected string or boolean\"), ss.boolean(\"Expected string or boolean\")],\n \"Expected string or boolean\",\n);\n\nconst metaSchema = ss.object(\n {\n highlight: ss.optional(ss.string(\"Expected string\")),\n showLineNumbers: ss.optional(stringOrBoolean),\n commandLine: ss.optional(stringOrBoolean),\n fileName: ss.optional(ss.string(\"Expected string\")),\n },\n \"Expected object\",\n);\n\nfunction parseMetaString(meta: string): MdxCodeMeta {\n let raw: unknown;\n try {\n raw = JSON.parse(meta.trim());\n } catch {\n return {};\n }\n const parsed = validateStandardSchemaSync(metaSchema, raw, \"Code metadata validation failed\");\n const options: MdxCodeMeta = {};\n\n if (parsed.highlight !== undefined) {\n options.highlight = { lineRange: parseNumericRange(parsed.highlight) };\n }\n\n if (parsed.showLineNumbers !== undefined) {\n if (typeof parsed.showLineNumbers === \"string\") {\n options.showLineNumbers = {\n lineRange: parseNumericRange(parsed.showLineNumbers),\n };\n } else if (parsed.showLineNumbers) {\n options.showLineNumbers = { lineRange: [] };\n }\n }\n\n if (parsed.commandLine !== undefined) {\n if (typeof parsed.commandLine === \"string\") {\n options.commandLine = {\n commandRange: parseNumericRange(parsed.commandLine),\n };\n } else if (parsed.commandLine) {\n options.commandLine = { commandRange: [] };\n }\n }\n\n if (parsed.fileName !== undefined) {\n options.fileName = parsed.fileName.trim();\n }\n\n return options;\n}\n"],"mappings":";;;AAwBA,SAAgB,gBAAgB,MAAgC;CAE9D,OAAO,gBADM,MAAM,MAAM,QAAQ,MAAM,YAAY,cAAc,EAC5B;AACvC;AAEA,MAAM,kBAAkB,GAAG,MACzB,CAAC,GAAG,OAAO,4BAA4B,GAAG,GAAG,QAAQ,4BAA4B,CAAC,GAClF,4BACF;AAEA,MAAM,aAAa,GAAG,OACpB;CACE,WAAW,GAAG,SAAS,GAAG,OAAO,iBAAiB,CAAC;CACnD,iBAAiB,GAAG,SAAS,eAAe;CAC5C,aAAa,GAAG,SAAS,eAAe;CACxC,UAAU,GAAG,SAAS,GAAG,OAAO,iBAAiB,CAAC;AACpD,GACA,iBACF;AAEA,SAAS,gBAAgB,MAA2B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,KAAK,MAAM,KAAK,KAAK,CAAC;CAC9B,QAAQ;EACN,OAAO,CAAC;CACV;CACA,MAAM,SAAS,2BAA2B,YAAY,KAAK,iCAAiC;CAC5F,MAAM,UAAuB,CAAC;CAE9B,IAAI,OAAO,cAAc,KAAA,GACvB,QAAQ,YAAY,EAAE,WAAW,kBAAkB,OAAO,SAAS,EAAE;CAGvE,IAAI,OAAO,oBAAoB,KAAA,GACzB;MAAA,OAAO,OAAO,oBAAoB,UACpC,QAAQ,kBAAkB,EACxB,WAAW,kBAAkB,OAAO,eAAe,EACrD;OACK,IAAI,OAAO,iBAChB,QAAQ,kBAAkB,EAAE,WAAW,CAAC,EAAE;CAAA;CAI9C,IAAI,OAAO,gBAAgB,KAAA,GACrB;MAAA,OAAO,OAAO,gBAAgB,UAChC,QAAQ,cAAc,EACpB,cAAc,kBAAkB,OAAO,WAAW,EACpD;OACK,IAAI,OAAO,aAChB,QAAQ,cAAc,EAAE,cAAc,CAAC,EAAE;CAAA;CAI7C,IAAI,OAAO,aAAa,KAAA,GACtB,QAAQ,WAAW,OAAO,SAAS,KAAK;CAG1C,OAAO;AACT"}
|
|
@@ -2,7 +2,6 @@ import { HastNode as Node } from "../../types.mjs";
|
|
|
2
2
|
import { TransformerNotationHighlightOptions } from "@shikijs/transformers";
|
|
3
3
|
import { BundledLanguage, BundledTheme, CodeToHastOptions } from "shiki";
|
|
4
4
|
import { Plugin } from "unified";
|
|
5
|
-
|
|
6
5
|
//#region src/plugins/syntax-highlight/plugin.d.ts
|
|
7
6
|
type ShikiHastOptions = Partial<CodeToHastOptions<BundledLanguage, BundledTheme>>;
|
|
8
7
|
type SyntaxDataAttribute = "source-code" | "language" | "line-count";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/syntax-highlight/plugin.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/syntax-highlight/plugin.ts"],"mappings":";;;;;KAsBK,mBAAmB,QAAQ,kBAAkB,iBAAiB;KAE9D;;;;UAKY;;;;;EAKf,wBAAwB;;;;EAKxB;IACE,cAAc;;;;;EAMhB;;;;;IAKE;;;;IAIA;;;;;EAMF;;;;IAIE;;;;;EAMF,mBAAmB;;;;;cAMR,uBAAuB,QAAQ,gCAAgC,MAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":["hastToString"],"sources":["../../../src/plugins/syntax-highlight/plugin.ts"],"sourcesContent":["import type { Properties } from \"hast\";\nimport type { Plugin } from \"unified\";\n\nimport {\n type TransformerNotationHighlightOptions,\n transformerNotationHighlight,\n} from \"@shikijs/transformers\";\nimport { numericRangeContains } from \"@temelj/iterator\";\nimport { toString as hastToString } from \"hast-util-to-string\";\nimport {\n type BundledLanguage,\n type BundledTheme,\n type CodeToHastOptions,\n codeToHast,\n ShikiError,\n} from \"shiki\";\nimport { visit } from \"unist-util-visit\";\n\nimport type { HastElement, HastNode } from \"../../types\";\n\nimport { extractCodeMeta } from \"./code-meta\";\n\ntype ShikiHastOptions = Partial<CodeToHastOptions<BundledLanguage, BundledTheme>>;\n\ntype SyntaxDataAttribute = \"source-code\" | \"language\" | \"line-count\";\n\n/**\n * Options for {@linkcode syntaxHighlightPlugin}.\n */\nexport interface SyntaxHighlightPluginOptions {\n /**\n * Include these data attributes on the `<pre>` element.\n * These might be useful to have when building custom code components.\n */\n includeDataAttributes?: SyntaxDataAttribute[];\n\n /**\n * Options for the highlight transformer.\n */\n highlight?: {\n transformer?: TransformerNotationHighlightOptions;\n };\n\n /**\n * Options for line numbers.\n */\n lineNumbers?: {\n /**\n * The name of the variable that contains the line number width.\n * This is used for padding the line numbers so that they align.\n */\n widthVariableName?: string;\n /**\n * A class name to be added to the line numbers.\n */\n className?: string;\n };\n\n /**\n * Options for command line.\n */\n commandLine?: {\n /**\n * A class name to be added to the prompt line.\n */\n className?: string;\n };\n\n /**\n * Extra options for the Shiki hast transformer.\n */\n shikiHastOptions?: ShikiHastOptions;\n}\n\n/**\n * A plugin that highlights code blocks using Shiki.\n */\nexport const syntaxHighlightPlugin: Plugin<[SyntaxHighlightPluginOptions?], HastNode, HastNode> = (\n options: SyntaxHighlightPluginOptions = {},\n) => {\n return async (tree) => {\n const promises: Promise<void>[] = [];\n\n async function visitor(node: HastElement, index: number, parent: HastElement): Promise<void> {\n if (!parent || index === null || node.tagName !== \"pre\") {\n return;\n }\n\n const codeNode = node.children[0];\n if (\n !codeNode ||\n codeNode.type !== \"element\" ||\n codeNode.tagName !== \"code\" ||\n !codeNode.properties\n ) {\n return;\n }\n\n const lang = getNodeLanguage(codeNode);\n if (typeof lang !== \"string\") {\n return;\n }\n\n const meta = extractCodeMeta(codeNode);\n\n const sourceCode = hastToString(codeNode).trim();\n\n const hastOptions: CodeToHastOptions<BundledLanguage, BundledTheme> = {\n tokenizeTimeLimit: 10_000,\n lang,\n themes: {\n light: \"github-light-default\",\n dark: \"github-dark-default\",\n },\n ...options.shikiHastOptions,\n };\n if (hastOptions.transformers === undefined) {\n hastOptions.transformers = [];\n }\n\n if (options.highlight) {\n hastOptions.transformers.push(\n transformerNotationHighlight({\n ...options.highlight.transformer,\n matchAlgorithm: \"v3\",\n }),\n );\n }\n\n let lineCount = 0;\n hastOptions.transformers.push({\n code(node): void {\n let lineIndex = 0;\n for (const line of node.children.filter(\n (node: HastNode) => node.type === \"element\",\n ) as HastElement[]) {\n line.properties[\"data-line\"] = lineIndex + 1;\n\n if (options.highlight) {\n if (meta.highlight && numericRangeContains(meta.highlight.lineRange, lineIndex)) {\n this.addClassToHast(\n line,\n options.highlight.transformer?.classActiveLine ?? \"highlighted\",\n );\n }\n }\n\n if (\n options.lineNumbers &&\n meta.showLineNumbers &&\n (meta.showLineNumbers.lineRange.length === 0 ||\n numericRangeContains(meta.showLineNumbers.lineRange, lineIndex))\n ) {\n this.addClassToHast(line, options.lineNumbers.className ?? \"line-number\");\n }\n\n if (\n options.commandLine &&\n meta.commandLine &&\n (meta.commandLine.commandRange.length === 0 ||\n numericRangeContains(meta.commandLine.commandRange, lineIndex))\n ) {\n this.addClassToHast(line, options.commandLine.className ?? \"line-command\");\n }\n\n lineIndex++;\n }\n\n lineCount = lineIndex;\n\n if (meta.showLineNumbers) {\n if (typeof node.properties.style !== \"string\") {\n node.properties.style = \"\";\n }\n node.properties.style += `--${\n options.lineNumbers?.widthVariableName ?? \"line-number-width\"\n }:${1 + Math.floor(Math.log10(this.lines.length))}ch;`;\n }\n },\n });\n\n try {\n const hast = await codeToHast(sourceCode, hastOptions);\n\n // Insert highlighted code into parent\n const hastPre = hast.children[0] as HastElement;\n\n const properties: Properties = {\n ...hastPre.properties,\n dataFileName: meta.fileName,\n };\n if (options.includeDataAttributes) {\n if (options.includeDataAttributes.includes(\"language\")) {\n properties.dataLanguage = lang;\n }\n if (options.includeDataAttributes.includes(\"source-code\")) {\n properties.dataSourceCode = sourceCode;\n }\n if (options.includeDataAttributes.includes(\"line-count\")) {\n properties.dataLineCount = lineCount;\n }\n }\n\n parent.children.splice(index, 1, {\n ...hastPre,\n properties,\n });\n } catch (error) {\n if (error instanceof ShikiError) {\n if (error.message.includes(\"Language `math` is not included in this bundle\")) {\n // Skip if the block is math block.\n return;\n }\n }\n throw error;\n }\n }\n\n visit(tree, \"element\", (node: HastElement, index: number, parent: HastElement) => {\n promises.push(visitor(node, index, parent));\n });\n\n await Promise.all(promises);\n\n return tree;\n };\n};\n\nfunction getNodeLanguage(node: HastElement): string | undefined {\n if (!Array.isArray(node.properties.className)) {\n return undefined;\n }\n const prefix = \"language-\";\n const language = node.properties.className.find(\n (name) => typeof name === \"string\" && name.startsWith(prefix),\n ) as string | undefined;\n if (typeof language === \"string\") {\n return language.slice(prefix.length);\n }\n return language;\n}\n"],"mappings":";;;;;;;;;;AA6EA,MAAa,yBACX,UAAwC,CAAC,MACtC;CACH,OAAO,OAAO,SAAS;EACrB,MAAM,WAA4B,CAAC;EAEnC,eAAe,QAAQ,MAAmB,OAAe,QAAoC;GAC3F,IAAI,CAAC,UAAU,UAAU,QAAQ,KAAK,YAAY,OAChD;GAGF,MAAM,WAAW,KAAK,SAAS;GAC/B,IACE,CAAC,YACD,SAAS,SAAS,aAClB,SAAS,YAAY,UACrB,CAAC,SAAS,YAEV;GAGF,MAAM,OAAO,gBAAgB,QAAQ;GACrC,IAAI,OAAO,SAAS,UAClB;GAGF,MAAM,OAAO,gBAAgB,QAAQ;GAErC,MAAM,aAAaA,SAAa,QAAQ,CAAC,CAAC,KAAK;GAE/C,MAAM,cAAgE;IACpE,mBAAmB;IACnB;IACA,QAAQ;KACN,OAAO;KACP,MAAM;IACR;IACA,GAAG,QAAQ;GACb;GACA,IAAI,YAAY,iBAAiB,KAAA,GAC/B,YAAY,eAAe,CAAC;GAG9B,IAAI,QAAQ,WACV,YAAY,aAAa,KACvB,6BAA6B;IAC3B,GAAG,QAAQ,UAAU;IACrB,gBAAgB;GAClB,CAAC,CACH;GAGF,IAAI,YAAY;GAChB,YAAY,aAAa,KAAK,EAC5B,KAAK,MAAY;IACf,IAAI,YAAY;IAChB,KAAK,MAAM,QAAQ,KAAK,SAAS,QAC9B,SAAmB,KAAK,SAAS,SACpC,GAAoB;KAClB,KAAK,WAAW,eAAe,YAAY;KAE3C,IAAI,QAAQ;
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":["hastToString"],"sources":["../../../src/plugins/syntax-highlight/plugin.ts"],"sourcesContent":["import type { Properties } from \"hast\";\nimport type { Plugin } from \"unified\";\n\nimport {\n type TransformerNotationHighlightOptions,\n transformerNotationHighlight,\n} from \"@shikijs/transformers\";\nimport { numericRangeContains } from \"@temelj/iterator\";\nimport { toString as hastToString } from \"hast-util-to-string\";\nimport {\n type BundledLanguage,\n type BundledTheme,\n type CodeToHastOptions,\n codeToHast,\n ShikiError,\n} from \"shiki\";\nimport { visit } from \"unist-util-visit\";\n\nimport type { HastElement, HastNode } from \"../../types\";\n\nimport { extractCodeMeta } from \"./code-meta\";\n\ntype ShikiHastOptions = Partial<CodeToHastOptions<BundledLanguage, BundledTheme>>;\n\ntype SyntaxDataAttribute = \"source-code\" | \"language\" | \"line-count\";\n\n/**\n * Options for {@linkcode syntaxHighlightPlugin}.\n */\nexport interface SyntaxHighlightPluginOptions {\n /**\n * Include these data attributes on the `<pre>` element.\n * These might be useful to have when building custom code components.\n */\n includeDataAttributes?: SyntaxDataAttribute[];\n\n /**\n * Options for the highlight transformer.\n */\n highlight?: {\n transformer?: TransformerNotationHighlightOptions;\n };\n\n /**\n * Options for line numbers.\n */\n lineNumbers?: {\n /**\n * The name of the variable that contains the line number width.\n * This is used for padding the line numbers so that they align.\n */\n widthVariableName?: string;\n /**\n * A class name to be added to the line numbers.\n */\n className?: string;\n };\n\n /**\n * Options for command line.\n */\n commandLine?: {\n /**\n * A class name to be added to the prompt line.\n */\n className?: string;\n };\n\n /**\n * Extra options for the Shiki hast transformer.\n */\n shikiHastOptions?: ShikiHastOptions;\n}\n\n/**\n * A plugin that highlights code blocks using Shiki.\n */\nexport const syntaxHighlightPlugin: Plugin<[SyntaxHighlightPluginOptions?], HastNode, HastNode> = (\n options: SyntaxHighlightPluginOptions = {},\n) => {\n return async (tree) => {\n const promises: Promise<void>[] = [];\n\n async function visitor(node: HastElement, index: number, parent: HastElement): Promise<void> {\n if (!parent || index === null || node.tagName !== \"pre\") {\n return;\n }\n\n const codeNode = node.children[0];\n if (\n !codeNode ||\n codeNode.type !== \"element\" ||\n codeNode.tagName !== \"code\" ||\n !codeNode.properties\n ) {\n return;\n }\n\n const lang = getNodeLanguage(codeNode);\n if (typeof lang !== \"string\") {\n return;\n }\n\n const meta = extractCodeMeta(codeNode);\n\n const sourceCode = hastToString(codeNode).trim();\n\n const hastOptions: CodeToHastOptions<BundledLanguage, BundledTheme> = {\n tokenizeTimeLimit: 10_000,\n lang,\n themes: {\n light: \"github-light-default\",\n dark: \"github-dark-default\",\n },\n ...options.shikiHastOptions,\n };\n if (hastOptions.transformers === undefined) {\n hastOptions.transformers = [];\n }\n\n if (options.highlight) {\n hastOptions.transformers.push(\n transformerNotationHighlight({\n ...options.highlight.transformer,\n matchAlgorithm: \"v3\",\n }),\n );\n }\n\n let lineCount = 0;\n hastOptions.transformers.push({\n code(node): void {\n let lineIndex = 0;\n for (const line of node.children.filter(\n (node: HastNode) => node.type === \"element\",\n ) as HastElement[]) {\n line.properties[\"data-line\"] = lineIndex + 1;\n\n if (options.highlight) {\n if (meta.highlight && numericRangeContains(meta.highlight.lineRange, lineIndex)) {\n this.addClassToHast(\n line,\n options.highlight.transformer?.classActiveLine ?? \"highlighted\",\n );\n }\n }\n\n if (\n options.lineNumbers &&\n meta.showLineNumbers &&\n (meta.showLineNumbers.lineRange.length === 0 ||\n numericRangeContains(meta.showLineNumbers.lineRange, lineIndex))\n ) {\n this.addClassToHast(line, options.lineNumbers.className ?? \"line-number\");\n }\n\n if (\n options.commandLine &&\n meta.commandLine &&\n (meta.commandLine.commandRange.length === 0 ||\n numericRangeContains(meta.commandLine.commandRange, lineIndex))\n ) {\n this.addClassToHast(line, options.commandLine.className ?? \"line-command\");\n }\n\n lineIndex++;\n }\n\n lineCount = lineIndex;\n\n if (meta.showLineNumbers) {\n if (typeof node.properties.style !== \"string\") {\n node.properties.style = \"\";\n }\n node.properties.style += `--${\n options.lineNumbers?.widthVariableName ?? \"line-number-width\"\n }:${1 + Math.floor(Math.log10(this.lines.length))}ch;`;\n }\n },\n });\n\n try {\n const hast = await codeToHast(sourceCode, hastOptions);\n\n // Insert highlighted code into parent\n const hastPre = hast.children[0] as HastElement;\n\n const properties: Properties = {\n ...hastPre.properties,\n dataFileName: meta.fileName,\n };\n if (options.includeDataAttributes) {\n if (options.includeDataAttributes.includes(\"language\")) {\n properties.dataLanguage = lang;\n }\n if (options.includeDataAttributes.includes(\"source-code\")) {\n properties.dataSourceCode = sourceCode;\n }\n if (options.includeDataAttributes.includes(\"line-count\")) {\n properties.dataLineCount = lineCount;\n }\n }\n\n parent.children.splice(index, 1, {\n ...hastPre,\n properties,\n });\n } catch (error) {\n if (error instanceof ShikiError) {\n if (error.message.includes(\"Language `math` is not included in this bundle\")) {\n // Skip if the block is math block.\n return;\n }\n }\n throw error;\n }\n }\n\n visit(tree, \"element\", (node: HastElement, index: number, parent: HastElement) => {\n promises.push(visitor(node, index, parent));\n });\n\n await Promise.all(promises);\n\n return tree;\n };\n};\n\nfunction getNodeLanguage(node: HastElement): string | undefined {\n if (!Array.isArray(node.properties.className)) {\n return undefined;\n }\n const prefix = \"language-\";\n const language = node.properties.className.find(\n (name) => typeof name === \"string\" && name.startsWith(prefix),\n ) as string | undefined;\n if (typeof language === \"string\") {\n return language.slice(prefix.length);\n }\n return language;\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { HastElement as Element, HastNode as Node } from "../../types.mjs";
|
|
2
2
|
import { Plugin } from "unified";
|
|
3
|
-
|
|
4
3
|
//#region src/plugins/tree-processor/plugin.d.ts
|
|
5
4
|
type MdxTreeProcessor = (node: Element, index: number, parent: Element) => void | Promise<void>;
|
|
6
5
|
/**
|
|
7
6
|
* Options for {@linkcode treeProcessorPlugin}.
|
|
8
7
|
*/
|
|
9
8
|
type TreeProcessorPluginOptions = {
|
|
10
|
-
/** The processor. */
|
|
9
|
+
/** The processor. */
|
|
10
|
+
process: MdxTreeProcessor;
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* A plugin that allows to process MDX tree nodes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/tree-processor/plugin.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/tree-processor/plugin.ts"],"mappings":";;;KAMY,oBACV,MAAM,SACN,eACA,QAAQ,mBACE;;;;KAKP;;EAEH,SAAS;;;;;;cAOE,qBAAqB,QAAQ,8BAA8B,MAAU"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temelj/mdx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "MDX processing utilities.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,33 +20,36 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@mdx-js/mdx": "^3.1.1",
|
|
23
|
-
"@shikijs/transformers": "^4.
|
|
23
|
+
"@shikijs/transformers": "^4.3.1",
|
|
24
24
|
"@standard-schema/spec": "^1.1.0",
|
|
25
|
-
"@types/hast": "^3.0.
|
|
25
|
+
"@types/hast": "^3.0.5",
|
|
26
26
|
"github-slugger": "^2.0.0",
|
|
27
27
|
"hast": "^1.0.0",
|
|
28
|
+
"hast-util-from-html-isomorphic": "^2.0.0",
|
|
28
29
|
"hast-util-to-string": "^3.0.1",
|
|
29
|
-
"
|
|
30
|
+
"hast-util-to-text": "^4.0.2",
|
|
31
|
+
"katex": "^0.18.1",
|
|
30
32
|
"remark-frontmatter": "^5.0.0",
|
|
31
33
|
"remark-gfm": "^4.0.1",
|
|
32
34
|
"remark-math": "^6.0.0",
|
|
33
35
|
"remark-parse": "^11.0.0",
|
|
34
|
-
"shiki": "^4.
|
|
36
|
+
"shiki": "^4.3.1",
|
|
35
37
|
"unified": "^11.0.5",
|
|
36
38
|
"unist-util-remove": "^4.0.0",
|
|
37
39
|
"unist-util-visit": "^5.1.0",
|
|
40
|
+
"unist-util-visit-parents": "^6.0.2",
|
|
38
41
|
"vfile": "^6.0.3",
|
|
39
42
|
"vfile-matter": "^5.0.1",
|
|
40
|
-
"@temelj/iterator": "0.
|
|
43
|
+
"@temelj/iterator": "0.13.0",
|
|
41
44
|
"@temelj/standard-schema": "0.1.0"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
47
|
"@types/mdast": "^4.0.4",
|
|
45
|
-
"@types/node": "
|
|
48
|
+
"@types/node": "26.1.1",
|
|
46
49
|
"shx": "^0.4.0",
|
|
47
|
-
"tsdown": "^0.22.
|
|
48
|
-
"typescript": "^
|
|
49
|
-
"vitest": "^4.1.
|
|
50
|
+
"tsdown": "^0.22.14",
|
|
51
|
+
"typescript": "^7.0.2",
|
|
52
|
+
"vitest": "^4.1.10",
|
|
50
53
|
"zod": "^4.4.3"
|
|
51
54
|
},
|
|
52
55
|
"scripts": {
|