Skip to content

Commit

Permalink
Start adopting Flow strict mode (#8281)
Browse files Browse the repository at this point in the history
* start adopting Flow strict mode

* fix lint

* enable sketchy-null and strict-type throttle.js

* strict-type webp_supported, browser, task_queue, cancelable

* strictly type dom.js

* fix lint in dom.js
  • Loading branch information
mourner committed May 29, 2019
1 parent 8e9a34b commit 27ac83a
Show file tree
Hide file tree
Showing 17 changed files with 158 additions and 128 deletions.
7 changes: 7 additions & 0 deletions .flowconfig
Expand Up @@ -22,3 +22,10 @@

[options]
server.max_workers=4

[strict]
nonstrict-import
unclear-type
untyped-import
untyped-type-import
sketchy-null
5 changes: 5 additions & 0 deletions flow-typed/gl.js
@@ -0,0 +1,5 @@
// @flow strict
declare module "gl" {
declare function gl(width: number, height: number, attributes: WebGLContextAttributes): WebGLRenderingContext;
declare module.exports: typeof gl;
}
18 changes: 18 additions & 0 deletions flow-typed/jsdom.js
@@ -0,0 +1,18 @@
// @flow strict

import type Window from '../src/types/window';

declare module "jsdom" {
declare class JSDOM {
constructor(content: string, options: Object): JSDOM;
window: Window;
}
declare class VirtualConsole {
constructor(): VirtualConsole;
sendTo(console: typeof console): VirtualConsole;
}
declare module.exports: {
JSDOM: typeof JSDOM,
VirtualConsole: typeof VirtualConsole
};
}
10 changes: 10 additions & 0 deletions flow-typed/sinon.js
@@ -0,0 +1,10 @@
// @flow strict
declare module "sinon" {
declare class FakeServer {
xhr: XMLHttpRequest
}
declare module.exports: {
xhr: {supportsCORS: boolean},
fakeServer: {create: () => FakeServer}
};
}
11 changes: 0 additions & 11 deletions flow-typed/unitbezier.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/types/callback.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

// Flow can't perfectly type Node-style callbacks yet; it does not have a way to
// express that if the first parameter is null, the second is not, so for the time
Expand Down
2 changes: 1 addition & 1 deletion src/types/cancelable.js
@@ -1,3 +1,3 @@
// @flow
// @flow strict

export type Cancelable = { cancel: () => void };
162 changes: 81 additions & 81 deletions src/types/window.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

/* global EventTarget, IDBEnvironment */

Expand All @@ -22,83 +22,83 @@ export interface Window extends EventTarget, IDBEnvironment {
name: string;
+navigator: Navigator;
offscreenBuffering: string | boolean;
onabort: (ev: UIEvent) => any;
onafterprint: (ev: Event) => any;
onbeforeprint: (ev: Event) => any;
onbeforeunload: (ev: Event) => any;
onblur: (ev: FocusEvent) => any;
oncanplay: (ev: Event) => any;
oncanplaythrough: (ev: Event) => any;
onchange: (ev: Event) => any;
onclick: (ev: MouseEvent) => any;
oncompassneedscalibration: (ev: Event) => any;
oncontextmenu: (ev: Event) => any;
ondblclick: (ev: MouseEvent) => any;
ondevicelight: (ev: Event) => any;
ondevicemotion: (ev: Event) => any;
ondeviceorientation: (ev: Event) => any;
ondrag: (ev: DragEvent) => any;
ondragend: (ev: DragEvent) => any;
ondragenter: (ev: DragEvent) => any;
ondragleave: (ev: DragEvent) => any;
ondragover: (ev: DragEvent) => any;
ondragstart: (ev: DragEvent) => any;
ondrop: (ev: DragEvent) => any;
ondurationchange: (ev: Event) => any;
onemptied: (ev: Event) => any;
onended: (ev: Event) => any;
onerror: (ev: Event) => any;
onfocus: (ev: FocusEvent) => any;
onhashchange: (ev: Event) => any;
oninput: (ev: Event) => any;
oninvalid: (ev: Event) => any;
onkeydown: (ev: KeyboardEvent) => any;
onkeypress: (ev: KeyboardEvent) => any;
onkeyup: (ev: KeyboardEvent) => any;
onload: (ev: Event) => any;
onloadeddata: (ev: Event) => any;
onloadedmetadata: (ev: Event) => any;
onloadstart: (ev: Event) => any;
onmessage: (ev: MessageEvent) => any;
onmousedown: (ev: MouseEvent) => any;
onmouseenter: (ev: MouseEvent) => any;
onmouseleave: (ev: MouseEvent) => any;
onmousemove: (ev: MouseEvent) => any;
onmouseout: (ev: MouseEvent) => any;
onmouseover: (ev: MouseEvent) => any;
onmouseup: (ev: MouseEvent) => any;
onmousewheel: (ev: WheelEvent) => any;
onoffline: (ev: Event) => any;
ononline: (ev: Event) => any;
onorientationchange: (ev: Event) => any;
onpagehide: (ev: Event) => any;
onpageshow: (ev: Event) => any;
onpause: (ev: Event) => any;
onplay: (ev: Event) => any;
onplaying: (ev: Event) => any;
onpopstate: (ev: Event) => any;
onprogress: (ev: ProgressEvent) => any;
onratechange: (ev: Event) => any;
onreadystatechange: (ev: ProgressEvent) => any;
onreset: (ev: Event) => any;
onresize: (ev: UIEvent) => any;
onscroll: (ev: UIEvent) => any;
onseeked: (ev: Event) => any;
onseeking: (ev: Event) => any;
onselect: (ev: UIEvent) => any;
onstalled: (ev: Event) => any;
onstorage: (ev: Event) => any;
onsubmit: (ev: Event) => any;
onsuspend: (ev: Event) => any;
ontimeupdate: (ev: Event) => any;
ontouchcancel: (ev: TouchEvent) => any;
ontouchend: (ev: TouchEvent) => any;
ontouchmove: (ev: TouchEvent) => any;
ontouchstart: (ev: TouchEvent) => any;
onunload: (ev: Event) => any;
onvolumechange: (ev: Event) => any;
onwaiting: (ev: Event) => any;
opener: any;
onabort: (ev: UIEvent) => ?boolean;
onafterprint: (ev: Event) => ?boolean;
onbeforeprint: (ev: Event) => ?boolean;
onbeforeunload: (ev: Event) => ?boolean;
onblur: (ev: FocusEvent) => ?boolean;
oncanplay: (ev: Event) => ?boolean;
oncanplaythrough: (ev: Event) => ?boolean;
onchange: (ev: Event) => ?boolean;
onclick: (ev: MouseEvent) => ?boolean;
oncompassneedscalibration: (ev: Event) => ?boolean;
oncontextmenu: (ev: Event) => ?boolean;
ondblclick: (ev: MouseEvent) => ?boolean;
ondevicelight: (ev: Event) => ?boolean;
ondevicemotion: (ev: Event) => ?boolean;
ondeviceorientation: (ev: Event) => ?boolean;
ondrag: (ev: DragEvent) => ?boolean;
ondragend: (ev: DragEvent) => ?boolean;
ondragenter: (ev: DragEvent) => ?boolean;
ondragleave: (ev: DragEvent) => ?boolean;
ondragover: (ev: DragEvent) => ?boolean;
ondragstart: (ev: DragEvent) => ?boolean;
ondrop: (ev: DragEvent) => ?boolean;
ondurationchange: (ev: Event) => ?boolean;
onemptied: (ev: Event) => ?boolean;
onended: (ev: Event) => ?boolean;
onerror: (ev: Event) => ?boolean;
onfocus: (ev: FocusEvent) => ?boolean;
onhashchange: (ev: Event) => ?boolean;
oninput: (ev: Event) => ?boolean;
oninvalid: (ev: Event) => ?boolean;
onkeydown: (ev: KeyboardEvent) => ?boolean;
onkeypress: (ev: KeyboardEvent) => ?boolean;
onkeyup: (ev: KeyboardEvent) => ?boolean;
onload: (ev: Event) => ?boolean;
onloadeddata: (ev: Event) => ?boolean;
onloadedmetadata: (ev: Event) => ?boolean;
onloadstart: (ev: Event) => ?boolean;
onmessage: (ev: MessageEvent) => ?boolean;
onmousedown: (ev: MouseEvent) => ?boolean;
onmouseenter: (ev: MouseEvent) => ?boolean;
onmouseleave: (ev: MouseEvent) => ?boolean;
onmousemove: (ev: MouseEvent) => ?boolean;
onmouseout: (ev: MouseEvent) => ?boolean;
onmouseover: (ev: MouseEvent) => ?boolean;
onmouseup: (ev: MouseEvent) => ?boolean;
onmousewheel: (ev: WheelEvent) => ?boolean;
onoffline: (ev: Event) => ?boolean;
ononline: (ev: Event) => ?boolean;
onorientationchange: (ev: Event) => ?boolean;
onpagehide: (ev: Event) => ?boolean;
onpageshow: (ev: Event) => ?boolean;
onpause: (ev: Event) => ?boolean;
onplay: (ev: Event) => ?boolean;
onplaying: (ev: Event) => ?boolean;
onpopstate: (ev: Event) => ?boolean;
onprogress: (ev: ProgressEvent) => ?boolean;
onratechange: (ev: Event) => ?boolean;
onreadystatechange: (ev: ProgressEvent) => ?boolean;
onreset: (ev: Event) => ?boolean;
onresize: (ev: UIEvent) => ?boolean;
onscroll: (ev: UIEvent) => ?boolean;
onseeked: (ev: Event) => ?boolean;
onseeking: (ev: Event) => ?boolean;
onselect: (ev: UIEvent) => ?boolean;
onstalled: (ev: Event) => ?boolean;
onstorage: (ev: Event) => ?boolean;
onsubmit: (ev: Event) => ?boolean;
onsuspend: (ev: Event) => ?boolean;
ontimeupdate: (ev: Event) => ?boolean;
ontouchcancel: (ev: TouchEvent) => ?boolean;
ontouchend: (ev: TouchEvent) => ?boolean;
ontouchmove: (ev: TouchEvent) => ?boolean;
ontouchstart: (ev: TouchEvent) => ?boolean;
onunload: (ev: Event) => ?boolean;
onvolumechange: (ev: Event) => ?boolean;
onwaiting: (ev: Event) => ?boolean;
opener: Window;
orientation: string | number;
+outerHeight: number;
+outerWidth: number;
Expand Down Expand Up @@ -133,9 +133,9 @@ export interface Window extends EventTarget, IDBEnvironment {
Worker: typeof Worker;
XMLHttpRequest: typeof XMLHttpRequest;
Request: typeof Request;
AbortController: any;
AbortController: typeof AbortController;

alert(message?: any): void;
alert(message?: string): void;
blur(): void;
captureEvents(): void;
close(): void;
Expand All @@ -148,7 +148,7 @@ export interface Window extends EventTarget, IDBEnvironment {
moveTo(x?: number, y?: number): void;
msWriteProfilerMark(profilerMarkName: string): void;
open(url?: string, target?: string, features?: string, replace?: boolean): Window;
postMessage(message: any, targetOrigin: string, transfer?: any[]): void;
postMessage(message: mixed, targetOrigin: string, transfer?: ArrayBuffer[]): void;
print(): void;
prompt(message?: string, _default?: string): string | null;
releaseEvents(): void;
Expand Down
2 changes: 1 addition & 1 deletion src/ui/hash.js
Expand Up @@ -14,7 +14,7 @@ import type Map from './map';
*/
class Hash {
_map: Map;
_updateHash: () => TimeoutID;
_updateHash: () => ?TimeoutID;

constructor() {
bindAll([
Expand Down
4 changes: 2 additions & 2 deletions src/util/browser.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

import window from './window';
import type { Cancelable } from '../types/cancelable';
Expand Down Expand Up @@ -29,7 +29,7 @@ const exported = {
*/
now,

frame(fn: Function): Cancelable {
frame(fn: () => void): Cancelable {
const frame = raf(fn);
return { cancel: () => cancel(frame) };
},
Expand Down
2 changes: 1 addition & 1 deletion src/util/config.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

type Config = {|
API_URL: string,
Expand Down
2 changes: 1 addition & 1 deletion src/util/dictionary_coder.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

import assert from 'assert';

Expand Down
40 changes: 21 additions & 19 deletions src/util/dom.js
@@ -1,4 +1,4 @@
// @flow
// @flow strict

import Point from '@mapbox/point-geometry';

Expand All @@ -8,9 +8,9 @@ import assert from 'assert';
const DOM = {};
export default DOM;

DOM.create = function (tagName: *, className?: string, container?: HTMLElement) {
DOM.create = function (tagName: string, className: ?string, container?: HTMLElement) {
const el = window.document.createElement(tagName);
if (className) el.className = className;
if (className !== undefined) el.className = className;
if (container) container.appendChild(el);
return el;
};
Expand All @@ -20,12 +20,10 @@ DOM.createNS = function (namespaceURI: string, tagName: string) {
return el;
};

const docStyle = window.document ?
(window.document.documentElement: any).style :
null;
const docStyle = window.document.documentElement.style;

function testProp(props) {
if (!docStyle) return null;
if (!docStyle) return props[0];
for (let i = 0; i < props.length; i++) {
if (props[i] in docStyle) {
return props[i];
Expand Down Expand Up @@ -53,35 +51,39 @@ DOM.enableDrag = function () {
const transformProp = testProp(['transform', 'WebkitTransform']);

DOM.setTransform = function(el: HTMLElement, value: string) {
(el.style: any)[transformProp] = value;
// https://github.com/facebook/flow/issues/7754
// $FlowFixMe
el.style[transformProp] = value;
};

// Feature detection for {passive: false} support in add/removeEventListener.
let passiveSupported = false;

try {
const options = (Object.defineProperty: any)({}, "passive", {
const options = Object.defineProperty({}, "passive", {
get() {
passiveSupported = true;
}
return false;
},
value: false

This comment has been minimized.

Copy link
@pakastin

pakastin May 29, 2019

Contributor

This change breaks e.preventDefault() on iOS. You can't use both accessors and a value.

});
(window.addEventListener: any)("test", options, options);
(window.removeEventListener: any)("test", options, options);
window.addEventListener("test", options, options);
window.removeEventListener("test", options, options);
} catch (err) {
passiveSupported = false;
}

DOM.addEventListener = function(target: *, type: *, callback: *, options: {passive?: boolean, capture?: boolean} = {}) {
if ('passive' in options && passiveSupported) {
target.addEventListener(type, callback, (options: any));
target.addEventListener(type, callback, options);
} else {
target.addEventListener(type, callback, options.capture);
}
};

DOM.removeEventListener = function(target: *, type: *, callback: *, options: {passive?: boolean, capture?: boolean} = {}) {
if ('passive' in options && passiveSupported) {
target.removeEventListener(type, callback, (options: any));
target.removeEventListener(type, callback, options);
} else {
target.removeEventListener(type, callback, options.capture);
}
Expand All @@ -101,16 +103,16 @@ DOM.suppressClick = function() {
}, 0);
};

DOM.mousePos = function (el: HTMLElement, e: any) {
DOM.mousePos = function (el: HTMLElement, e: MouseEvent | window.TouchEvent | Touch) {
const rect = el.getBoundingClientRect();
e = e.touches ? e.touches[0] : e;
const t = window.TouchEvent && (e instanceof window.TouchEvent) ? e.touches[0] : e;
return new Point(
e.clientX - rect.left - el.clientLeft,
e.clientY - rect.top - el.clientTop
t.clientX - rect.left - el.clientLeft,
t.clientY - rect.top - el.clientTop
);
};

DOM.touchPos = function (el: HTMLElement, e: any) {
DOM.touchPos = function (el: HTMLElement, e: TouchEvent) {
const rect = el.getBoundingClientRect(),
points = [];
const touches = (e.type === 'touchend') ? e.changedTouches : e.touches;
Expand Down

0 comments on commit 27ac83a

Please sign in to comment.