Syntax highlighting extension for the marked markdown parser
npx @tessl/cli install tessl/npm-marked-highlight@2.2.0marked-highlight is a syntax highlighting extension for the marked markdown parser. It provides a flexible API that accepts custom highlight functions (synchronous or asynchronous) and integrates seamlessly with popular syntax highlighting libraries like highlight.js and pygmentize.
npm install marked-highlightimport { markedHighlight } from "marked-highlight";For CommonJS:
const { markedHighlight } = require("marked-highlight");UMD (browser):
<script src="https://cdn.jsdelivr.net/npm/marked-highlight/lib/index.umd.js"></script>
<script>
const { markedHighlight } = globalThis.markedHighlight;
</script>marked-highlight integrates with the marked parser using the extension system:
markedHighlight function returns a MarkedExtension object that plugs into marked's parsing pipelinewalkTokens to identify and process code block tokens during parsingcode renderer that applies CSS classes and processes highlighted contentThis architecture allows marked-highlight to integrate seamlessly with any marked instance while maintaining compatibility with other extensions.
import { Marked } from "marked";
import { markedHighlight } from "marked-highlight";
import hljs from 'highlight.js';
const marked = new Marked(
markedHighlight({
emptyLangClass: 'hljs',
langPrefix: 'hljs language-',
highlight(code, lang, info) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
}
})
);
const html = marked.parse(`
\`\`\`javascript
const highlight = "code";
\`\`\`
`);
// Output: <pre><code class="hljs language-javascript">
// <span class="hljs-keyword">const</span> highlight = <span class="hljs-string">"code"</span>;
// </code></pre>import { Marked } from "marked";
import { markedHighlight } from "marked-highlight";
import pygmentize from 'pygmentize-bundled';
const marked = new Marked(
markedHighlight({
async: true,
highlight(code, lang, info) {
return new Promise((resolve, reject) => {
pygmentize({ lang, format: 'html' }, code, function (err, result) {
if (err) {
reject(err);
return;
}
resolve(result.toString());
});
});
}
})
);
const html = await marked.parse(`
\`\`\`javascript
const highlight = "code";
\`\`\`
`);Creates a marked extension for syntax highlighting code blocks with three different calling patterns.
/**
* Creates a marked extension for syntax highlighting with synchronous highlighting function
* @param options - Configuration options with synchronous highlight function
* @returns MarkedExtension to be passed to marked.use()
*/
function markedHighlight(options: SynchronousOptions): MarkedExtension;
/**
* Creates a marked extension for syntax highlighting with asynchronous highlighting function
* @param options - Configuration options with asynchronous highlight function
* @returns MarkedExtension to be passed to marked.use()
*/
function markedHighlight(options: AsynchronousOptions): MarkedExtension;
/**
* Creates a marked extension for syntax highlighting with a direct function
* @param highlightFunction - A synchronous function to apply syntax highlighting
* @returns MarkedExtension to be passed to marked.use()
*/
function markedHighlight(highlightFunction: SyncHighlightFunction): MarkedExtension;Usage Examples:
// Direct function approach
markedHighlight((code, lang) => {
return hljs.highlight(code, { language: lang }).value;
});
// Synchronous options approach
markedHighlight({
highlight: (code, lang) => hljs.highlight(code, { language: lang }).value,
langPrefix: 'hljs language-',
emptyLangClass: 'hljs'
});
// Asynchronous options approach
markedHighlight({
async: true,
highlight: async (code, lang) => {
return await someAsyncHighlighter(code, lang);
}
});/**
* A synchronous function to highlight code
*/
type SyncHighlightFunction = (
code: string,
language: string,
info: string
) => string;
/**
* An asynchronous function to highlight code
*/
type AsyncHighlightFunction = (
code: string,
language: string,
info: string
) => Promise<string>;
/**
* Options for configuring the marked-highlight extension using a synchronous
* highlighting function.
*/
interface SynchronousOptions {
/** Function to highlight code with */
highlight: SyncHighlightFunction;
/**
* Not necessary when using a synchronous highlighting function, but can be
* set without harm (it will make marked.parse() return a promise if true)
*/
async?: boolean;
/**
* The language tag found immediately after the code block opening marker is
* appended to this to form the class attribute added to the <code> element.
* @default 'language-'
*/
langPrefix?: string;
/**
* The class attribute added to the <code> element if the language tag is
* empty.
* @default ''
*/
emptyLangClass?: string;
}
/**
* Options for configuring the marked-highlight extension using an
* asynchronous highlighting function.
*/
interface AsynchronousOptions {
/** Function to highlight code with */
highlight: AsyncHighlightFunction;
/** Must be set to true when using an asynchronous highlight function */
async: true;
/**
* The language tag found immediately after the code block opening marker is
* appended to this to form the class attribute added to the <code> element.
* @default 'language-'
*/
langPrefix?: string;
/**
* The class attribute added to the <code> element if the language tag is
* empty.
* @default ''
*/
emptyLangClass?: string;
}
/**
* MarkedExtension interface from marked library
* This is the return type of markedHighlight() function
*/
interface MarkedExtension {
/** Whether the extension requires async processing */
async: boolean;
/** Token processing function for code blocks */
walkTokens: (token: any) => void | Promise<void>;
/** Indicates use of the new renderer system */
useNewRenderer: boolean;
/** Custom renderer for code blocks */
renderer: {
code: (code: string, infoString: string, escaped: boolean) => string;
};
}The function that transforms raw code into highlighted HTML.
Parameters:
code (string): The raw code to be highlightedlanguage (string): The language tag found immediately after the code block opening marker (e.g., javascript from ```javascript). Only the first word is used if multiple words are present.info (string): The full string after the code block opening marker (e.g., ts twoslash from ```ts twoslash). Empty string for code blocks without language tags.Returns: Highlighted code as HTML string (or Promise for async functions). Returning null will skip highlighting and render the original code with HTML escaping.
Edge Case Behaviors:
ts twoslash becomes language ts)null, the original code is rendered with proper HTML escapinglanguage parameter is empty string and emptyLangClass is appliedSet to true when using an asynchronous highlight function. When true, marked.parse() will return a Promise.
Default: false
A prefix added to the CSS class on the <code> element. The language tag is appended to this prefix.
Default: 'language-'
Example: With langPrefix: 'hljs language-' and language javascript, the resulting class will be hljs language-javascript
The CSS class added to the <code> element when the language tag is empty or not specified.
Default: '' (empty string)
Example: With emptyLangClass: 'hljs', code blocks without language tags will have class="hljs"
The library throws specific errors for common configuration mistakes:
Missing highlight function:
"Must provide highlight function"Thrown when options object is provided without a highlight function.
Async configuration mismatch:
"markedHighlight is not set to async but the highlight function is async. Set the async option to true on markedHighlight to await the async highlight function."Thrown when an async highlight function is used but async: true is not set in options.
import { markedHighlight } from "marked-highlight";
import hljs from 'highlight.js';
const extension = markedHighlight({
langPrefix: 'hljs language-',
highlight(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
}
});import { markedHighlight } from "marked-highlight";
import Prism from 'prismjs';
const extension = markedHighlight({
langPrefix: 'language-',
highlight(code, lang) {
if (Prism.languages[lang]) {
return Prism.highlight(code, Prism.languages[lang], lang);
}
return code;
}
});import { markedHighlight } from "marked-highlight";
const extension = markedHighlight({
async: true,
highlight: async (code, lang) => {
const response = await fetch('/api/highlight', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, language: lang })
});
const result = await response.json();
return result.highlighted;
}
});>=4 <17 (required)The extension is compatible with marked versions 4 through 16 and integrates using marked's extension system.