Skip to content

Commit 7160ed1

Browse files
committed
feat: add Flowtype
BREAKING CHANGE: Some internal and deprecated methods have been removed from the abstraction. By the looks of it, it doesn’t break anything. Making the breaking change just in case (as it is a risky change).
1 parent 097008a commit 7160ed1

11 files changed

+168
-74
lines changed

.babelrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"plugins": [
33
"lodash",
44
"transform-object-rest-spread",
5-
"transform-flow-comments",
5+
"transform-flow-strip-types",
66
"transform-runtime",
77
"add-module-exports"
88
],

.flowconfig

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[ignore]
2+
.*/node_modules/.*/test/.*
3+
.*/node_modules/babel-plugin-flow-runtime/.*
4+
.*/node_modules/config-chain/.*
5+
.*/node_modules/conventional-changelog-core/.*
6+
.*/node_modules/flow-runtime/.*
7+
.*/node_modules/npmconf/.*

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@
2222
"babel-cli": "^6.24.1",
2323
"babel-plugin-add-module-exports": "^0.2.1",
2424
"babel-plugin-lodash": "^3.2.11",
25-
"babel-plugin-transform-flow-comments": "^6.22.0",
25+
"babel-plugin-transform-flow-strip-types": "^6.22.0",
2626
"babel-plugin-transform-object-rest-spread": "^6.23.0",
2727
"babel-plugin-transform-runtime": "^6.23.0",
2828
"babel-preset-env": "1.4.0",
2929
"babel-register": "^6.24.1",
3030
"chai": "^3.5.0",
3131
"eslint": "^3.19.0",
3232
"eslint-config-canonical": "^8.2.0",
33+
"flow-bin": "^0.45.0",
34+
"flow-copy-source": "^1.1.0",
3335
"husky": "^0.13.3",
3436
"npm-watch": "^0.1.9",
3537
"semantic-release": "^6.3.2"
@@ -54,7 +56,7 @@
5456
"test": "{src,test}/*.js"
5557
},
5658
"scripts": {
57-
"build": "NODE_ENV=production babel ./src --out-dir ./dist --copy-files",
59+
"build": "NODE_ENV=production babel ./src --out-dir ./dist --copy-files && flow-copy-source src dist",
5860
"lint": "eslint ./src ./test",
5961
"watch": "npm-watch",
6062
"precommit": "npm run lint && npm run test",

src/FunctionStateMap.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
import PlayerStates from './constants/PlayerStates';
24

35
export default {

src/YouTubePlayer.js

+20-12
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
1+
// @flow
2+
13
import _ from 'lodash';
24
import functionNames from './functionNames';
35
import eventNames from './eventNames';
46
import FunctionStateMap from './FunctionStateMap';
7+
import type {
8+
EmitterType,
9+
YouTubePlayerType
10+
} from './types';
511

612
const YouTubePlayer = {};
713

14+
type EventHandlerMapType = {
15+
[key: string]: (event: Object) => void
16+
};
17+
818
/**
919
* Construct an object that defines an event handler for all of the YouTube
1020
* player events. Proxy captured events through an event emitter.
1121
*
1222
* @todo Capture event parameters.
1323
* @see https://developers.google.com/youtube/iframe_api_reference#Events
14-
* @param {Sister} emitter
15-
* @returns {Object}
1624
*/
17-
YouTubePlayer.proxyEvents = (emitter) => {
25+
YouTubePlayer.proxyEvents = (emitter: EmitterType): EventHandlerMapType => {
1826
const events = {};
1927

20-
_.forEach(eventNames, (eventName) => {
28+
for (const eventName of eventNames) {
2129
const onEventName = 'on' + _.upperFirst(eventName);
2230

2331
events[onEventName] = (event) => {
2432
emitter.trigger(eventName, event);
2533
};
26-
});
34+
}
2735

2836
return events;
2937
};
@@ -33,16 +41,16 @@ YouTubePlayer.proxyEvents = (emitter) => {
3341
*
3442
* @todo Proxy all of the methods using Object.keys.
3543
* @todo See TRICKY below.
36-
* @param {Promise} playerAPIReady Promise that resolves when player is ready.
37-
* @param {boolean} strictState A flag designating whether or not to wait for
38-
* an acceptable state when calling supported functions. Default: `false`.
44+
* @param playerAPIReady Promise that resolves when player is ready.
45+
* @param strictState A flag designating whether or not to wait for
46+
* an acceptable state when calling supported functions.
3947
* @returns {Object}
4048
*/
41-
YouTubePlayer.promisifyPlayer = (playerAPIReady, strictState = false) => {
49+
YouTubePlayer.promisifyPlayer = (playerAPIReady: Promise<YouTubePlayerType>, strictState: boolean = false) => {
4250
const functions = {};
4351

44-
_.forEach(functionNames, (functionName) => {
45-
if (strictState && FunctionStateMap[functionName] instanceof Object) {
52+
for (const functionName of functionNames) {
53+
if (strictState && FunctionStateMap[functionName]) {
4654
functions[functionName] = async (...args) => {
4755
const stateInfo = FunctionStateMap[functionName];
4856
const player = await playerAPIReady;
@@ -110,7 +118,7 @@ YouTubePlayer.promisifyPlayer = (playerAPIReady, strictState = false) => {
110118
return player[functionName].apply(player, args);
111119
};
112120
}
113-
});
121+
}
114122

115123
return functions;
116124
};

src/constants/PlayerStates.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
export default {
24
BUFFERING: 3,
35
ENDED: 0,

src/eventNames.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
/**
24
* @see https://developers.google.com/youtube/iframe_api_reference#Events
35
*/

src/functionNames.js

+2-25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
/**
24
* @see https://developers.google.com/youtube/iframe_api_reference#Functions
35
*/
@@ -9,11 +11,7 @@ export default [
911
'playVideo',
1012
'pauseVideo',
1113
'stopVideo',
12-
'clearVideo',
13-
'getVideoBytesLoaded',
14-
'getVideoBytesTotal',
1514
'getVideoLoadedFraction',
16-
'getVideoStartBytes',
1715
'cuePlaylist',
1816
'loadPlaylist',
1917
'nextVideo',
@@ -23,9 +21,6 @@ export default [
2321
'setLoop',
2422
'getPlaylist',
2523
'getPlaylistIndex',
26-
'getPlaylistId',
27-
'loadModule',
28-
'unloadModule',
2924
'setOption',
3025
'mute',
3126
'unMute',
@@ -44,29 +39,11 @@ export default [
4439
'getDuration',
4540
'removeEventListener',
4641
'getVideoUrl',
47-
'getDebugText',
48-
'getVideoData',
49-
'addCueRange',
50-
'removeCueRange',
51-
'getApiInterface',
52-
'showVideoInfo',
53-
'hideVideoInfo',
54-
'G',
55-
'C',
56-
'R',
57-
'aa',
58-
'$',
59-
'Z',
6042
'getVideoEmbedCode',
6143
'getOptions',
6244
'getOption',
63-
'Y',
64-
'X',
6545
'addEventListener',
6646
'destroy',
67-
'A',
68-
'P',
69-
'J',
7047
'setSize',
7148
'getIframe'
7249
];

src/index.js

+31-30
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
import _ from 'lodash';
1+
// @flow
2+
23
import Sister from 'sister';
34
import loadYouTubeIframeApi from './loadYouTubeIframeApi';
45
import YouTubePlayer from './YouTubePlayer';
6+
import type {
7+
YouTubePlayerType
8+
} from './types';
59

610
/**
7-
* @typedef options
811
* @see https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
9-
* @param {Number} width
10-
* @param {Number} height
11-
* @param {String} videoId
12-
* @param {Object} playerVars
13-
* @param {Object} events
1412
*/
13+
type OptionsType = {
14+
events?: Object,
15+
height?: number,
16+
playerVars?: Object,
17+
videoId?: string,
18+
width?: number
19+
};
1520

1621
/**
1722
* @typedef YT.Player
@@ -23,15 +28,14 @@ let youtubeIframeAPI;
2328
/**
2429
* A factory function used to produce an instance of YT.Player and queue function calls and proxy events of the resulting object.
2530
*
26-
* @param {YT.Player|HTMLElement|String} elementId Either An existing YT.Player instance,
31+
* @param elementId Either An existing YT.Player instance,
2732
* the DOM element or the id of the HTML element where the API will insert an <iframe>.
28-
* @param {YouTubePlayer~options} options See `options` (Ignored when using an existing YT.Player instance).
29-
* @param {boolean} strictState A flag designating whether or not to wait for
33+
* @param options See `options` (Ignored when using an existing YT.Player instance).
34+
* @param strictState A flag designating whether or not to wait for
3035
* an acceptable state when calling supported functions. Default: `false`.
3136
* See `FunctionStateMap.js` for supported functions and acceptable states.
32-
* @returns {Object}
3337
*/
34-
export default (elementId, options = {}, strictState = false) => {
38+
export default (maybeElementId: YouTubePlayerType | HTMLElement | string, options: OptionsType = {}, strictState: boolean = false) => {
3539
const emitter = Sister();
3640

3741
if (!youtubeIframeAPI) {
@@ -42,37 +46,34 @@ export default (elementId, options = {}, strictState = false) => {
4246
throw new Error('Event handlers cannot be overwritten.');
4347
}
4448

45-
if (_.isString(elementId) && !document.getElementById(elementId)) {
46-
throw new Error('Element "' + elementId + '" does not exist.');
49+
if (typeof maybeElementId === 'string' && !document.getElementById(maybeElementId)) {
50+
throw new Error('Element "' + maybeElementId + '" does not exist.');
4751
}
4852

4953
options.events = YouTubePlayer.proxyEvents(emitter);
5054

51-
const playerAPIReady = new Promise(async (resolve) => {
52-
let player;
53-
54-
if (
55-
elementId instanceof Object &&
56-
elementId.playVideo instanceof Function
57-
) {
58-
player = elementId;
59-
60-
resolve(player);
61-
} else {
55+
const playerAPIReady = new Promise(async (resolve: (result: YouTubePlayerType) => void) => {
56+
if (typeof maybeElementId === 'string' || maybeElementId instanceof HTMLElement) {
6257
const YT = await youtubeIframeAPI;
6358

64-
player = new YT.Player(elementId, options);
59+
const player: YouTubePlayerType = new YT.Player(maybeElementId, options);
6560

6661
emitter.on('ready', () => {
6762
resolve(player);
6863
});
64+
} else if (typeof maybeElementId === 'object' && maybeElementId.playVideo instanceof Function) {
65+
const player: YouTubePlayerType = maybeElementId;
66+
67+
resolve(player);
68+
} else {
69+
throw new TypeError('Unexpected state.');
6970
}
7071
});
7172

72-
const playerAPI = YouTubePlayer.promisifyPlayer(playerAPIReady, strictState);
73+
const playerApi = YouTubePlayer.promisifyPlayer(playerAPIReady, strictState);
7374

74-
playerAPI.on = emitter.on;
75-
playerAPI.off = emitter.off;
75+
playerApi.on = emitter.on;
76+
playerApi.off = emitter.off;
7677

77-
return playerAPI;
78+
return playerApi;
7879
};

src/loadYouTubeIframeApi.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
// @flow
2+
13
import load from 'load-script';
4+
import type {
5+
IframeApiType
6+
} from './types';
27

3-
export default () => {
8+
export default (): Promise<IframeApiType> => {
49
/**
510
* A promise that is resolved when window.onYouTubeIframeAPIReady is called.
611
* The promise is resolved with a reference to window.YT object.
7-
*
8-
* @param {Function} resolve
9-
* @member {Object} iframeAPIReady
1012
*/
1113
const iframeAPIReady = new Promise((resolve) => {
1214
if (window.YT && window.YT.Player && window.YT.Player instanceof Function) {
@@ -27,6 +29,7 @@ export default () => {
2729
resolve(window.YT);
2830
};
2931
});
32+
3033
const protocol = window.location.protocol === 'http:' ? 'http:' : 'https:';
3134

3235
load(protocol + '//www.youtube.com/iframe_api');

0 commit comments

Comments
 (0)