Commit 73980adb by Torkel Ödegaard Committed by GitHub

Merge pull request #15826 from grafana/davkal/15635-vendor-ansicolor-ts

fix(renderer): Vendor ansicolor as typescript
parents b63ef540 26236b4b
......@@ -172,7 +172,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",
......
import React, { PureComponent } from 'react';
import ansicolor from 'ansicolor';
import ansicolor from 'vendor/ansicolor/ansicolor';
interface Style {
[key: string]: string;
......
import ansicolor from 'ansicolor';
import ansicolor from 'vendor/ansicolor/ansicolor';
import _ from 'lodash';
import moment from 'moment';
......
// 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);
......@@ -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"]
}
......@@ -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"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment