From 9b60f00020cad9822797ac066b0e70553502284a Mon Sep 17 00:00:00 2001 From: Clay Anderson <469582+supersonicclay@users.noreply.github.com> Date: Wed, 27 Nov 2019 20:39:51 -0700 Subject: [PATCH] Measure distance mode + tooltips (#299) --- .../layers/editable-geojson-layer.md | 4 +- docs/api-reference/modes/overview.md | 20 +++ examples/advanced/example.js | 70 ++++++-- modules/edit-modes/package.json | 1 + modules/edit-modes/src/index.js | 1 + modules/edit-modes/src/lib/edit-mode.js | 4 + .../edit-modes/src/lib/geojson-edit-mode.js | 6 + .../src/lib/measure-distance-mode.js | 134 ++++++++++++++ modules/edit-modes/src/types.js | 5 + .../measure-distance-mode.test.js.snap | 169 ++++++++++++++++++ .../test/lib/measure-distance-mode.test.js | 122 +++++++++++++ .../src/layers/editable-geojson-layer.js | 18 +- modules/main/src/index.js | 1 + yarn.lock | 105 ++++++++++- 14 files changed, 639 insertions(+), 21 deletions(-) create mode 100644 modules/edit-modes/src/lib/measure-distance-mode.js create mode 100644 modules/edit-modes/test/lib/__snapshots__/measure-distance-mode.test.js.snap create mode 100644 modules/edit-modes/test/lib/measure-distance-mode.test.js diff --git a/docs/api-reference/layers/editable-geojson-layer.md b/docs/api-reference/layers/editable-geojson-layer.md index 36e79b876..81cb0fff0 100644 --- a/docs/api-reference/layers/editable-geojson-layer.md +++ b/docs/api-reference/layers/editable-geojson-layer.md @@ -248,11 +248,11 @@ Edit handle objects can be represented by either points or icons. `editHandlePoi #### `editHandlePointOutline` (Boolean, optional) -* Default: `false` +* Default: `true` #### `editHandlePointStrokeWidth` (Number, optional) -* Default: `1` +* Default: `2` #### `editHandlePointRadiusMinPixels` (Number, optional) diff --git a/docs/api-reference/modes/overview.md b/docs/api-reference/modes/overview.md index b27f4bc5d..17113e741 100644 --- a/docs/api-reference/modes/overview.md +++ b/docs/api-reference/modes/overview.md @@ -133,6 +133,26 @@ User can split a polygon by drawing a new `LineString` feature on top of the pol * If the clicked position is inside the polygon, it will not split the polygon +## [MeasureDistanceMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/measure-distance-mode.js) + +User can measure a distance between two points. + +### ModeConfig + +The following options can be provided in the `modeConfig` object: + +* `turfOptions` (Object, optional) + * `options` object passed to turf's [distance](https://turfjs.org/docs/#distance) function + * Default: `undefined` + +* `formatTooltip` (Function, optional) + * Function to format tooltip text (argument is the numeric distance) + * Default: `(distance) => parseFloat(distance).toFixed(2) + units` + +* `measurementCallback` (Function, optional) + * Function to call as measurements are calculated + * Default: `undefined` + ## [ElevationMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/elevation-mode.js) User can move a point up and down. diff --git a/examples/advanced/example.js b/examples/advanced/example.js index df20b7414..696b7e92c 100644 --- a/examples/advanced/example.js +++ b/examples/advanced/example.js @@ -31,6 +31,7 @@ import { DrawEllipseUsingThreePointsMode, DrawRectangleUsingThreePointsMode, Draw90DegreePolygonMode, + MeasureDistanceMode, ViewMode, CompositeMode, SnappableMode, @@ -78,19 +79,9 @@ const initialViewport = { const ALL_MODES = [ { category: 'View', - modes: [{ label: 'View', mode: ViewMode }] - }, - { - category: 'Alter', modes: [ - { label: 'Modify', mode: ModifyMode }, - { label: 'Elevation', mode: ElevationMode }, - { label: 'Translate', mode: new SnappableMode(new TranslateMode()) }, - { label: 'Rotate', mode: RotateMode }, - { label: 'Scale', mode: ScaleMode }, - { label: 'Duplicate', mode: DuplicateMode }, - { label: 'Extrude', mode: ExtrudeMode }, - { label: 'Split', mode: SplitPolygonMode } + { label: 'View', mode: ViewMode }, + { label: 'Measure Distance', mode: MeasureDistanceMode } ] }, { @@ -108,6 +99,19 @@ const ALL_MODES = [ { label: 'Draw Ellipse Using 3 Points', mode: DrawEllipseUsingThreePointsMode } ] }, + { + category: 'Alter', + modes: [ + { label: 'Modify', mode: ModifyMode }, + { label: 'Elevation', mode: ElevationMode }, + { label: 'Translate', mode: new SnappableMode(new TranslateMode()) }, + { label: 'Rotate', mode: RotateMode }, + { label: 'Scale', mode: ScaleMode }, + { label: 'Duplicate', mode: DuplicateMode }, + { label: 'Extrude', mode: ExtrudeMode }, + { label: 'Split', mode: SplitPolygonMode } + ] + }, { category: 'Composite', modes: [{ label: 'Draw LineString + Modify', mode: COMPOSITE_MODE }] @@ -525,6 +529,32 @@ export default class Example extends Component< ); } + _renderMeasureDistanceControls() { + return ( + + Units + + + + + ); + } + _renderModeConfigControls() { const controls = []; @@ -543,6 +573,9 @@ export default class Example extends Component< if (this.state.mode instanceof SnappableMode) { controls.push(this._renderSnappingControls()); } + if (this.state.mode === MeasureDistanceMode) { + controls.push(this._renderMeasureDistanceControls()); + } return controls; } @@ -807,9 +840,14 @@ export default class Example extends Component< } // Demonstrate how to override sub layer properties - let _subLayerProps = null; + let _subLayerProps = { + tooltips: { + getColor: [255, 255, 255, 255] + } + }; + if (this.state.editHandleType === 'elevated') { - _subLayerProps = { + _subLayerProps = Object.assign(_subLayerProps, { guides: { _subLayerProps: { points: { @@ -818,11 +856,11 @@ export default class Example extends Component< } } } - }; + }); } if (this.state.pathMarkerLayer) { - _subLayerProps = Object.assign(_subLayerProps || {}, { + _subLayerProps = Object.assign(_subLayerProps, { geojson: { _subLayerProps: { 'line-strings': { diff --git a/modules/edit-modes/package.json b/modules/edit-modes/package.json index 81b814dde..b68d9d8be 100644 --- a/modules/edit-modes/package.json +++ b/modules/edit-modes/package.json @@ -67,6 +67,7 @@ "@turf/transform-scale": ">=4.0.0", "@turf/transform-translate": ">=4.0.0", "@turf/union": ">=4.0.0", + "memoizee": "^0.4.14", "viewport-mercator-project": ">=6.0.0" } } diff --git a/modules/edit-modes/src/index.js b/modules/edit-modes/src/index.js index aea10d315..05ff0fd8e 100644 --- a/modules/edit-modes/src/index.js +++ b/modules/edit-modes/src/index.js @@ -27,6 +27,7 @@ export { ImmutableFeatureCollection } from './lib/immutable-feature-collection.j // Other modes export { ViewMode } from './lib/view-mode.js'; +export { MeasureDistanceMode } from './lib/measure-distance-mode.js'; export { CompositeMode } from './lib/composite-mode.js'; export { SnappableMode } from './lib/snappable-mode.js'; diff --git a/modules/edit-modes/src/lib/edit-mode.js b/modules/edit-modes/src/lib/edit-mode.js index 9b0003341..f295b8966 100644 --- a/modules/edit-modes/src/lib/edit-mode.js +++ b/modules/edit-modes/src/lib/edit-mode.js @@ -6,6 +6,7 @@ import type { PointerMoveEvent, StartDraggingEvent, StopDraggingEvent, + Tooltip, ModeProps } from '../types.js'; @@ -24,4 +25,7 @@ export interface EditMode { // Return features that can be used as a guide for editing the data getGuides(props: ModeProps): TGuides; + + // Return tooltips + getTooltips(props: ModeProps): Tooltip[]; } diff --git a/modules/edit-modes/src/lib/geojson-edit-mode.js b/modules/edit-modes/src/lib/geojson-edit-mode.js index 60459600b..9626e57e4 100644 --- a/modules/edit-modes/src/lib/geojson-edit-mode.js +++ b/modules/edit-modes/src/lib/geojson-edit-mode.js @@ -11,6 +11,7 @@ import type { StartDraggingEvent, StopDraggingEvent, Pick, + Tooltip, ModeProps } from '../types.js'; import type { @@ -39,6 +40,7 @@ export type EditHandle = { export type GeoJsonEditAction = EditAction; const DEFAULT_EDIT_HANDLES: EditHandle[] = []; +const DEFAULT_TOOLTIPS: Tooltip[] = []; // Main interface for `EditMode`s that edit GeoJSON export type GeoJsonEditMode = EditMode; @@ -75,6 +77,10 @@ export class BaseGeoJsonEditMode implements EditMode): Tooltip[] { + return DEFAULT_TOOLTIPS; + } + getSelectedFeature(props: ModeProps): ?Feature { if (props.selectedIndexes.length === 1) { return props.data.features[props.selectedIndexes[0]]; diff --git a/modules/edit-modes/src/lib/measure-distance-mode.js b/modules/edit-modes/src/lib/measure-distance-mode.js new file mode 100644 index 000000000..928d03ff5 --- /dev/null +++ b/modules/edit-modes/src/lib/measure-distance-mode.js @@ -0,0 +1,134 @@ +// @flow + +import turfDistance from '@turf/distance'; +import memoize from 'memoizee'; +import type { + ClickEvent, + PointerMoveEvent, + StartDraggingEvent, + StopDraggingEvent, + Tooltip, + ModeProps +} from '../types.js'; +import type { FeatureCollection, Position } from '../geojson-types.js'; +import { BaseGeoJsonEditMode } from './geojson-edit-mode.js'; + +const DEFAULT_TOOLTIPS = []; + +export class MeasureDistanceMode extends BaseGeoJsonEditMode { + startingPoint = null; + endingPoint = null; + endingPointLocked = false; + + _setEndingPoint(mapCoords: Position) { + this.endingPoint = { + type: 'Feature', + properties: { + guideType: 'editHandle', + editHandleType: 'existing' + }, + geometry: { + type: 'Point', + coordinates: mapCoords + } + }; + } + + _getTooltips = memoize((modeConfig, startingPoint, endingPoint) => { + let tooltips = DEFAULT_TOOLTIPS; + + if (startingPoint && endingPoint) { + const { formatTooltip, turfOptions, measurementCallback } = modeConfig || {}; + const units = (turfOptions && turfOptions.units) || 'kilometers'; + + const distance = turfDistance(startingPoint, endingPoint, turfOptions); + + let text; + if (formatTooltip) { + text = formatTooltip(distance); + } + if (!formatTooltip) { + // By default, round to 2 decimal places and append units + text = `${parseFloat(distance).toFixed(2)} ${units}`; + } + + if (measurementCallback) { + measurementCallback(distance); + } + + tooltips = [ + { + position: endingPoint.geometry.coordinates, + text + } + ]; + } + + return tooltips; + }); + + handleClick(event: ClickEvent, props: ModeProps): void { + if (!this.startingPoint || this.endingPointLocked) { + this.startingPoint = { + type: 'Feature', + properties: { + guideType: 'editHandle', + editHandleType: 'existing' + }, + geometry: { + type: 'Point', + coordinates: event.mapCoords + } + }; + this.endingPoint = null; + this.endingPointLocked = false; + } else if (this.startingPoint) { + this._setEndingPoint(event.mapCoords); + this.endingPointLocked = true; + } + } + + // Called when the pointer moved, regardless of whether the pointer is down, up, and whether something was picked + handlePointerMove(event: PointerMoveEvent, props: ModeProps): void { + if (this.startingPoint && !this.endingPointLocked) { + this._setEndingPoint(event.mapCoords); + } + + props.onUpdateCursor('cell'); + } + + // Called when the pointer went down on something rendered by this layer and the pointer started to move + handleStartDragging(event: StartDraggingEvent, props: ModeProps): void {} + + // Called when the pointer went down on something rendered by this layer, the pointer moved, and now the pointer is up + handleStopDragging(event: StopDraggingEvent, props: ModeProps): void {} + + // Return features that can be used as a guide for editing the data + getGuides(props: ModeProps): FeatureCollection { + const features = []; + if (this.startingPoint) { + features.push(this.startingPoint); + } + if (this.endingPoint) { + features.push(this.endingPoint); + } + if (this.startingPoint && this.endingPoint) { + features.push({ + type: 'Feature', + properties: { guideType: 'tentative' }, + geometry: { + type: 'LineString', + coordinates: [ + this.startingPoint.geometry.coordinates, + this.endingPoint.geometry.coordinates + ] + } + }); + } + return { type: 'FeatureCollection', features }; + } + + getTooltips(props: ModeProps): Tooltip[] { + return this._getTooltips(props.modeConfig, this.startingPoint, this.endingPoint); + } +} diff --git a/modules/edit-modes/src/types.js b/modules/edit-modes/src/types.js index 389e517e8..a3099f39d 100644 --- a/modules/edit-modes/src/types.js +++ b/modules/edit-modes/src/types.js @@ -74,6 +74,11 @@ export type PointerMoveEvent = { sourceEvent: any }; +export type Tooltip = { + position: Position, + text: string +}; + export type ModeProps = { // The data being edited, this can be an array or an object data: TData, diff --git a/modules/edit-modes/test/lib/__snapshots__/measure-distance-mode.test.js.snap b/modules/edit-modes/test/lib/__snapshots__/measure-distance-mode.test.js.snap new file mode 100644 index 000000000..61b90076c --- /dev/null +++ b/modules/edit-modes/test/lib/__snapshots__/measure-distance-mode.test.js.snap @@ -0,0 +1,169 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`one click + pointer move guides are two points + line string 1`] = ` +Object { + "features": Array [ + Object { + "geometry": Object { + "coordinates": Array [ + 1, + 2, + ], + "type": "Point", + }, + "properties": Object { + "editHandleType": "existing", + "guideType": "editHandle", + }, + "type": "Feature", + }, + Object { + "geometry": Object { + "coordinates": Array [ + 3, + 4, + ], + "type": "Point", + }, + "properties": Object { + "editHandleType": "existing", + "guideType": "editHandle", + }, + "type": "Feature", + }, + Object { + "geometry": Object { + "coordinates": Array [ + Array [ + 1, + 2, + ], + Array [ + 3, + 4, + ], + ], + "type": "LineString", + }, + "properties": Object { + "guideType": "tentative", + }, + "type": "Feature", + }, + ], + "type": "FeatureCollection", +} +`; + +exports[`one click + pointer move tooltip contains distance 1`] = ` +Array [ + Object { + "position": Array [ + 3, + 4, + ], + "text": "314.28 kilometers", + }, +] +`; + +exports[`one click guides are a single point 1`] = ` +Object { + "features": Array [ + Object { + "geometry": Object { + "coordinates": Array [ + 1, + 2, + ], + "type": "Point", + }, + "properties": Object { + "editHandleType": "existing", + "guideType": "editHandle", + }, + "type": "Feature", + }, + ], + "type": "FeatureCollection", +} +`; + +exports[`two clicks + pointer move tooltip contains distance 1`] = ` +Array [ + Object { + "position": Array [ + 3, + 4, + ], + "text": "314.28 kilometers", + }, +] +`; + +exports[`two clicks guides are two points + line string 1`] = ` +Object { + "features": Array [ + Object { + "geometry": Object { + "coordinates": Array [ + 1, + 2, + ], + "type": "Point", + }, + "properties": Object { + "editHandleType": "existing", + "guideType": "editHandle", + }, + "type": "Feature", + }, + Object { + "geometry": Object { + "coordinates": Array [ + 3, + 4, + ], + "type": "Point", + }, + "properties": Object { + "editHandleType": "existing", + "guideType": "editHandle", + }, + "type": "Feature", + }, + Object { + "geometry": Object { + "coordinates": Array [ + Array [ + 1, + 2, + ], + Array [ + 3, + 4, + ], + ], + "type": "LineString", + }, + "properties": Object { + "guideType": "tentative", + }, + "type": "Feature", + }, + ], + "type": "FeatureCollection", +} +`; + +exports[`two clicks tooltip contains distance 1`] = ` +Array [ + Object { + "position": Array [ + 3, + 4, + ], + "text": "314.28 kilometers", + }, +] +`; diff --git a/modules/edit-modes/test/lib/measure-distance-mode.test.js b/modules/edit-modes/test/lib/measure-distance-mode.test.js new file mode 100644 index 000000000..dd2befda3 --- /dev/null +++ b/modules/edit-modes/test/lib/measure-distance-mode.test.js @@ -0,0 +1,122 @@ +// @flow +/* eslint-env jest */ + +import { MeasureDistanceMode } from '../../src/lib/measure-distance-mode.js'; +import { + createFeatureCollectionProps, + createClickEvent, + createPointerMoveEvent +} from '../test-utils.js'; + +describe('move without click', () => { + let mode; + beforeEach(() => { + mode = new MeasureDistanceMode(); + mode.handlePointerMove(createPointerMoveEvent(), createFeatureCollectionProps()); + }); + + it('guides are empty', () => { + const guides = mode.getGuides(createFeatureCollectionProps()); + expect(guides).toEqual({ type: 'FeatureCollection', features: [] }); + }); + + it('tooltips are empty', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips).toEqual([]); + }); +}); + +describe('one click', () => { + let mode; + beforeEach(() => { + mode = new MeasureDistanceMode(); + mode.handleClick(createClickEvent([1, 2]), createFeatureCollectionProps()); + }); + + it('guides are a single point', () => { + const guides = mode.getGuides(createFeatureCollectionProps()); + expect(guides).toMatchSnapshot(); + }); + + it('tooltips are empty', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips).toEqual([]); + }); +}); + +describe('one click + pointer move', () => { + let mode; + beforeEach(() => { + mode = new MeasureDistanceMode(); + mode.handleClick(createClickEvent([1, 2]), createFeatureCollectionProps()); + mode.handlePointerMove(createPointerMoveEvent([3, 4]), createFeatureCollectionProps()); + }); + + it('guides are two points + line string', () => { + const guides = mode.getGuides(createFeatureCollectionProps()); + expect(guides).toMatchSnapshot(); + }); + + it('tooltip contains distance', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips).toMatchSnapshot(); + }); +}); + +describe('two clicks', () => { + let mode; + beforeEach(() => { + mode = new MeasureDistanceMode(); + mode.handleClick(createClickEvent([1, 2]), createFeatureCollectionProps()); + mode.handleClick(createClickEvent([3, 4]), createFeatureCollectionProps()); + }); + + it('guides are two points + line string', () => { + const guides = mode.getGuides(createFeatureCollectionProps()); + expect(guides).toMatchSnapshot(); + }); + + it('tooltip contains distance', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips).toMatchSnapshot(); + }); + + it('can measure kilometers', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips[0].text).toContain('kilometers'); + }); + + it('can measure miles', () => { + const tooltips = mode.getTooltips( + createFeatureCollectionProps({ modeConfig: { turfOptions: { units: 'miles' } } }) + ); + expect(tooltips[0].text).toContain('miles'); + }); + + it('can format distance', () => { + const tooltips = mode.getTooltips( + createFeatureCollectionProps({ modeConfig: { formatTooltip: String } }) + ); + expect(tooltips[0].text).toEqual('314.28368918020476'); + }); +}); + +describe('two clicks + pointer move', () => { + let mode; + beforeEach(() => { + mode = new MeasureDistanceMode(); + mode.handleClick(createClickEvent([1, 2]), createFeatureCollectionProps()); + mode.handleClick(createClickEvent([3, 4]), createFeatureCollectionProps()); + mode.handlePointerMove(createPointerMoveEvent([4, 5]), createFeatureCollectionProps()); + }); + + it('ending point is clicked point not hovered point', () => { + const guides = mode.getGuides(createFeatureCollectionProps()); + expect(guides.features[1].geometry.coordinates).toEqual([3, 4]); + }); + + it('tooltip contains distance', () => { + const tooltips = mode.getTooltips(createFeatureCollectionProps()); + expect(tooltips).toMatchSnapshot(); + }); +}); diff --git a/modules/layers/src/layers/editable-geojson-layer.js b/modules/layers/src/layers/editable-geojson-layer.js index 43699e52a..06eb8610c 100644 --- a/modules/layers/src/layers/editable-geojson-layer.js +++ b/modules/layers/src/layers/editable-geojson-layer.js @@ -1,7 +1,7 @@ // @flow /* eslint-env browser */ -import { GeoJsonLayer, ScatterplotLayer, IconLayer } from '@deck.gl/layers'; +import { GeoJsonLayer, ScatterplotLayer, IconLayer, TextLayer } from '@deck.gl/layers'; import { ViewMode, @@ -252,7 +252,7 @@ export default class EditableGeoJsonLayer extends EditableLayer { let layers: any = [new GeoJsonLayer(subLayerProps)]; - layers = layers.concat(this.createGuidesLayers()); + layers = layers.concat(this.createGuidesLayers(), this.createTooltipsLayers()); return layers; } @@ -428,6 +428,20 @@ export default class EditableGeoJsonLayer extends EditableLayer { return [layer]; } + createTooltipsLayers() { + const mode = this.getActiveMode(); + const tooltips = mode.getTooltips(this.getModeProps(this.props)); + + const layer = new TextLayer( + this.getSubLayerProps({ + id: `tooltips`, + data: tooltips + }) + ); + + return [layer]; + } + onLayerClick(event: ClickEvent) { this.getActiveMode().handleClick(event, this.getModeProps(this.props)); } diff --git a/modules/main/src/index.js b/modules/main/src/index.js index 7da127382..32c4b0899 100644 --- a/modules/main/src/index.js +++ b/modules/main/src/index.js @@ -53,5 +53,6 @@ export { ImmutableFeatureCollection } from '@nebula.gl/edit-modes'; // Other modes export { ViewMode } from '@nebula.gl/edit-modes'; +export { MeasureDistanceMode } from '@nebula.gl/edit-modes'; export { CompositeMode } from '@nebula.gl/edit-modes'; export { SnappableMode } from '@nebula.gl/edit-modes'; diff --git a/yarn.lock b/yarn.lock index 902183afa..eac04efa6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3858,6 +3858,14 @@ d3-geo@1.7.1: dependencies: d3-array "1" +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + dargs@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" @@ -4307,6 +4315,24 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.52" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.52.tgz#bb21777e919a04263736ded120a9d665f10ea63f" + integrity sha512-bWCbE9fbpYQY4CU6hJbJ1vSz70EClMlDgJ7BmwI+zEJhxrwjesZRPglGJlsZhu0334U3hI+gaspwksH9IGD6ag== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.2" + next-tick "~1.0.0" + +es6-iterator@^2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-promise@^4.0.3: version "4.2.5" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" @@ -4319,6 +4345,24 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +es6-symbol@^3.1.1, es6-symbol@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -4534,6 +4578,14 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" @@ -4676,6 +4728,13 @@ express@^4.16.2: utils-merge "1.0.1" vary "~1.1.2" +ext@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.2.0.tgz#8dd8d2dd21bcced3045be09621fa0cbf73908ba4" + integrity sha512-0ccUQK/9e3NreLFg6K6np8aPyRgwycx+oFGtfx1dSp7Wj00Ozw9r05FgBRlzjf2XBM7LAzwgLyDscRrtSU91hA== + dependencies: + type "^2.0.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -5940,7 +5999,7 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-promise@^2.1.0: +is-promise@^2.1, is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -7075,6 +7134,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + dependencies: + es5-ext "~0.10.2" + magic-string@~0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.16.0.tgz#970ebb0da7193301285fb1aa650f39bdd81eb45a" @@ -7221,6 +7287,20 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" +memoizee@^0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" + integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== + dependencies: + d "1" + es5-ext "^0.10.45" + es6-weak-map "^2.0.2" + event-emitter "^0.3.5" + is-promise "^2.1" + lru-queue "0.1" + next-tick "1" + timers-ext "^0.1.5" + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -7552,6 +7632,11 @@ neo-async@^2.5.0, neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +next-tick@1, next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -10006,6 +10091,14 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +timers-ext@^0.1.5: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + tinyqueue@^1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-1.2.3.tgz#b6a61de23060584da29f82362e45df1ec7353f3d" @@ -10157,6 +10250,16 @@ type-is@~1.6.15, type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" + integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"