// import the necessary packages
import octicons from '@primer/octicons';
import * as cheerio from 'cheerio';
// markdown-it-regexp type definitions are undefined
// @ts-ignore
import markdownItRegExp from 'markdown-it-regexp';
// regular expression to match the icon patterns
const ICON_REGEXP
= /:(fa[brs]|fa-brands|fa-solid|glyphicon|octicon|octiconlight|mi[forst]|bi)-([a-z0-9-]+)~?([a-z0-9-]+)?:/;
// function to get the octicon icons
function getOcticonIcon(iconName: string) {
// Indexing octicons varies based on @types/primer__octicons version
// @ts-ignore
return octicons[iconName] ?? null;
}
// handler function for glyphicon icons
const handleGlyphicon = (iconFontName: string) =>
``;
// handler function for octicon icons
const handleOcticon = (iconFontName: string, iconClass?: string) => {
const octiconIcon = getOcticonIcon(iconFontName);
// ensure octicons are valid
if (octiconIcon === null) {
return '';
}
return iconClass ? octiconIcon.toSVG({ class: iconClass }) : octiconIcon.toSVG();
};
// handler function for light octicon icons
const handleOcticonLight = (iconFontName: string, iconClass?: string) => {
const octiconIcon = getOcticonIcon(iconFontName);
// ensure octicons are valid
if (octiconIcon === null) {
return '';
}
const octiconIconHtml = iconClass ? octiconIcon.toSVG({ class: iconClass }) : octiconIcon.toSVG();
const $ = cheerio.load(octiconIconHtml);
$('svg').attr('style', 'color: #fff');
return $.html();
};
// handler function for material icons
const handleMaterialIcon = (iconFontType: string, iconFontName: string) => {
let materialIconsClass = 'material-icons';
switch (iconFontType) {
case 'mio':
materialIconsClass += '-outlined';
break;
case 'mir':
materialIconsClass += '-round';
break;
case 'mis':
materialIconsClass += '-sharp';
break;
case 'mit':
materialIconsClass += '-two-tone';
break;
default:
// .material-icons generates 'Filled' style icons; hence, no suffix is needed for 'mif'.
}
// Use .align-middle by default to vertically-align the icon with its surrounding text (if any).
// Also, replace dashes (-) with underscores (_) to format the icon name properly.
return ``
+ `${iconFontName.split('-').join('_')}`;
};
// handler function for font awesome icons
const handleFontAwesome = (iconFontType: string, iconFontName: string) =>
``;
// Handler function for Bootstrap Icons
const handleBootstrapIcon = (iconFontName: string) => ``;
// function to get the respective icon html based on the icon font type
const getIconHtml = (match: string[]) => {
const iconFontType = match[1];
const iconFontName = match[2];
const iconClass = match[3];
if (iconFontType === 'glyphicon') {
return handleGlyphicon(iconFontName);
} else if (iconFontType === 'octicon') {
return handleOcticon(iconFontName, iconClass);
} else if (iconFontType === 'octiconlight') {
return handleOcticonLight(iconFontName, iconClass);
} else if (iconFontType.startsWith('mi')) {
return handleMaterialIcon(iconFontType, iconFontName);
} else if (iconFontType === 'bi') {
return handleBootstrapIcon(iconFontName);
}
return handleFontAwesome(iconFontType, iconFontName);
};
// function to process the icon string and get the icon html
const processIconString = (iconStr: string) => {
let icon = iconStr;
if (!iconStr.startsWith(':') && !iconStr.endsWith(':')) {
icon = `:${iconStr}:`;
}
const match = icon.match(ICON_REGEXP);
return match ? getIconHtml(match) : null;
};
// create a markdown-it plugin to process the icon strings in the markdown
/**
* A Markdown-It plugin that replaces icon syntax matching `ICON_REGEXP` with corresponding HTML.
*
* This plugin uses a regular expression to detect icon patterns in Markdown content,
* and transforms them into HTML using the `getIconHtml` function.
*/
const markdownItIconsPlugin = markdownItRegExp(
ICON_REGEXP,
(match: string[]) => getIconHtml(match),
);
export { markdownItIconsPlugin, processIconString };