go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/tools/markdown/plugins/bug_line.ts (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import MarkdownIt from 'markdown-it';
    16  import Token from 'markdown-it/lib/token';
    17  
    18  import { specialLine } from './special_line';
    19  
    20  /**
    21   * Replace text tokens with bug links.
    22   */
    23  function processToken(srcToken: Token): Token[] {
    24    const reBug = /\b([-_a-zA-Z0-9]+:)?#?\d+\b/g;
    25    let pos = 0;
    26    let match = reBug.exec(srcToken.content);
    27    const newTokens: Token[] = [];
    28    let token: Token;
    29    while (match) {
    30      const bugStr = match[0];
    31  
    32      // Insert the text between the last processed character and the first
    33      // character of the new match as a text node.
    34      if (match.index !== pos) {
    35        token = new Token('text', '', 0);
    36        token.content = srcToken.content.slice(pos, match.index);
    37        newTokens.push(token);
    38        pos = match.index;
    39      }
    40  
    41      // Insert the bug link nodes.
    42      token = new Token('link_open', 'a', 1);
    43      token.attrs = [
    44        [
    45          'href',
    46          `https://crbug.com/${bugStr.replace('#', '').replace(':', '/')}`,
    47        ],
    48      ];
    49      token.level = srcToken.level;
    50      newTokens.push(token);
    51  
    52      token = new Token('text', '', 0);
    53      token.content = bugStr;
    54      token.level = srcToken.level + 1;
    55      pos += bugStr.length;
    56      newTokens.push(token);
    57  
    58      token = new Token('link_close', 'a', -1);
    59      token.level = srcToken.level;
    60      newTokens.push(token);
    61  
    62      match = reBug.exec(srcToken.content);
    63    }
    64  
    65    // If there are remaining unprocessed characters, add them as a text node.
    66    if (pos !== srcToken.content.length) {
    67      token = new Token('text', '', 0);
    68      token.content = srcToken.content.slice(pos);
    69      newTokens.push(token);
    70    }
    71  
    72    return newTokens;
    73  }
    74  
    75  /**
    76   * Support converting bug identifiers (e.g. 'proj/123', '234') in bug lines
    77   * (e.g. 'Bugs: proj/123, 234', 'BUG=345') to crbug links.
    78   *
    79   * For instance
    80   * ```
    81   * Bug: 123, proj/234
    82   * ```
    83   * will be converted to
    84   * ```html
    85   * <p>Bug:
    86   *   <a href="https://crbug.com/123">123</a>
    87   *   <a href="https://crbug.com/proj/234">proj/234</a>
    88   * </p>
    89   * ```
    90   */
    91  export function bugLine(md: MarkdownIt) {
    92    md.use(specialLine, /^(>| )*(bugs?)[:=]/i, processToken);
    93  }