diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4ab162c8..a26bd3d8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,9 +25,6 @@ jobs: - script: | yarn lint displayName: 'Lint' - - script: | - yarn test-coverage - displayName: 'Generate and publish coverage' - job: macOS pool: @@ -46,6 +43,11 @@ jobs: - script: | yarn lint displayName: 'Lint' + - script: | + yarn test-coverage + export COVERALLS_GIT_BRANCH=$BUILD_SOURCEBRANCH + yarn coveralls + displayName: 'Generate and publish coverage' - job: Windows pool: diff --git a/package.json b/package.json index 4bdac048..f83e498c 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "merge-stream": "^1.0.1", "node-pty": "0.7.6", "nodemon": "1.10.2", - "npm-run-all": "^4.1.2", "nyc": "^11.8.0", "sorcery": "^0.10.0", "source-map-loader": "^0.2.3", @@ -51,7 +50,8 @@ "start": "node demo/start", "start-zmodem": "node demo/zmodem/app", "lint": "tslint 'src/**/*.ts' './demo/**/*.ts'", - "test": "npm-run-all mocha lint", + "test": "npm run mocha", + "posttest": "npm run lint", "test-debug": "node --inspect-brk node_modules/.bin/gulp test", "test-suite": "gulp mocha-suite --test", "test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha", diff --git a/src/Linkifier.test.ts b/src/Linkifier.test.ts index c4f6016f..22e797aa 100644 --- a/src/Linkifier.test.ts +++ b/src/Linkifier.test.ts @@ -42,6 +42,7 @@ describe('Linkifier', () => { beforeEach(() => { terminal = new MockTerminal(); terminal.cols = 100; + terminal.rows = 10; terminal.buffer = new MockBuffer(); (terminal.buffer).setLines(new CircularList(20)); terminal.buffer.ydisp = 0; @@ -64,6 +65,7 @@ describe('Linkifier', () => { function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, links: {x: number, length: number}[], done: MochaDone): void { addRow(rowText); linkifier.registerLinkMatcher(linkMatcherRegex, () => {}); + terminal.rows = terminal.buffer.lines.length - 1; linkifier.linkifyRows(); // Allow linkify to happen setTimeout(() => { diff --git a/src/Linkifier.ts b/src/Linkifier.ts index 4d84b1a7..0dd33a85 100644 --- a/src/Linkifier.ts +++ b/src/Linkifier.ts @@ -81,18 +81,22 @@ export class Linkifier extends EventEmitter implements ILinkifier { */ private _linkifyRows(): void { this._rowsTimeoutId = null; + const buffer = this._terminal.buffer; - // Ensure the row exists - const absoluteRowIndexStart = this._terminal.buffer.ydisp + this._rowsToLinkify.start; - if (absoluteRowIndexStart >= this._terminal.buffer.lines.length) { + // Ensure the start row exists + const absoluteRowIndexStart = buffer.ydisp + this._rowsToLinkify.start; + if (absoluteRowIndexStart >= buffer.lines.length) { return; } + // Invalidate bad end row values (if a resize happened) + const absoluteRowIndexEnd = buffer.ydisp + Math.min(this._rowsToLinkify.end, this._terminal.rows) + 1; + // iterate over the range of unwrapped content strings within start..end (excluding) // _doLinkifyRow gets full unwrapped lines with the start row as buffer offset for every matcher // for wrapped content over several rows the iterator might return rows outside the viewport // we skip those later in _doLinkifyRow - const iterator = this._terminal.buffer.iterator(false, absoluteRowIndexStart, this._terminal.buffer.ydisp + this._rowsToLinkify.end + 1); + const iterator = buffer.iterator(false, absoluteRowIndexStart, absoluteRowIndexEnd); while (iterator.hasNext()) { const lineData: IBufferStringIteratorResult = iterator.next(); for (let i = 0; i < this._linkMatchers.length; i++) { diff --git a/src/Viewport.ts b/src/Viewport.ts index e89676d9..50d04457 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -22,6 +22,7 @@ export class Viewport extends Disposable implements IViewport { private _lastRecordedViewportHeight: number = 0; private _lastRecordedBufferHeight: number = 0; private _lastTouchY: number; + private _lastScrollTop: number = 0; // Stores a partial line amount when scrolling, this is used to keep track of how much of a line // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a @@ -97,18 +98,36 @@ export class Viewport extends Disposable implements IViewport { * Updates dimensions and synchronizes the scroll area if necessary. */ public syncScrollArea(): void { + // If buffer height changed if (this._lastRecordedBufferLength !== this._terminal.buffer.lines.length) { - // If buffer height changed this._lastRecordedBufferLength = this._terminal.buffer.lines.length; this._refresh(); - } else if (this._lastRecordedViewportHeight !== (this._terminal).renderer.dimensions.canvasHeight) { - // If viewport height changed + return; + } + + // If viewport height changed + if (this._lastRecordedViewportHeight !== (this._terminal).renderer.dimensions.canvasHeight) { this._refresh(); - } else { - // If size has changed, refresh viewport - if (this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) { - this._refresh(); - } + return; + } + + // If the buffer position doesn't match last scroll top + const newScrollTop = this._terminal.buffer.ydisp * this._currentRowHeight; + if (this._lastScrollTop !== newScrollTop) { + this._refresh(); + return; + } + + // If element's scroll top changed, this can happen when hiding the element + if (this._lastScrollTop !== this._viewportElement.scrollTop) { + this._refresh(); + return; + } + + // If row height changed + if (this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) { + this._refresh(); + return; } } @@ -118,6 +137,9 @@ export class Viewport extends Disposable implements IViewport { * @param ev The scroll event. */ private _onScroll(ev: Event): void { + // Record current scroll top position + this._lastScrollTop = this._viewportElement.scrollTop; + // Don't attempt to scroll if the element is not visible, otherwise scrollTop will be corrupt // which causes the terminal to scroll the buffer to the top if (!this._viewportElement.offsetParent) { @@ -130,8 +152,7 @@ export class Viewport extends Disposable implements IViewport { return; } - - const newRow = Math.round(this._viewportElement.scrollTop / this._currentRowHeight); + const newRow = Math.round(this._lastScrollTop / this._currentRowHeight); const diff = newRow - this._terminal.buffer.ydisp; this._terminal.scrollLines(diff, true); } diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 1df9c3ea..1590d6e2 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -5,7 +5,7 @@ import { IRenderLayer, IColorSet, IRenderDimensions } from './Types'; import { CharData, ITerminal } from '../Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from './atlas/Types'; +import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/Types'; import BaseCharAtlas from './atlas/BaseCharAtlas'; import { acquireCharAtlas } from './atlas/CharAtlasCache'; import { CHAR_DATA_CHAR_INDEX } from '../Buffer'; @@ -22,6 +22,19 @@ export abstract class BaseRenderLayer implements IRenderLayer { protected _charAtlas: BaseCharAtlas; + /** + * An object that's reused when drawing glyphs in order to reduce GC. + */ + private _currentGlyphIdentifier: IGlyphIdentifier = { + chars: '', + code: 0, + bg: 0, + fg: 0, + bold: false, + dim: false, + italic: false + }; + constructor( private _container: HTMLElement, id: string, @@ -38,6 +51,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { public dispose(): void { this._container.removeChild(this._canvas); + this._charAtlas.dispose(); } private _initCanvas(): void { @@ -245,9 +259,16 @@ export abstract class BaseRenderLayer implements IRenderLayer { const drawInBrightColor = terminal.options.drawBoldTextInBrightColors && bold && fg < 8 && fg !== INVERTED_DEFAULT_COLOR; fg += drawInBrightColor ? 8 : 0; + this._currentGlyphIdentifier.chars = chars; + this._currentGlyphIdentifier.code = code; + this._currentGlyphIdentifier.bg = bg; + this._currentGlyphIdentifier.fg = fg; + this._currentGlyphIdentifier.bold = bold && terminal.options.enableBold; + this._currentGlyphIdentifier.dim = dim; + this._currentGlyphIdentifier.italic = italic; const atlasDidDraw = this._charAtlas && this._charAtlas.draw( this._ctx, - {chars, code, bg, fg, bold: bold && terminal.options.enableBold, dim, italic}, + this._currentGlyphIdentifier, x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop ); diff --git a/src/renderer/atlas/BaseCharAtlas.ts b/src/renderer/atlas/BaseCharAtlas.ts index 50d35faa..ee69b381 100644 --- a/src/renderer/atlas/BaseCharAtlas.ts +++ b/src/renderer/atlas/BaseCharAtlas.ts @@ -4,10 +4,13 @@ */ import { IGlyphIdentifier } from './Types'; +import { IDisposable } from 'xterm'; -export default abstract class BaseCharAtlas { +export default abstract class BaseCharAtlas implements IDisposable { private _didWarmUp: boolean = false; + public dispose(): void { } + /** * Perform any work needed to warm the cache before it can be used. May be called multiple times. * Implement _doWarmUp instead if you only want to get called once. diff --git a/src/renderer/atlas/DynamicCharAtlas.ts b/src/renderer/atlas/DynamicCharAtlas.ts index f6df365e..e67fe4f0 100644 --- a/src/renderer/atlas/DynamicCharAtlas.ts +++ b/src/renderer/atlas/DynamicCharAtlas.ts @@ -10,6 +10,7 @@ import BaseCharAtlas from './BaseCharAtlas'; import { DEFAULT_ANSI_COLORS } from '../ColorManager'; import { clearColor } from '../../shared/atlas/CharAtlasGenerator'; import LRUMap from './LRUMap'; +import { isFirefox, isSafari } from '../../shared/utils/Browser'; // In practice we're probably never going to exhaust a texture this large. For debugging purposes, // however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. @@ -29,14 +30,29 @@ const TRANSPARENT_COLOR = { // cache. const FRAME_CACHE_DRAW_LIMIT = 100; +/** + * The number of milliseconds to wait before generating the ImageBitmap, this is to debounce/batch + * the operation as window.createImageBitmap is asynchronous. + */ +const GLYPH_BITMAP_COMMIT_DELAY = 100; + interface IGlyphCacheValue { index: number; isEmpty: boolean; + inBitmap: boolean; } -function getGlyphCacheKey(glyph: IGlyphIdentifier): string { - const styleFlags = (glyph.bold ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1); - return `${glyph.bg}_${glyph.fg}_${styleFlags}${glyph.chars}`; +function getGlyphCacheKey(glyph: IGlyphIdentifier): number { + // Note that this only returns a valid key when code < 256 + // Layout: + // 0b00000000000000000000000000000001: italic (1) + // 0b00000000000000000000000000000010: dim (1) + // 0b00000000000000000000000000000100: bold (1) + // 0b00000000000000000000111111111000: fg (9) + // 0b00000000000111111111000000000000: bg (9) + // 0b00011111111000000000000000000000: code (8) + // 0b11100000000000000000000000000000: unused (3) + return glyph.code << 21 | glyph.bg << 12 | glyph.fg << 3 | (glyph.bold ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1); } export default class DynamicCharAtlas extends BaseCharAtlas { @@ -57,6 +73,15 @@ export default class DynamicCharAtlas extends BaseCharAtlas { private _drawToCacheCount: number = 0; + // An array of glyph keys that are waiting on the bitmap to be generated. + private _glyphsWaitingOnBitmap: IGlyphCacheValue[] = []; + + // The timeout that is used to batch bitmap generation so it's not requested for every new glyph. + private _bitmapCommitTimeout: number | null = null; + + // The bitmap to draw from, this is much faster on other browsers than others. + private _bitmap: ImageBitmap | null = null; + constructor(document: Document, private _config: ICharAtlasConfig) { super(); this._cacheCanvas = document.createElement('canvas'); @@ -82,6 +107,13 @@ export default class DynamicCharAtlas extends BaseCharAtlas { // document.body.appendChild(this._cacheCanvas); } + public dispose(): void { + if (this._bitmapCommitTimeout !== null) { + window.clearTimeout(this._bitmapCommitTimeout); + this._bitmapCommitTimeout = null; + } + } + public beginFrame(): void { this._drawToCacheCount = 0; } @@ -92,6 +124,11 @@ export default class DynamicCharAtlas extends BaseCharAtlas { x: number, y: number ): boolean { + // Space is always an empty cell, special case this as it's so common + if (glyph.code === 32) { + return true; + } + const glyphKey = getGlyphCacheKey(glyph); const cacheValue = this._cacheMap.get(glyphKey); if (cacheValue !== null && cacheValue !== undefined) { @@ -124,11 +161,12 @@ export default class DynamicCharAtlas extends BaseCharAtlas { return glyph.code < 256; } - private _toCoordinates(index: number): [number, number] { - return [ - (index % this._width) * this._config.scaledCharWidth, - Math.floor(index / this._width) * this._config.scaledCharHeight - ]; + private _toCoordinateX(index: number): number { + return (index % this._width) * this._config.scaledCharWidth; + } + + private _toCoordinateY(index: number): number { + return Math.floor(index / this._width) * this._config.scaledCharHeight; } private _drawFromCache( @@ -141,9 +179,10 @@ export default class DynamicCharAtlas extends BaseCharAtlas { if (cacheValue.isEmpty) { return; } - const [cacheX, cacheY] = this._toCoordinates(cacheValue.index); + const cacheX = this._toCoordinateX(cacheValue.index); + const cacheY = this._toCoordinateY(cacheValue.index); ctx.drawImage( - this._cacheCanvas, + cacheValue.inBitmap ? this._bitmap : this._cacheCanvas, cacheX, cacheY, this._config.scaledCharWidth, @@ -230,13 +269,58 @@ export default class DynamicCharAtlas extends BaseCharAtlas { } // copy the data from imageData to _cacheCanvas - const [x, y] = this._toCoordinates(index); + const x = this._toCoordinateX(index); + const y = this._toCoordinateY(index); // putImageData doesn't do any blending, so it will overwrite any existing cache entry for us this._cacheCtx.putImageData(imageData, x, y); - return { + // Add the glyph and queue it to the bitmap (if the browser supports it) + const cacheValue = { index, - isEmpty + isEmpty, + inBitmap: false }; + this._addGlyphToBitmap(cacheValue); + + return cacheValue; + } + + private _addGlyphToBitmap(cacheValue: IGlyphCacheValue): void { + // Support is patchy for createImageBitmap at the moment, pass a canvas back + // if support is lacking as drawImage works there too. Firefox is also + // included here as ImageBitmap appears both buggy and has horrible + // performance (tested on v55). + if (!('createImageBitmap' in window) || isFirefox || isSafari) { + return; + } + + // Add the glyph to the queue + this._glyphsWaitingOnBitmap.push(cacheValue); + + // Check if bitmap generation timeout already exists + if (this._bitmapCommitTimeout !== null) { + return; + } + + this._bitmapCommitTimeout = window.setTimeout(() => this._generateBitmap(), GLYPH_BITMAP_COMMIT_DELAY); + } + + private _generateBitmap(): void { + const glyphsMovingToBitmap = this._glyphsWaitingOnBitmap; + this._glyphsWaitingOnBitmap = []; + window.createImageBitmap(this._cacheCanvas).then(bitmap => { + // Set bitmap + this._bitmap = bitmap; + + // Mark all new glyphs as in bitmap, excluding glyphs that came in after + // the bitmap was requested + for (let i = 0; i < glyphsMovingToBitmap.length; i++) { + const value = glyphsMovingToBitmap[i]; + // It doesn't matter if the value was already evicted, it will be + // released from memory after this block if so. + value.inBitmap = true; + } + }); + this._bitmapCommitTimeout = null; } } diff --git a/src/renderer/atlas/LRUMap.test.ts b/src/renderer/atlas/LRUMap.test.ts index ba01e410..197d1159 100644 --- a/src/renderer/atlas/LRUMap.test.ts +++ b/src/renderer/atlas/LRUMap.test.ts @@ -9,57 +9,57 @@ import LRUMap from './LRUMap'; describe('LRUMap', () => { it('can be used to store and retrieve values', () => { const map = new LRUMap(10); - map.set('keya', 'valuea'); - map.set('keyb', 'valueb'); - map.set('keyc', 'valuec'); - assert.strictEqual(map.get('keya'), 'valuea'); - assert.strictEqual(map.get('keyb'), 'valueb'); - assert.strictEqual(map.get('keyc'), 'valuec'); + map.set(1, 'valuea'); + map.set(2, 'valueb'); + map.set(3, 'valuec'); + assert.strictEqual(map.get(1), 'valuea'); + assert.strictEqual(map.get(2), 'valueb'); + assert.strictEqual(map.get(3), 'valuec'); }); it('maintains a size from insertions', () => { const map = new LRUMap(10); assert.strictEqual(map.size, 0); - map.set('a', 'value'); + map.set(1, 'value'); assert.strictEqual(map.size, 1); - map.set('b', 'value'); + map.set(2, 'value'); assert.strictEqual(map.size, 2); }); it('deletes the oldest entry when the capacity is exceeded', () => { const map = new LRUMap(4); - map.set('a', 'value'); - map.set('b', 'value'); - map.set('c', 'value'); - map.set('d', 'value'); - map.set('e', 'value'); - assert.isNull(map.get('a')); - assert.isNotNull(map.get('b')); - assert.isNotNull(map.get('c')); - assert.isNotNull(map.get('d')); - assert.isNotNull(map.get('e')); + map.set(1, 'value'); + map.set(2, 'value'); + map.set(3, 'value'); + map.set(4, 'value'); + map.set(5, 'value'); + assert.isNull(map.get(1)); + assert.isNotNull(map.get(2)); + assert.isNotNull(map.get(3)); + assert.isNotNull(map.get(4)); + assert.isNotNull(map.get(5)); assert.strictEqual(map.size, 4); }); it('prevents a recently accessed entry from getting deleted', () => { const map = new LRUMap(2); - map.set('a', 'value'); - map.set('b', 'value'); - map.get('a'); + map.set(1, 'value'); + map.set(2, 'value'); + map.get(1); // a would normally get deleted here, except that we called get() - map.set('c', 'value'); - assert.isNotNull(map.get('a')); + map.set(3, 'value'); + assert.isNotNull(map.get(1)); // b got deleted instead of a - assert.isNull(map.get('b')); - assert.isNotNull(map.get('c')); + assert.isNull(map.get(2)); + assert.isNotNull(map.get(3)); }); it('supports mutation', () => { const map = new LRUMap(10); - map.set('keya', 'oldvalue'); - map.set('keya', 'newvalue'); + map.set(1, 'oldvalue'); + map.set(1, 'newvalue'); // mutation doesn't change the size assert.strictEqual(map.size, 1); - assert.strictEqual(map.get('keya'), 'newvalue'); + assert.strictEqual(map.get(1), 'newvalue'); }); }); diff --git a/src/renderer/atlas/LRUMap.ts b/src/renderer/atlas/LRUMap.ts index eccfbfea..d7e01ec6 100644 --- a/src/renderer/atlas/LRUMap.ts +++ b/src/renderer/atlas/LRUMap.ts @@ -6,12 +6,12 @@ interface ILinkedListNode { prev: ILinkedListNode; next: ILinkedListNode; - key: string; + key: number; value: T; } export default class LRUMap { - private _map: { [key: string]: ILinkedListNode } = {}; + private _map: { [key: number]: ILinkedListNode } = {}; private _head: ILinkedListNode = null; private _tail: ILinkedListNode = null; private _nodePool: ILinkedListNode[] = []; @@ -68,7 +68,7 @@ export default class LRUMap { } } - public get(key: string): T | null { + public get(key: number): T | null { // This is unsafe: We're assuming our keyspace doesn't overlap with Object.prototype. However, // it's faster than calling hasOwnProperty, and in our case, it would never overlap. const node = this._map[key]; @@ -80,12 +80,23 @@ export default class LRUMap { return null; } + /** + * Gets a value from a key without marking it as the most recently used item. + */ + public peekValue(key: number): T | null { + const node = this._map[key]; + if (node !== undefined) { + return node.value; + } + return null; + } + public peek(): T | null { const head = this._head; return head === null ? null : head.value; } - public set(key: string, value: T): void { + public set(key: number, value: T): void { // This is unsafe: See note above. let node = this._map[key]; if (node !== undefined) { diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 9a2ef469..8f51c4ef 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -4,7 +4,7 @@ */ import { IRenderer, IRenderDimensions, IColorSet } from '../Types'; -import { ITerminal, CharacterJoinerHandler } from '../../Types'; +import { ILinkHoverEvent, ITerminal, CharacterJoinerHandler, LinkHoverEventTypes } from '../../Types'; import { ITheme } from 'xterm'; import { EventEmitter } from '../../common/EventEmitter'; import { ColorManager } from '../ColorManager'; @@ -79,6 +79,9 @@ export class DomRenderer extends EventEmitter implements IRenderer { this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); this._terminal.screenElement.appendChild(this._rowContainer); this._terminal.screenElement.appendChild(this._selectionContainer); + + this._terminal.linkifier.on(LinkHoverEventTypes.HOVER, (e: ILinkHoverEvent) => this._onLinkHover(e)); + this._terminal.linkifier.on(LinkHoverEventTypes.LEAVE, (e: ILinkHoverEvent) => this._onLinkLeave(e)); } public dispose(): void { @@ -338,4 +341,23 @@ export class DomRenderer extends EventEmitter implements IRenderer { public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return -1; } public deregisterCharacterJoiner(joinerId: number): boolean { return false; } + + private _onLinkHover(e: ILinkHoverEvent): void { + this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, true); + } + + private _onLinkLeave(e: ILinkHoverEvent): void { + this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, false); + } + + private _setCellUnderline(x: number, x2: number, y: number, y2: number, cols: number, enabled: boolean): void { + while (x !== x2 || y !== y2) { + const span = this._rowElements[y].children[x]; + span.style.textDecoration = enabled ? 'underline' : 'none'; + x = (x + 1) % cols; + if (x === 0) { + y++; + } + } + } } diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index cde81a37..5efa0dd7 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -159,7 +159,6 @@ declare module 'xterm' { * when canvas is too slow for the environment. The following features do * not work when the DOM renderer is used: * - * - Link underlines * - Line height * - Letter spacing * - Cursor blink diff --git a/yarn.lock b/yarn.lock index f12043f7..8cebcd9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -338,7 +338,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: @@ -942,7 +942,7 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: @@ -1333,7 +1333,7 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.4, cross-spawn@^6.0.5: +cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: @@ -1490,13 +1490,6 @@ defaults@^1.0.0: dependencies: clone "^1.0.2" -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -1701,24 +1694,6 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.4.3: - version "1.12.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.45" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" @@ -2119,10 +2094,6 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - foreground-child@^1.5.3, foreground-child@^1.5.6: version "1.5.6" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" @@ -2201,7 +2172,7 @@ fsevents@^1.0.0, fsevents@^1.2.2: nan "^2.9.2" node-pre-gyp "^0.10.0" -function-bind@^1.0.2, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -2638,7 +2609,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.0, has@^1.0.1: +has@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: @@ -2897,10 +2868,6 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -2913,10 +2880,6 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -3037,12 +3000,6 @@ is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - is-relative@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" @@ -3053,10 +3010,6 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -3715,10 +3668,6 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -4107,20 +4056,6 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-run-all@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.3.tgz#49f15b55a66bb4101664ce270cb18e7103f8f185" - dependencies: - ansi-styles "^3.2.0" - chalk "^2.1.0" - cross-spawn "^6.0.4" - memorystream "^0.3.1" - minimatch "^3.0.4" - ps-tree "^1.1.0" - read-pkg "^3.0.0" - shell-quote "^1.6.1" - string.prototype.padend "^3.0.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4200,10 +4135,6 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-keys@^1.0.8: - version "1.0.12" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" - object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -4645,7 +4576,7 @@ prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" -ps-tree@^1.0.1, ps-tree@^1.1.0: +ps-tree@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" dependencies: @@ -5504,14 +5435,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string.prototype.padend@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.4.3" - function-bind "^1.0.2" - string_decoder@^1.0.0, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"