Sfoglia il codice sorgente

fix(renderer): Vendor ansicolor as typescript

Fixes #15635

Importing ansicolor from node_modules or vendored as is failed because
there is no ES5 transpiler configured for ES6 libs.

- remove ansicolor from package.json
- add ansicolor to public/vendor/ansicolor and port to typescript
- adapt all ansicolor imports
- add `public/vendor` as a path to be considered by ts compiler
David Kaltschmidt 6 anni fa
parent
commit
26236b4bc3

+ 0 - 1
package.json

@@ -169,7 +169,6 @@
     "angular-native-dragdrop": "1.2.2",
     "angular-route": "1.6.6",
     "angular-sanitize": "1.6.6",
-    "ansicolor": "1.1.78",
     "baron": "^3.0.3",
     "brace": "^0.10.0",
     "classnames": "^2.2.6",

+ 1 - 1
public/app/features/explore/LogMessageAnsi.tsx

@@ -1,5 +1,5 @@
 import React, { PureComponent } from 'react';
-import ansicolor from 'ansicolor';
+import ansicolor from 'vendor/ansicolor/ansicolor';
 
 interface Style {
   [key: string]: string;

+ 1 - 1
public/app/plugins/datasource/loki/result_transformer.ts

@@ -1,4 +1,4 @@
-import ansicolor from 'ansicolor';
+import ansicolor from 'vendor/ansicolor/ansicolor';
 import _ from 'lodash';
 import moment from 'moment';
 

+ 471 - 0
public/vendor/ansicolor/ansicolor.ts

@@ -0,0 +1,471 @@
+// Vendored and converted to TS, source: https://github.com/xpl/ansicolor/blob/b82360563ed29de444dc7618b9236191e0a77096/ansicolor.js
+// License: Unlicense, author: https://github.com/xpl
+
+const O = Object;
+
+/*  See https://misc.flogisoft.com/bash/tip_colors_and_formatting
+    ------------------------------------------------------------------------ */
+
+const colorCodes = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'lightGray', '', 'default'],
+  colorCodesLight = [
+    'darkGray',
+    'lightRed',
+    'lightGreen',
+    'lightYellow',
+    'lightBlue',
+    'lightMagenta',
+    'lightCyan',
+    'white',
+    '',
+  ],
+  styleCodes = ['', 'bright', 'dim', 'italic', 'underline', '', '', 'inverse'],
+  asBright = {
+    red: 'lightRed',
+    green: 'lightGreen',
+    yellow: 'lightYellow',
+    blue: 'lightBlue',
+    magenta: 'lightMagenta',
+    cyan: 'lightCyan',
+    black: 'darkGray',
+    lightGray: 'white',
+  },
+  types = {
+    0: 'style',
+    2: 'unstyle',
+    3: 'color',
+    9: 'colorLight',
+    4: 'bgColor',
+    10: 'bgColorLight',
+  },
+  subtypes = {
+    color: colorCodes,
+    colorLight: colorCodesLight,
+    bgColor: colorCodes,
+    bgColorLight: colorCodesLight,
+    style: styleCodes,
+    unstyle: styleCodes,
+  };
+
+/*  ------------------------------------------------------------------------ */
+
+const clean = obj => {
+  for (const k in obj) {
+    if (!obj[k]) {
+      delete obj[k];
+    }
+  }
+  return O.keys(obj).length === 0 ? undefined : obj;
+};
+
+/*  ------------------------------------------------------------------------ */
+
+class Color {
+  background: string;
+  name: string;
+  brightness: number;
+
+  constructor(background?, name?, brightness?) {
+    this.background = background;
+    this.name = name;
+    this.brightness = brightness;
+  }
+
+  get inverse() {
+    return new Color(!this.background, this.name || (this.background ? 'black' : 'white'), this.brightness);
+  }
+
+  get clean() {
+    return clean({
+      name: this.name === 'default' ? '' : this.name,
+      bright: this.brightness === Code.bright,
+      dim: this.brightness === Code.dim,
+    });
+  }
+
+  defaultBrightness(value) {
+    return new Color(this.background, this.name, this.brightness || value);
+  }
+
+  css(inverted) {
+    const color = inverted ? this.inverse : this;
+
+    const rgbName = (color.brightness === Code.bright && asBright[color.name]) || color.name;
+
+    const prop = color.background ? 'background:' : 'color:',
+      rgb = Colors.rgb[rgbName],
+      alpha = this.brightness === Code.dim ? 0.5 : 1;
+
+    return rgb
+      ? prop + 'rgba(' + [...rgb, alpha].join(',') + ');'
+      : !color.background && alpha < 1 ? 'color:rgba(0,0,0,0.5);' : ''; // Chrome does not support 'opacity' property...
+  }
+}
+
+/*  ------------------------------------------------------------------------ */
+
+class Code {
+  static reset = 0;
+  static bright = 1;
+  static dim = 2;
+  static inverse = 7;
+  static noBrightness = 22;
+  static noItalic = 23;
+  static noUnderline = 24;
+  static noInverse = 27;
+  static noColor = 39;
+  static noBgColor = 49;
+
+  value: number;
+
+  constructor(n?) {
+    if (n !== undefined) {
+      this.value = Number(n);
+    }
+  }
+
+  get type() {
+    return types[Math.floor(this.value / 10)];
+  }
+
+  get subtype() {
+    return subtypes[this.type][this.value % 10];
+  }
+
+  get str() {
+    return this.value ? '\u001b[' + this.value + 'm' : '';
+  }
+
+  static str(x) {
+    return new Code(x).str;
+  }
+
+  get isBrightness() {
+    return this.value === Code.noBrightness || this.value === Code.bright || this.value === Code.dim;
+  }
+}
+
+/*  ------------------------------------------------------------------------ */
+
+const replaceAll = (str, a, b) => str.split(a).join(b);
+
+/*  ANSI brightness codes do not overlap, e.g. "{bright}{dim}foo" will be rendered bright (not dim).
+    So we fix it by adding brightness canceling before each brightness code, so the former example gets
+    converted to "{noBrightness}{bright}{noBrightness}{dim}foo" – this way it gets rendered as expected.
+ */
+
+const denormalizeBrightness = s => s.replace(/(\u001b\[(1|2)m)/g, '\u001b[22m$1');
+const normalizeBrightness = s => s.replace(/\u001b\[22m(\u001b\[(1|2)m)/g, '$1');
+
+const wrap = (x, openCode, closeCode) => {
+  const open = Code.str(openCode),
+    close = Code.str(closeCode);
+
+  return String(x)
+    .split('\n')
+    .map(line => denormalizeBrightness(open + replaceAll(normalizeBrightness(line), close, open) + close))
+    .join('\n');
+};
+
+/*  ------------------------------------------------------------------------ */
+
+const camel = (a, b) => a + b.charAt(0).toUpperCase() + b.slice(1);
+
+const stringWrappingMethods = (() =>
+  [
+    ...colorCodes.map(
+      (k, i) =>
+        !k
+          ? []
+          : [
+              // color methods
+
+              [k, 30 + i, Code.noColor],
+              [camel('bg', k), 40 + i, Code.noBgColor],
+            ]
+    ),
+
+    ...colorCodesLight.map(
+      (k, i) =>
+        !k
+          ? []
+          : [
+              // light color methods
+
+              [k, 90 + i, Code.noColor],
+              [camel('bg', k), 100 + i, Code.noBgColor],
+            ]
+    ),
+
+    /* THIS ONE IS FOR BACKWARDS COMPATIBILITY WITH PREVIOUS VERSIONS (had 'bright' instead of 'light' for backgrounds)
+         */
+    ...['', 'BrightRed', 'BrightGreen', 'BrightYellow', 'BrightBlue', 'BrightMagenta', 'BrightCyan'].map(
+      (k, i) => (!k ? [] : [['bg' + k, 100 + i, Code.noBgColor]])
+    ),
+
+    ...styleCodes.map(
+      (k, i) =>
+        !k
+          ? []
+          : [
+              // style methods
+
+              [k, i, k === 'bright' || k === 'dim' ? Code.noBrightness : 20 + i],
+            ]
+    ),
+  ].reduce((a, b) => a.concat(b)))();
+
+/*  ------------------------------------------------------------------------ */
+
+const assignStringWrappingAPI = (target, wrapBefore = target) =>
+  stringWrappingMethods.reduce(
+    (memo, [k, open, close]) =>
+      O.defineProperty(memo, k, {
+        get: () => assignStringWrappingAPI(str => wrapBefore(wrap(str, open, close))),
+      }),
+
+    target
+  );
+
+/*  ------------------------------------------------------------------------ */
+
+const TEXT = 0,
+  BRACKET = 1,
+  CODE = 2;
+
+function rawParse(s) {
+  let state = TEXT,
+    buffer = '',
+    text = '',
+    code = '',
+    codes = [];
+  const spans = [];
+
+  for (let i = 0, n = s.length; i < n; i++) {
+    const c = s[i];
+
+    buffer += c;
+
+    switch (state) {
+      case TEXT: {
+        if (c === '\u001b') {
+          state = BRACKET;
+          buffer = c;
+        } else {
+          text += c;
+        }
+        break;
+      }
+      case BRACKET:
+        if (c === '[') {
+          state = CODE;
+          code = '';
+          codes = [];
+        } else {
+          state = TEXT;
+          text += buffer;
+        }
+        break;
+
+      case CODE:
+        if (c >= '0' && c <= '9') {
+          code += c;
+        } else if (c === ';') {
+          codes.push(new Code(code));
+          code = '';
+        } else if (c === 'm' && code.length) {
+          codes.push(new Code(code));
+          for (const code of codes) {
+            spans.push({ text, code });
+            text = '';
+          }
+          state = TEXT;
+        } else {
+          state = TEXT;
+          text += buffer;
+        }
+    }
+  }
+
+  if (state !== TEXT) {
+    text += buffer;
+  }
+
+  if (text) {
+    spans.push({ text, code: new Code() });
+  }
+
+  return spans;
+}
+
+/*  ------------------------------------------------------------------------ */
+
+/**
+ * Represents an ANSI-escaped string.
+ */
+export default class Colors {
+  spans: any[];
+  static names = stringWrappingMethods.map(([k]) => k);
+  static rgb = {
+    black: [0, 0, 0],
+    darkGray: [100, 100, 100],
+    lightGray: [200, 200, 200],
+    white: [255, 255, 255],
+
+    red: [204, 0, 0],
+    lightRed: [255, 51, 0],
+
+    green: [0, 204, 0],
+    lightGreen: [51, 204, 51],
+
+    yellow: [204, 102, 0],
+    lightYellow: [255, 153, 51],
+
+    blue: [0, 0, 255],
+    lightBlue: [26, 140, 255],
+
+    magenta: [204, 0, 204],
+    lightMagenta: [255, 0, 255],
+
+    cyan: [0, 153, 255],
+    lightCyan: [0, 204, 255],
+  };
+
+  /**
+   * @param {string} s a string containing ANSI escape codes.
+   */
+  constructor(s?) {
+    this.spans = s ? rawParse(s) : [];
+  }
+
+  get str() {
+    return this.spans.reduce((str, p) => str + p.text + p.code.str, '');
+  }
+
+  get parsed() {
+    let color, bgColor, brightness, styles;
+
+    function reset() {
+      (color = new Color()),
+        (bgColor = new Color(true /* background */)),
+        (brightness = undefined),
+        (styles = new Set());
+    }
+
+    reset();
+
+    return O.assign(new Colors(), {
+      spans: this.spans
+        .map(span => {
+          const c = span.code;
+
+          const inverted = styles.has('inverse'),
+            underline = styles.has('underline') ? 'text-decoration: underline;' : '',
+            italic = styles.has('italic') ? 'font-style: italic;' : '',
+            bold = brightness === Code.bright ? 'font-weight: bold;' : '';
+
+          const foreColor = color.defaultBrightness(brightness);
+
+          const styledSpan = O.assign(
+            { css: bold + italic + underline + foreColor.css(inverted) + bgColor.css(inverted) },
+            clean({ bold: !!bold, color: foreColor.clean, bgColor: bgColor.clean }),
+            span
+          );
+
+          for (const k of styles) {
+            styledSpan[k] = true;
+          }
+
+          if (c.isBrightness) {
+            brightness = c.value;
+          } else if (span.code.value !== undefined) {
+            if (span.code.value === Code.reset) {
+              reset();
+            } else {
+              switch (span.code.type) {
+                case 'color':
+                case 'colorLight':
+                  color = new Color(false, c.subtype);
+                  break;
+
+                case 'bgColor':
+                case 'bgColorLight':
+                  bgColor = new Color(true, c.subtype);
+                  break;
+
+                case 'style':
+                  styles.add(c.subtype);
+                  break;
+                case 'unstyle':
+                  styles.delete(c.subtype);
+                  break;
+              }
+            }
+          }
+
+          return styledSpan;
+        })
+        .filter(s => s.text.length > 0),
+    });
+  }
+
+  /*  Outputs with Chrome DevTools-compatible format     */
+
+  get asChromeConsoleLogArguments() {
+    const spans = this.parsed.spans;
+
+    return [spans.map(s => '%c' + s.text).join(''), ...spans.map(s => s.css)];
+  }
+
+  get browserConsoleArguments() /* LEGACY, DEPRECATED */ {
+    return this.asChromeConsoleLogArguments;
+  }
+
+  /**
+   * @desc installs String prototype extensions
+   * @example
+   * require ('ansicolor').nice
+   * console.log ('foo'.bright.red)
+   */
+  static get nice() {
+    Colors.names.forEach(k => {
+      if (!(k in String.prototype)) {
+        O.defineProperty(String.prototype, k, {
+          get: function() {
+            return Colors[k](this);
+          },
+        });
+      }
+    });
+
+    return Colors;
+  }
+
+  /**
+   * @desc parses a string containing ANSI escape codes
+   * @return {Colors} parsed representation.
+   */
+  static parse(s) {
+    return new Colors(s).parsed;
+  }
+
+  /**
+   * @desc strips ANSI codes from a string
+   * @param {string} s a string containing ANSI escape codes.
+   * @return {string} clean string.
+   */
+  static strip(s) {
+    return s.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g, ''); // hope V8 caches the regexp
+  }
+
+  /**
+   * @example
+   * const spans = [...ansi.parse ('\u001b[7m\u001b[7mfoo\u001b[7mbar\u001b[27m')]
+   */
+  [Symbol.iterator]() {
+    return this.spans[Symbol.iterator]();
+  }
+}
+
+/*  ------------------------------------------------------------------------ */
+
+assignStringWrappingAPI(Colors, str => str);

+ 1 - 1
tsconfig.json

@@ -32,5 +32,5 @@
       "sass": ["sass"]
     }
   },
-  "include": ["public/app/**/*.ts", "public/app/**/*.tsx", "public/test/**/*.ts"]
+  "include": ["public/app/**/*.ts", "public/app/**/*.tsx", "public/test/**/*.ts", "public/vendor/**/*.ts"]
 }

+ 0 - 5
yarn.lock

@@ -2690,11 +2690,6 @@ ansi-styles@~1.0.0:
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
   integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
 
-ansicolor@1.1.78:
-  version "1.1.78"
-  resolved "https://registry.yarnpkg.com/ansicolor/-/ansicolor-1.1.78.tgz#4c1f1dbef81ff3e1292e6f95b4bfb8ba51212db9"
-  integrity sha512-mdNo/iRwUyb4Z0L8AthEV4BZ3TlSWr6YakKtItA48ufGBzYYtTVp+gX6bkweKTfs7wGpUepOz+qHrTPqfBus2Q==
-
 ansicolors@~0.3.2:
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"