diff --git a/.flowconfig b/.flowconfig index f9f5008ab28..6a02582fad3 100644 --- a/.flowconfig +++ b/.flowconfig @@ -12,4 +12,4 @@ .*/test/integration/render-tests/.* [version] -0.66.0 +0.69.0 diff --git a/flow-typed/vector-tile.js b/flow-typed/vector-tile.js index 1fc1a947621..160b08c8339 100644 --- a/flow-typed/vector-tile.js +++ b/flow-typed/vector-tile.js @@ -5,6 +5,7 @@ declare interface VectorTile { } declare interface VectorTileLayer { + version?: number; name: string; extent: number; length: number; diff --git a/package.json b/package.json index 893daa532f0..e9d9d3eefc4 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "eslint-plugin-node": "^5.1.1", "eslint-plugin-react": "^7.3.0", "execcommand-copy": "^1.1.0", - "flow-bin": "^0.66.0", + "flow-bin": "^0.69.0", "flow-coverage-report": "^0.3.0", "github-slugger": "^1.1.1", "gl": "^4.0.1", diff --git a/src/data/program_configuration.js b/src/data/program_configuration.js index e32187d5366..2f1e866e9aa 100644 --- a/src/data/program_configuration.js +++ b/src/data/program_configuration.js @@ -14,6 +14,7 @@ import type VertexBuffer from '../gl/vertex_buffer'; import type Program from '../render/program'; import type { Feature, + FeatureState, GlobalProperties, SourceExpression, CompositeExpression @@ -64,7 +65,7 @@ interface Binder { statistics: { max: number }; populatePaintArray(length: number, feature: Feature): void; - updatePaintArray(start: number, length: number, feature: Feature): void; + updatePaintArray(start: number, length: number, feature: Feature, featureState: FeatureState): void; upload(Context): void; destroy(): void; @@ -163,9 +164,9 @@ class SourceExpressionBinder implements Binder { } } - updatePaintArray(start: number, end: number, feature: Feature) { + updatePaintArray(start: number, end: number, feature: Feature, featureState: FeatureState) { const paintArray = this.paintVertexArray; - const value = this.expression.evaluate({zoom: 0}, feature); + const value = this.expression.evaluate({zoom: 0}, feature, featureState); if (this.type === 'color') { const color = packColor(value); @@ -255,11 +256,11 @@ class CompositeExpressionBinder implements Binder { } } - updatePaintArray(start: number, end: number, feature: Feature) { + updatePaintArray(start: number, end: number, feature: Feature, featureState: FeatureState) { const paintArray = this.paintVertexArray; - const min = this.expression.evaluate({zoom: this.zoom }, feature); - const max = this.expression.evaluate({zoom: this.zoom + 1}, feature); + const min = this.expression.evaluate({zoom: this.zoom }, feature, featureState); + const max = this.expression.evaluate({zoom: this.zoom + 1}, feature, featureState); if (this.type === 'color') { const minColor = packColor(min); @@ -394,18 +395,18 @@ export default class ProgramConfiguration { const posArray = this._idMap[id]; if (!posArray) continue; + const featureState = featureStates[id]; for (const pos of posArray) { - const feature: any = vtLayer.feature(pos.index); - feature.state = featureStates[id]; + const feature = vtLayer.feature(pos.index); for (const property in this.binders) { - const binder: Binder = this.binders[property]; + const binder = this.binders[property]; if (binder instanceof ConstantBinder) continue; if ((binder: any).expression.isStateDependent === true) { //AHM: Remove after https://github.com/mapbox/mapbox-gl-js/issues/6255 const value = layer.paint.get(property); (binder: any).expression = value.value; - binder.updatePaintArray(pos.start, pos.end, feature); + binder.updatePaintArray(pos.start, pos.end, feature, featureState); dirty = true; } } diff --git a/src/source/geojson_worker_source.js b/src/source/geojson_worker_source.js index 5013946443d..2d0fdfe6a39 100644 --- a/src/source/geojson_worker_source.js +++ b/src/source/geojson_worker_source.js @@ -29,6 +29,7 @@ export type LoadGeoJSONParameters = { request?: RequestParameters, data?: string, source: string, + cluster: boolean, superclusterOptions?: Object, geojsonVtOptions?: Object }; diff --git a/src/source/source.js b/src/source/source.js index 5b372a11b40..154fb3b803f 100644 --- a/src/source/source.js +++ b/src/source/source.js @@ -8,6 +8,7 @@ import type Map from '../ui/map'; import type Tile from './tile'; import type {OverscaledTileID} from './tile_id'; import type {Callback} from '../types/callback'; +import {CanonicalTileID} from './tile_id'; /** * The `Source` interface must be implemented by each source type, including "core" types (`vector`, `raster`, @@ -34,15 +35,6 @@ import type {Callback} from '../types/callback'; * if they are floor-ed to the nearest integer. */ export interface Source { - /** - * An optional URL to a script which, when run by a Worker, registers a {@link WorkerSource} - * implementation for this Source type by calling `self.registerWorkerSource(workerSource: WorkerSource)`. - * @private - */ - // Static interface properties are not supported in flow as of 0.62.0. - // https://github.com/facebook/flow/issues/5590 - // static workerSourceURL?: URL; - +type: string; id: string; minzoom: number, @@ -51,6 +43,9 @@ export interface Source { attribution?: string, roundZoom?: boolean, + isTileClipped?: boolean, + mapbox_logo?: boolean, + tileID?: CanonicalTileID; reparseOverscaled?: boolean, vectorLayerIds?: Array, @@ -77,6 +72,17 @@ export interface Source { +prepare?: () => void; } +type SourceStatics = { + /** + * An optional URL to a script which, when run by a Worker, registers a {@link WorkerSource} + * implementation for this Source type by calling `self.registerWorkerSource(workerSource: WorkerSource)`. + * @private + */ + workerSourceURL?: URL; +}; + +export type SourceClass = Class & SourceStatics; + import vector from '../source/vector_tile_source'; import raster from '../source/raster_tile_source'; import rasterDem from '../source/raster_dem_tile_source'; diff --git a/src/source/source_cache.js b/src/source/source_cache.js index 75e3eaa65b4..4069fd537c3 100644 --- a/src/source/source_cache.js +++ b/src/source/source_cache.js @@ -241,7 +241,7 @@ class SourceCache extends Evented { _tileLoaded(tile: Tile, id: string | number, previousState: TileState, err: ?Error) { if (err) { tile.state = 'errored'; - if (err.status !== 404) this._source.fire(new ErrorEvent(err, {tile})); + if ((err: any).status !== 404) this._source.fire(new ErrorEvent(err, {tile})); // continue to try loading parent/children tiles if a tile doesn't exist (404) else this.update(this.transform); return; @@ -461,7 +461,7 @@ class SourceCache extends Evented { if (!this.used) { idealTileIDs = []; } else if (this._source.tileID) { - idealTileIDs = transform.getVisibleUnwrappedCoordinates((this._source.tileID: any)) + idealTileIDs = transform.getVisibleUnwrappedCoordinates(this._source.tileID) .map((unwrapped) => new OverscaledTileID(unwrapped.canonical.z, unwrapped.wrap, unwrapped.canonical.z, unwrapped.canonical.x, unwrapped.canonical.y)); } else { idealTileIDs = transform.coveringTiles({ diff --git a/src/source/source_state.js b/src/source/source_state.js index 6e48a6f7ad8..9fe8c39bb61 100644 --- a/src/source/source_state.js +++ b/src/source/source_state.js @@ -1,11 +1,13 @@ // @flow + import { extend } from '../util/util'; import Tile from './tile'; +import type {FeatureState} from '../style-spec/expression'; -export type FeatureStates = {[feature_id: string]: {[key: string]: any }}; +export type FeatureStates = {[feature_id: string]: FeatureState}; export type LayerFeatureStates = {[layer: string]: FeatureStates}; -/** +/** * SourceFeatureState manages the state and state changes * to features in a source, separated by source layer. * diff --git a/src/style-spec/expression/definitions/index.js b/src/style-spec/expression/definitions/index.js index e7313794ca4..d357072c475 100644 --- a/src/style-spec/expression/definitions/index.js +++ b/src/style-spec/expression/definitions/index.js @@ -172,7 +172,7 @@ CompoundExpression.register(expressions, { 'feature-state': [ ValueType, [StringType], - (ctx, [key]) => get(key.evaluate(ctx), ctx.state()) + (ctx, [key]) => get(key.evaluate(ctx), ctx.featureState || {}) ], 'properties': [ ObjectType, diff --git a/src/style-spec/expression/evaluation_context.js b/src/style-spec/expression/evaluation_context.js index ca96eae64cd..f6a88333048 100644 --- a/src/style-spec/expression/evaluation_context.js +++ b/src/style-spec/expression/evaluation_context.js @@ -2,13 +2,14 @@ import { Color } from './values'; -import type { Feature, GlobalProperties } from './index'; +import type { GlobalProperties, Feature, FeatureState } from './index'; const geometryTypes = ['Unknown', 'Point', 'LineString', 'Polygon']; class EvaluationContext { globals: GlobalProperties; feature: ?Feature; + featureState: ?FeatureState; _parseColorCache: {[string]: ?Color}; @@ -28,10 +29,6 @@ class EvaluationContext { return this.feature && this.feature.properties || {}; } - state() { - return this.feature && this.feature.state || {}; - } - parseColor(input: string): ?Color { let cached = this._parseColorCache[input]; if (!cached) { diff --git a/src/style-spec/expression/index.js b/src/style-spec/expression/index.js index c9d1abf3b79..745cfed8437 100644 --- a/src/style-spec/expression/index.js +++ b/src/style-spec/expression/index.js @@ -29,6 +29,8 @@ export type Feature = { +properties: {[string]: any} }; +export type FeatureState = {[string]: any}; + export type GlobalProperties = $ReadOnly<{ zoom: number, heatmapDensity?: number, @@ -53,24 +55,26 @@ export class StyleExpression { } } - evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature): any { + evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { if (!this._evaluator) { this._evaluator = new EvaluationContext(); } this._evaluator.globals = globals; this._evaluator.feature = feature; + this._evaluator.featureState = featureState; return this.expression.evaluate(this._evaluator); } - evaluate(globals: GlobalProperties, feature?: Feature): any { + evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { if (!this._evaluator) { this._evaluator = new EvaluationContext(); } this._evaluator.globals = globals; this._evaluator.feature = feature; + this._evaluator.featureState = featureState; try { const val = this.expression.evaluate(this._evaluator); @@ -129,12 +133,12 @@ export class ZoomConstantExpression { this.isStateDependent = kind !== 'constant' && !isConstant.isStateConstant(expression.expression); } - evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature): any { - return this._styleExpression.evaluateWithoutErrorHandling(globals, feature); + evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { + return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState); } - evaluate(globals: GlobalProperties, feature?: Feature): any { - return this._styleExpression.evaluate(globals, feature); + evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { + return this._styleExpression.evaluate(globals, feature, featureState); } } @@ -156,12 +160,12 @@ export class ZoomDependentExpression { } } - evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature): any { - return this._styleExpression.evaluateWithoutErrorHandling(globals, feature); + evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { + return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState); } - evaluate(globals: GlobalProperties, feature?: Feature): any { - return this._styleExpression.evaluate(globals, feature); + evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState): any { + return this._styleExpression.evaluate(globals, feature, featureState); } interpolationFactor(input: number, lower: number, upper: number): number { @@ -181,12 +185,12 @@ export type ConstantExpression = { export type SourceExpression = { kind: 'source', isStateDependent: boolean, - +evaluate: (globals: GlobalProperties, feature?: Feature) => any, + +evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState) => any, }; export type CameraExpression = { kind: 'camera', - +evaluate: (globals: GlobalProperties, feature?: Feature) => any, + +evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState) => any, +interpolationFactor: (input: number, lower: number, upper: number) => number, zoomStops: Array }; @@ -194,7 +198,7 @@ export type CameraExpression = { export type CompositeExpression = { kind: 'composite', isStateDependent: boolean, - +evaluate: (globals: GlobalProperties, feature?: Feature) => any, + +evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState) => any, +interpolationFactor: (input: number, lower: number, upper: number) => number, zoomStops: Array }; diff --git a/src/style-spec/feature_filter/index.js b/src/style-spec/feature_filter/index.js index 54cad4aaf3a..82e84896c98 100644 --- a/src/style-spec/feature_filter/index.js +++ b/src/style-spec/feature_filter/index.js @@ -47,9 +47,10 @@ function isExpressionFilter(filter: any) { const filterSpec = { 'type': 'boolean', 'default': false, - 'function': true, + 'function': 'piecewise-constant', 'property-function': true, - 'zoom-function': true + 'zoom-function': true, + 'transition': false }; /** diff --git a/src/style-spec/style-spec.js b/src/style-spec/style-spec.js index 51c6ac7b92c..1d48171fc9c 100644 --- a/src/style-spec/style-spec.js +++ b/src/style-spec/style-spec.js @@ -2,50 +2,57 @@ export type StylePropertySpecification = { type: 'number', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, + transition: boolean, default?: number } | { type: 'string', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, default?: string, + transition: boolean, tokens?: boolean } | { type: 'boolean', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, + transition: boolean, default?: boolean } | { type: 'enum', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, values: {[string]: {}}, + transition: boolean, default?: string } | { type: 'color', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, + transition: boolean, default?: string } | { type: 'array', value: 'number', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, + transition: boolean, length?: number, default?: Array } | { type: 'array', value: 'string', - 'function': boolean, + 'function': 'interpolated' | 'piecewise-constant', 'property-function': boolean, 'zoom-function': boolean, + transition: boolean, length?: number, default?: Array }; diff --git a/src/style/style.js b/src/style/style.js index 86ac69d92e1..29c033c5c99 100644 --- a/src/style/style.js +++ b/src/style/style.js @@ -18,7 +18,8 @@ import Dispatcher from '../util/dispatcher'; import { validateStyle, emitValidationErrors as _emitValidationErrors } from './validate_style'; import { getType as getSourceType, - setType as setSourceType + setType as setSourceType, + type SourceClass } from '../source/source'; import { queryRenderedFeatures, queryRenderedSymbols, querySourceFeatures } from '../source/query_features'; import SourceCache from '../source/source_cache'; @@ -43,7 +44,6 @@ const emitValidationErrors = (evented: Evented, errors: ?$ReadOnlyArray<{message import type Map from '../ui/map'; import type Transform from '../geo/transform'; -import type {Source} from '../source/source'; import type {StyleImage} from './style_image'; import type {StyleGlyph} from './style_glyph'; import type {Callback} from '../types/callback'; @@ -914,7 +914,7 @@ class Style extends Evented { return sourceCache ? querySourceFeatures(sourceCache, params) : []; } - addSourceType(name: string, SourceType: Class, callback: Callback) { + addSourceType(name: string, SourceType: SourceClass, callback: Callback) { if (Style.getSourceType(name)) { return callback(new Error(`A source type called "${name}" already exists.`)); } diff --git a/src/ui/bind_handlers.js b/src/ui/bind_handlers.js index ceb2fd712d3..b8f9767bedc 100644 --- a/src/ui/bind_handlers.js +++ b/src/ui/bind_handlers.js @@ -21,7 +21,7 @@ const handlers = { touchZoomRotate }; -export default function bindHandlers(map: Map, options: {}) { +export default function bindHandlers(map: Map, options: {interactive: boolean}) { const el = map.getCanvasContainer(); let contextMenuEvent = null; let mouseDown = false; @@ -97,7 +97,7 @@ export default function bindHandlers(map: Map, options: {}) { if (map.dragPan.isActive()) return; if (map.dragRotate.isActive()) return; - let target: any = e.toElement || e.target; + let target: ?Node = (e.target: any); while (target && target !== el) target = target.parentNode; if (target !== el) return; @@ -105,7 +105,7 @@ export default function bindHandlers(map: Map, options: {}) { } function onMouseOver(e: MouseEvent) { - let target: any = e.toElement || e.target; + let target: ?Node = (e.target: any); while (target && target !== el) target = target.parentNode; if (target !== el) return; diff --git a/src/ui/control/fullscreen_control.js b/src/ui/control/fullscreen_control.js index 35198c1c57d..539a26b549b 100644 --- a/src/ui/control/fullscreen_control.js +++ b/src/ui/control/fullscreen_control.js @@ -110,11 +110,11 @@ class FullscreenControl { } } else if (this._mapContainer.requestFullscreen) { this._mapContainer.requestFullscreen(); - } else if (this._mapContainer.mozRequestFullScreen) { + } else if ((this._mapContainer: any).mozRequestFullScreen) { (this._mapContainer: any).mozRequestFullScreen(); - } else if (this._mapContainer.msRequestFullscreen) { + } else if ((this._mapContainer: any).msRequestFullscreen) { (this._mapContainer: any).msRequestFullscreen(); - } else if (this._mapContainer.webkitRequestFullscreen) { + } else if ((this._mapContainer: any).webkitRequestFullscreen) { (this._mapContainer: any).webkitRequestFullscreen(); } } diff --git a/src/util/evented.js b/src/util/evented.js index 87b01f02ef9..c4d31ceb098 100644 --- a/src/util/evented.js +++ b/src/util/evented.js @@ -1,6 +1,6 @@ // @flow -import { extend, endsWith } from './util'; +import { extend } from './util'; type Listener = (Object) => any; type Listeners = { [string]: Array }; @@ -29,6 +29,8 @@ export class Event { } export class ErrorEvent extends Event { + error: Error; + constructor(error: Error, data: Object = {}) { super('error', extend({error}, data)); } @@ -120,10 +122,8 @@ export class Evented { // To ensure that no error events are dropped, print them to the // console if they have no listeners. - } else if (endsWith(type, 'error')) { - console.error((event && event.error) || event || 'Empty error event'); - } else if (endsWith(type, 'warning')) { - console.warn((event && event.warning) || event || 'Empty warning event'); + } else if (event instanceof ErrorEvent) { + console.error(event.error); } return this; diff --git a/src/util/worker_pool.js b/src/util/worker_pool.js index 24ae4d178d7..63dc69b1327 100644 --- a/src/util/worker_pool.js +++ b/src/util/worker_pool.js @@ -19,7 +19,7 @@ class WorkerPool { this.active = {}; } - acquire(mapId: number) { + acquire(mapId: number): Array { if (!this.workers) { // Lazily look up the value of mapboxgl.workerCount so that // client code has had a chance to set it. diff --git a/test/integration/render-tests/feature-state/composite-expression/expected.png b/test/integration/render-tests/feature-state/composite-expression/expected.png new file mode 100644 index 00000000000..44cb3becbdc Binary files /dev/null and b/test/integration/render-tests/feature-state/composite-expression/expected.png differ diff --git a/test/integration/render-tests/feature-state/composite-expression/style.json b/test/integration/render-tests/feature-state/composite-expression/style.json new file mode 100644 index 00000000000..0c9c7f8d4d8 --- /dev/null +++ b/test/integration/render-tests/feature-state/composite-expression/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64, + "operations": [ + [ + "setFeatureState", + { + "source": "geojson", + "id": "1" + }, + { + "color": "red" + } + ], + [ + "wait" + ] + ] + } + }, + "zoom": 2, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Feature", + "id": "1", + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson", + "paint": { + "circle-radius": 5, + "circle-color": [ + "step", + [ + "zoom" + ], + "black", + 1, + [ + "coalesce", + [ + "feature-state", + "color" + ], + "black" + ] + ] + } + } + ] +} diff --git a/test/integration/render-tests/feature-state/data-expression/expected.png b/test/integration/render-tests/feature-state/data-expression/expected.png new file mode 100644 index 00000000000..44cb3becbdc Binary files /dev/null and b/test/integration/render-tests/feature-state/data-expression/expected.png differ diff --git a/test/integration/render-tests/feature-state/data-expression/style.json b/test/integration/render-tests/feature-state/data-expression/style.json new file mode 100644 index 00000000000..6c045c000ec --- /dev/null +++ b/test/integration/render-tests/feature-state/data-expression/style.json @@ -0,0 +1,59 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64, + "operations": [ + [ + "setFeatureState", + { + "source": "geojson", + "id": "1" + }, + { + "color": "red" + } + ], + [ + "wait" + ] + ] + } + }, + "zoom": 2, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Feature", + "id": "1", + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson", + "paint": { + "circle-radius": 5, + "circle-color": [ + "coalesce", + [ + "feature-state", + "color" + ], + "black" + ] + } + } + ] +} diff --git a/test/integration/render-tests/feature-state/default/expected.png b/test/integration/render-tests/feature-state/vector-source/expected.png similarity index 100% rename from test/integration/render-tests/feature-state/default/expected.png rename to test/integration/render-tests/feature-state/vector-source/expected.png diff --git a/test/integration/render-tests/feature-state/default/style.json b/test/integration/render-tests/feature-state/vector-source/style.json similarity index 61% rename from test/integration/render-tests/feature-state/default/style.json rename to test/integration/render-tests/feature-state/vector-source/style.json index ca265f65b3d..59efa088541 100644 --- a/test/integration/render-tests/feature-state/default/style.json +++ b/test/integration/render-tests/feature-state/vector-source/style.json @@ -5,17 +5,18 @@ "height": 256, "operations": [ [ - "setFeatureState", - { - "source": "mapbox", - "sourceLayer": "poi_label", - "id": "1000059876748" - }, - { - "isRed": true - } - ], [ - "wait" + "setFeatureState", + { + "source": "mapbox", + "sourceLayer": "poi_label", + "id": "1000059876748" + }, + { + "color": "red" + } + ], + [ + "wait" ] ] } @@ -49,13 +50,15 @@ "source-layer": "poi_label", "paint": { "circle-radius": 5, - "circle-color": ["case", - ["boolean", ["feature-state", "isRed"], false], - ["rgb", 255, 0, 0], - ["rgb", 0, 0, 0] + "circle-color": [ + "coalesce", + [ + "feature-state", + "color" + ], + "black" ] - } } ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 5882d86e004..7b63206fac5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4171,9 +4171,9 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -flow-bin@^0.66.0: - version "0.66.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.66.0.tgz#a96dde7015dc3343fd552a7b4963c02be705ca26" +flow-bin@^0.69.0: + version "0.69.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.69.0.tgz#053159a684a6051fcbf0b71a2eb19a9679082da6" flow-coverage-report@^0.3.0: version "0.3.0"