# All files / src/lib/markdown-it/plugins markdown-it-icons.ts

100% Statements 61/61
100% Branches 29/29
100% Functions 10/10
100% Lines 59/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    22x
    22x

    22x

    22x

    9x

    22x
    7x

    22x
    6x

    6x
    1x

    5x

    22x
    3x

    3x
    1x

    2x
    2x
    2x
    2x

    22x
    11x
    11x

    1x
    1x

    1x
    1x

    1x
    1x

    3x
    3x

    11x

    22x
    13x

    22x

    22x
    46x
    46x
    46x

    46x
    7x
    39x
    6x
    33x
    3x
    30x
    11x
    19x
    6x

    13x

    22x
    5x

    5x
    4x

    5x
    5x

    22x

    42x

    22x
     // 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) =>
      `<span aria-hidden="true" class="glyphicon glyphicon-${iconFontName}"></span>`;

    // handler function for octicon icons
    const handleOcticon = (iconFontName: string, iconClass?: string) => {
      const octiconIcon = getOcticonIcon(iconFontName);
      // ensure octicons are valid
      if (octiconIcon === null) {
        return '<span aria-hidden="true"></span>';
      }
      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 '<span aria-hidden="true"></span>';
      }
      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 `<span aria-hidden="true" class="${materialIconsClass} align-middle">`
        + `${iconFontName.split('-').join('_')}</span>`;
    };

    // handler function for font awesome icons
    const handleFontAwesome = (iconFontType: string, iconFontName: string) =>
      `<span aria-hidden="true" class="${iconFontType} fa-${iconFontName}"></span>`;

    // Handler function for Bootstrap Icons
    const handleBootstrapIcon = (iconFontName: string) => `<i class="bi-${iconFontName}"></i>`;

    // 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 };