github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/spyglass/lenses/buildlog/buildlog.ts (about)

     1  function showElem(elem: HTMLElement): void {
     2    elem.className = 'shown';
     3    elem.innerHTML = ansiToHTML(elem.innerHTML);
     4  }
     5  
     6  // given a string containing ansi formatting directives, return a new one
     7  // with designated regions of text marked with the appropriate color directives,
     8  // and with all unknown directives stripped
     9  function ansiToHTML(orig: string): string {
    10    // Given a cmd (like "32" or "0;97"), some enclosed body text, and the original string,
    11    // either return the body wrapped in an element to achieve the desired result, or the
    12    // original string if nothing works.
    13    function annotate(cmd: string, body: string, orig: string): string {
    14      const code = +(cmd.replace('0;', ''));
    15      if (code === 0) {
    16        // reset
    17        return body;
    18      } else if (code === 1) {
    19        // bold
    20        return '<em>' + body + '</em>';
    21      } else if (30 <= code && code <= 37) {
    22        // foreground color
    23        return '<span class="ansi-' + (code - 30) + '">' + body + '</span>';
    24      } else if (90 <= code && code <= 97) {
    25        // foreground color, bright
    26        return '<span class="ansi-' + (code - 90 + 8) + '">' + body + '</span>';
    27      }
    28      return body;  // fallback: don't change anything
    29    }
    30    // Find commands, optionally followed by a bold command, with some content, then a reset command.
    31    // Unpaired commands are *not* handled here, but they're very uncommon.
    32    const filtered = orig.replace(/\033\[([0-9;]*)\w(\033\[1m)?([^\033]*?)\033\[0m/g, (match: string, cmd: string, bold: string, body: string, offset: number, str: string) => {
    33      if (bold !== undefined) {
    34        // normal code + bold
    35        return '<em>' + annotate(cmd, body, str) + '</em>';
    36      }
    37      return annotate(cmd, body, str);
    38    });
    39    // Strip out anything left over.
    40    return filtered.replace(/\033\[([0-9;]*\w)/g, (match: string, cmd: string, offset: number, str: string) => {
    41      console.log('unhandled ansi code: ', cmd, "context:", filtered);
    42      return '';
    43    });
    44  }
    45  
    46  async function handleShowSkipped(this: HTMLDivElement, e: MouseEvent) {
    47    // Don't do anything unless they actually clicked the button.
    48    if (!(e.target instanceof HTMLButtonElement)) {
    49      return;
    50    }
    51    const {artifact, offset, length, startLine} = this.dataset;
    52    const content = await spyglass.request(JSON.stringify({
    53      artifact, offset: +offset!, length: +length!, startLine: +startLine!}));
    54    this.innerHTML = ansiToHTML(content);
    55    showElem(this);
    56  
    57    // Remove the "show all" button if we no longer need it.
    58    const log = document.getElementById(`${artifact}-content`)!;
    59    const skipped = log.querySelectorAll<HTMLElement>(".show-skipped");
    60    if (skipped.length === 0) {
    61      const button = document.querySelector('button.show-all-button')!;
    62      button.parentNode!.removeChild(button);
    63    }
    64    spyglass.contentUpdated();
    65  }
    66  
    67  async function handleShowAll(this: HTMLButtonElement) {
    68    // Remove ourselves immediately.
    69    if (this.parentElement) {
    70      this.parentElement.removeChild(this);
    71    }
    72  
    73    const {artifact} = this.dataset;
    74    const content = await spyglass.request(JSON.stringify({artifact, offset: 0, length: -1}));
    75    document.getElementById(`${artifact}-content`)!.innerHTML = `<tbody class="shown">${ansiToHTML(content)}</tbody>`;
    76    spyglass.contentUpdated();
    77  }
    78  
    79  window.addEventListener('load', () => {
    80    const shown = document.getElementsByClassName("shown");
    81    for (let i = 0; i < shown.length; i++) {
    82      shown[i].innerHTML = ansiToHTML(shown[i].innerHTML);
    83    }
    84  
    85    for (const button of Array.from(document.querySelectorAll<HTMLDivElement>(".show-skipped"))) {
    86      button.addEventListener('click', handleShowSkipped);
    87    }
    88  
    89    for (const button of Array.from(document.querySelectorAll<HTMLButtonElement>("button.show-all-button"))) {
    90      button.addEventListener('click', handleShowAll);
    91    }
    92  });