From 80cb54ee6d79e36b783de54b626ffd50fad6a971 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 5 Jan 2018 17:20:02 +0000 Subject: [PATCH] [internals][types] Last part of internal refactor; Got rid of remaining flow errors --- .flowconfig | 3 +- lib/modules/admob/index.js | 11 +++-- lib/modules/analytics/index.js | 25 +++++----- lib/modules/auth/ConfirmationResult.js | 3 +- lib/modules/auth/PhoneAuthListener.js | 14 ++++-- lib/modules/auth/User.js | 25 +++++----- lib/modules/auth/index.js | 37 +++++++------- lib/modules/config/index.js | 29 +++++------ lib/modules/core/firebase-app.js | 5 +- lib/modules/core/firebase.js | 8 +-- lib/modules/crash/index.js | 17 ++++--- lib/modules/database/index.js | 22 ++++----- lib/modules/database/reference.js | 52 +++++++++++--------- lib/modules/database/transaction.js | 29 +++++------ lib/modules/fabric/crashlytics/index.js | 23 ++++----- lib/modules/firestore/CollectionReference.js | 9 ++-- lib/modules/firestore/DocumentReference.js | 40 ++++++++++----- lib/modules/firestore/Query.js | 48 ++++++++++++------ lib/modules/firestore/WriteBatch.js | 4 +- lib/modules/firestore/index.js | 6 +-- lib/modules/links/index.js | 15 +++--- lib/modules/messaging/index.js | 39 ++++++++------- lib/modules/perf/Trace.js | 11 +++-- lib/modules/perf/index.js | 9 ++-- lib/modules/storage/index.js | 19 +++---- lib/modules/storage/reference.js | 15 +++--- lib/modules/utils/index.js | 16 +++--- lib/utils/ModuleBase.js | 27 +++++----- lib/utils/ReferenceBase.js | 7 +-- lib/utils/SyncTree.js | 33 +++++++------ lib/utils/apps.js | 44 +++++++++-------- lib/utils/events.js | 2 +- lib/utils/index.js | 8 +-- lib/utils/internals.js | 8 ++- lib/utils/log.js | 1 + 35 files changed, 358 insertions(+), 306 deletions(-) diff --git a/.flowconfig b/.flowconfig index 96622d4e..2130616f 100644 --- a/.flowconfig +++ b/.flowconfig @@ -50,7 +50,7 @@ module.system=haste emoji=true -munge_underscores=false +munge_underscores=true module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' @@ -69,6 +69,7 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1 suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError +suppress_comment=\\(.\\|\n\\)*\\$FlowBug.* unsafe.enable_getters_and_setters=true diff --git a/lib/modules/admob/index.js b/lib/modules/admob/index.js index 8a81f873..84879f18 100644 --- a/lib/modules/admob/index.js +++ b/lib/modules/admob/index.js @@ -4,6 +4,7 @@ */ import { SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; +import { getNativeModule } from '../../utils/native'; import ModuleBase from '../../utils/ModuleBase'; import Interstitial from './Interstitial'; @@ -18,7 +19,7 @@ import EventTypes, { RewardedVideoEventTypes, } from './EventTypes'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; type NativeEvent = { adUnit: string, @@ -38,8 +39,8 @@ export default class AdMob extends ModuleBase { _appId: ?string; _initialized: boolean; - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, @@ -80,7 +81,7 @@ export default class AdMob extends ModuleBase { } else { this._initialized = true; this._appId = appId; - this._native.initialize(appId); + getNativeModule(this).initialize(appId); } } @@ -89,7 +90,7 @@ export default class AdMob extends ModuleBase { getLogger(this).warn('AdMob needs to be initialized before opening the dev menu!'); } else { getLogger(this).info('Opening debug menu'); - this._native.openDebugMenu(this._appId); + getNativeModule(this).openDebugMenu(this._appId); } } diff --git a/lib/modules/analytics/index.js b/lib/modules/analytics/index.js index dbff883c..44d8464f 100644 --- a/lib/modules/analytics/index.js +++ b/lib/modules/analytics/index.js @@ -2,9 +2,10 @@ * @flow * Analytics representation wrapper */ -import ModuleBase from './../../utils/ModuleBase'; +import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; const AlphaNumericUnderscore = /^[a-zA-Z0-9_]+$/; @@ -28,8 +29,8 @@ export const MODULE_NAME = 'RNFirebaseAnalytics'; export const NAMESPACE = 'analytics'; export default class Analytics extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { moduleName: MODULE_NAME, namespace: NAMESPACE, }); @@ -60,7 +61,7 @@ export default class Analytics extends ModuleBase { // types are supported. String parameter values can be up to 36 characters long. The "firebase_" // prefix is reserved and should not be used for parameter names. - this._native.logEvent(name, params); + getNativeModule(this).logEvent(name, params); } /** @@ -68,7 +69,7 @@ export default class Analytics extends ModuleBase { * @param enabled */ setAnalyticsCollectionEnabled(enabled: boolean): void { - this._native.setAnalyticsCollectionEnabled(enabled); + getNativeModule(this).setAnalyticsCollectionEnabled(enabled); } /** @@ -77,7 +78,7 @@ export default class Analytics extends ModuleBase { * @param screenClassOverride */ setCurrentScreen(screenName: string, screenClassOverride: string): void { - this._native.setCurrentScreen(screenName, screenClassOverride); + getNativeModule(this).setCurrentScreen(screenName, screenClassOverride); } /** @@ -85,7 +86,7 @@ export default class Analytics extends ModuleBase { * @param milliseconds */ setMinimumSessionDuration(milliseconds: number = 10000): void { - this._native.setMinimumSessionDuration(milliseconds); + getNativeModule(this).setMinimumSessionDuration(milliseconds); } /** @@ -93,7 +94,7 @@ export default class Analytics extends ModuleBase { * @param milliseconds */ setSessionTimeoutDuration(milliseconds: number = 1800000): void { - this._native.setSessionTimeoutDuration(milliseconds); + getNativeModule(this).setSessionTimeoutDuration(milliseconds); } /** @@ -101,7 +102,7 @@ export default class Analytics extends ModuleBase { * @param id */ setUserId(id: string): void { - this._native.setUserId(id); + getNativeModule(this).setUserId(id); } /** @@ -110,7 +111,7 @@ export default class Analytics extends ModuleBase { * @param value */ setUserProperty(name: string, value: string): void { - this._native.setUserProperty(name, value); + getNativeModule(this).setUserProperty(name, value); } /** @@ -120,7 +121,7 @@ export default class Analytics extends ModuleBase { */ setUserProperties(object: Object): void { for (const property of Object.keys(object)) { - this._native.setUserProperty(property, object[property]); + getNativeModule(this).setUserProperty(property, object[property]); } } } diff --git a/lib/modules/auth/ConfirmationResult.js b/lib/modules/auth/ConfirmationResult.js index a2b80b72..340be9cb 100644 --- a/lib/modules/auth/ConfirmationResult.js +++ b/lib/modules/auth/ConfirmationResult.js @@ -2,6 +2,7 @@ * @flow * ConfirmationResult representation wrapper */ +import { getNativeModule } from '../../utils/native'; import type Auth from './'; import type User from './User'; @@ -25,7 +26,7 @@ export default class ConfirmationResult { * @return {*} */ confirm(verificationCode: string): Promise { - return this._auth._interceptUserValue(this._auth._native._confirmVerificationCode(verificationCode)); + return this._auth._interceptUserValue(getNativeModule(this._auth)._confirmVerificationCode(verificationCode)); } get verificationId(): string | null { diff --git a/lib/modules/auth/PhoneAuthListener.js b/lib/modules/auth/PhoneAuthListener.js index 9503d8cf..648b249e 100644 --- a/lib/modules/auth/PhoneAuthListener.js +++ b/lib/modules/auth/PhoneAuthListener.js @@ -1,7 +1,8 @@ // @flow import INTERNALS from '../../utils/internals'; import { SharedEventEmitter } from '../../utils/events'; -import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from './../../utils'; +import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from '../../utils'; +import { getNativeModule } from '../../utils/native'; import type Auth from './'; @@ -20,7 +21,7 @@ type PhoneAuthError = { }; export default class PhoneAuthListener { - _auth: Object; + _auth: Auth; _timeout: number; _publicEvents: Object; _internalEvents: Object; @@ -69,7 +70,7 @@ export default class PhoneAuthListener { // start verification flow natively if (isAndroid) { - this._auth._native.verifyPhoneNumber( + getNativeModule(this._auth).verifyPhoneNumber( phoneNumber, this._phoneAuthRequestKey, this._timeout, @@ -77,7 +78,7 @@ export default class PhoneAuthListener { } if (isIOS) { - this._auth._native.verifyPhoneNumber( + getNativeModule(this._auth).verifyPhoneNumber( phoneNumber, this._phoneAuthRequestKey, ); @@ -93,6 +94,7 @@ export default class PhoneAuthListener { for (let i = 0, len = events.length; i < len; i++) { const type = events[i]; + // $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 SharedEventEmitter.once(this._internalEvents[type], this[`_${type}Handler`].bind(this)); } } @@ -121,7 +123,7 @@ export default class PhoneAuthListener { * @private */ _emitToErrorCb(snapshot) { - const error = snapshot.error; + const { error } = snapshot; if (this._reject) this._reject(error); SharedEventEmitter.emit(this._publicEvents.error, error); } @@ -296,6 +298,7 @@ export default class PhoneAuthListener { */ then(fn: () => PhoneAuthSnapshot) { this._promiseDeferred(); + // $FlowFixMe: Unsure how to annotate `bind` here if (this._promise) return this._promise.then.bind(this._promise)(fn); return undefined; // will never get here - just to keep flow happy } @@ -306,6 +309,7 @@ export default class PhoneAuthListener { */ catch(fn: () => Error) { this._promiseDeferred(); + // $FlowFixMe: Unsure how to annotate `bind` here if (this._promise) return this._promise.catch.bind(this._promise)(fn); return undefined; // will never get here - just to keep flow happy } diff --git a/lib/modules/auth/User.js b/lib/modules/auth/User.js index aa6d5903..b357915e 100644 --- a/lib/modules/auth/User.js +++ b/lib/modules/auth/User.js @@ -1,8 +1,9 @@ -/** +getNativeModule(this._auth)/** * @flow * User representation wrapper */ import INTERNALS from '../../utils/internals'; +import { getNativeModule } from '../../utils/native'; import type Auth from './'; import type { ActionCodeSettings, AuthCredential } from '../../types'; @@ -92,7 +93,7 @@ export default class User { */ delete(): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.delete()); + ._interceptUndefinedUserValue(getNativeModule(this._auth).delete()); } /** @@ -100,7 +101,7 @@ export default class User { * @return {Promise} */ getIdToken(forceRefresh: boolean = false): Promise { - return this._auth._native.getToken(forceRefresh); + return getNativeModule(this._auth).getToken(forceRefresh); } /** @@ -109,7 +110,7 @@ export default class User { */ linkWithCredential(credential: AuthCredential): Promise { return this._auth - ._interceptUserValue(this._auth._native.link(credential.providerId, credential.token, credential.secret)); + ._interceptUserValue(getNativeModule(this._auth).link(credential.providerId, credential.token, credential.secret)); } /** @@ -118,7 +119,7 @@ export default class User { */ reauthenticateWithCredential(credential: AuthCredential): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.reauthenticate(credential.providerId, credential.token, credential.secret)); + ._interceptUndefinedUserValue(getNativeModule(this._auth).reauthenticate(credential.providerId, credential.token, credential.secret)); } /** @@ -127,7 +128,7 @@ export default class User { */ reload(): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.reload()); + ._interceptUndefinedUserValue(getNativeModule(this._auth).reload()); } /** @@ -135,7 +136,7 @@ export default class User { */ sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.sendEmailVerification(actionCodeSettings)); + ._interceptUndefinedUserValue(getNativeModule(this._auth).sendEmailVerification(actionCodeSettings)); } toJSON(): Object { @@ -148,7 +149,7 @@ export default class User { * @return {Promise.|*} */ unlink(providerId: string): Promise { - return this._auth._interceptUserValue(this._auth._native.unlink(providerId)); + return this._auth._interceptUserValue(getNativeModule(this._auth).unlink(providerId)); } /** @@ -159,7 +160,7 @@ export default class User { */ updateEmail(email: string): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.updateEmail(email)); + ._interceptUndefinedUserValue(getNativeModule(this._auth).updateEmail(email)); } /** @@ -169,7 +170,7 @@ export default class User { */ updatePassword(password: string): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.updatePassword(password)); + ._interceptUndefinedUserValue(getNativeModule(this._auth).updatePassword(password)); } /** @@ -179,7 +180,7 @@ export default class User { */ updateProfile(updates: Object = {}): Promise { return this._auth - ._interceptUndefinedUserValue(this._auth._native.updateProfile(updates)); + ._interceptUndefinedUserValue(getNativeModule(this._auth).updateProfile(updates)); } /** @@ -189,7 +190,7 @@ export default class User { */ getToken(forceRefresh: boolean = false): Promise { console.warn('Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.'); - return this._auth._native.getToken(forceRefresh); + return getNativeModule(this._auth).getToken(forceRefresh); } /** diff --git a/lib/modules/auth/index.js b/lib/modules/auth/index.js index acf8e0a5..224978a5 100644 --- a/lib/modules/auth/index.js +++ b/lib/modules/auth/index.js @@ -6,6 +6,7 @@ import User from './User'; import ModuleBase from '../../utils/ModuleBase'; import { getAppEventName, SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; +import { getNativeModule } from '../../utils/native'; import INTERNALS from '../../utils/internals'; import ConfirmationResult from './ConfirmationResult'; @@ -20,7 +21,7 @@ import FacebookAuthProvider from './providers/FacebookAuthProvider'; import PhoneAuthListener from './PhoneAuthListener'; import type { ActionCodeSettings, AuthCredential } from '../../types'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; type AuthResult = { authenticated: boolean, @@ -39,8 +40,8 @@ export default class Auth extends ModuleBase { _authResult: AuthResult | null; _user: User | null; - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, @@ -69,8 +70,8 @@ export default class Auth extends ModuleBase { this._onInternalIdTokenChanged.bind(this), ); - this._native.addAuthStateListener(); - this._native.addIdTokenListener(); + getNativeModule(this).addAuthStateListener(); + getNativeModule(this).addIdTokenListener(); } /** @@ -200,7 +201,7 @@ export default class Auth extends ModuleBase { * @return {Promise} */ signOut(): Promise { - return this._interceptUndefinedUserValue(this._native.signOut()); + return this._interceptUndefinedUserValue(getNativeModule(this).signOut()); } /** @@ -208,7 +209,7 @@ export default class Auth extends ModuleBase { * @return {Promise} A promise resolved upon completion */ signInAnonymously(): Promise { - return this._interceptUserValue(this._native.signInAnonymously()); + return this._interceptUserValue(getNativeModule(this).signInAnonymously()); } /** @@ -218,7 +219,7 @@ export default class Auth extends ModuleBase { * @return {Promise} A promise indicating the completion */ createUserWithEmailAndPassword(email: string, password: string): Promise { - return this._interceptUserValue(this._native.createUserWithEmailAndPassword(email, password)); + return this._interceptUserValue(getNativeModule(this).createUserWithEmailAndPassword(email, password)); } /** @@ -228,7 +229,7 @@ export default class Auth extends ModuleBase { * @return {Promise} A promise that is resolved upon completion */ signInWithEmailAndPassword(email: string, password: string): Promise { - return this._interceptUserValue(this._native.signInWithEmailAndPassword(email, password)); + return this._interceptUserValue(getNativeModule(this).signInWithEmailAndPassword(email, password)); } /** @@ -237,7 +238,7 @@ export default class Auth extends ModuleBase { * @return {Promise} A promise resolved upon completion */ signInWithCustomToken(customToken: string): Promise { - return this._interceptUserValue(this._native.signInWithCustomToken(customToken)); + return this._interceptUserValue(getNativeModule(this).signInWithCustomToken(customToken)); } /** @@ -246,7 +247,7 @@ export default class Auth extends ModuleBase { */ signInWithCredential(credential: AuthCredential): Promise { return this._interceptUserValue( - this._native.signInWithCredential( + getNativeModule(this).signInWithCredential( credential.providerId, credential.token, credential.secret, ), ); @@ -257,7 +258,7 @@ export default class Auth extends ModuleBase { * */ signInWithPhoneNumber(phoneNumber: string): Promise { - return this._native.signInWithPhoneNumber(phoneNumber).then((result) => { + return getNativeModule(this).signInWithPhoneNumber(phoneNumber).then((result) => { return new ConfirmationResult(this, result.verificationId); }); } @@ -280,7 +281,7 @@ export default class Auth extends ModuleBase { * @param {string} email The email to send password reset instructions */ sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise { - return this._native.sendPasswordResetEmail(email, actionCodeSettings); + return getNativeModule(this).sendPasswordResetEmail(email, actionCodeSettings); } /** @@ -292,7 +293,7 @@ export default class Auth extends ModuleBase { * @return {Promise.} */ confirmPasswordReset(code: string, newPassword: string): Promise { - return this._native.confirmPasswordReset(code, newPassword); + return getNativeModule(this).confirmPasswordReset(code, newPassword); } /** @@ -303,7 +304,7 @@ export default class Auth extends ModuleBase { * @return {Promise.} */ applyActionCode(code: string): Promise { - return this._native.applyActionCode(code); + return getNativeModule(this).applyActionCode(code); } /** @@ -314,7 +315,7 @@ export default class Auth extends ModuleBase { * @return {Promise.|Promise} */ checkActionCode(code: string): Promise { - return this._native.checkActionCode(code); + return getNativeModule(this).checkActionCode(code); } /** @@ -322,7 +323,7 @@ export default class Auth extends ModuleBase { * @return {Promise} */ getCurrentUser(): Promise { - return this._interceptUserValue(this._native.getCurrentUser()); + return this._interceptUserValue(getNativeModule(this).getCurrentUser()); } /** @@ -330,7 +331,7 @@ export default class Auth extends ModuleBase { * @return {Promise} */ fetchProvidersForEmail(email: string): Promise> { - return this._native.fetchProvidersForEmail(email); + return getNativeModule(this).fetchProvidersForEmail(email); } /** diff --git a/lib/modules/config/index.js b/lib/modules/config/index.js index ea3ab5cb..ab34b94b 100644 --- a/lib/modules/config/index.js +++ b/lib/modules/config/index.js @@ -3,9 +3,10 @@ * Remote Config representation wrapper */ import { getLogger } from '../../utils/log'; -import ModuleBase from './../../utils/ModuleBase'; +import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; type NativeValue = { stringValue?: string, @@ -24,8 +25,8 @@ export const NAMESPACE = 'config'; export default class RemoteConfig extends ModuleBase { _developerModeEnabled: boolean; - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { moduleName: MODULE_NAME, namespace: NAMESPACE, }); @@ -43,7 +44,7 @@ export default class RemoteConfig extends ModuleBase { source: nativeValue.source, val() { if (nativeValue.boolValue !== null && (nativeValue.stringValue === 'true' || nativeValue.stringValue === 'false' || nativeValue.stringValue === null)) return nativeValue.boolValue; - if (nativeValue.numberValue !== null && (nativeValue.stringValue == null || nativeValue.stringValue === '' || `${nativeValue.numberValue}` === nativeValue.stringValue)) return nativeValue.numberValue; + if (nativeValue.numberValue !== null && nativeValue.numberValue !== undefined && (nativeValue.stringValue == null || nativeValue.stringValue === '' || nativeValue.numberValue.toString() === nativeValue.stringValue)) return nativeValue.numberValue; if (nativeValue.dataValue !== nativeValue.stringValue && (nativeValue.stringValue == null || nativeValue.stringValue === '')) return nativeValue.dataValue; return nativeValue.stringValue; }, @@ -56,7 +57,7 @@ export default class RemoteConfig extends ModuleBase { enableDeveloperMode() { if (!this._developerModeEnabled) { getLogger(this).debug('Enabled developer mode'); - this._native.enableDeveloperMode(); + getNativeModule(this).enableDeveloperMode(); this._developerModeEnabled = true; } } @@ -69,10 +70,10 @@ export default class RemoteConfig extends ModuleBase { fetch(expiration?: number) { if (expiration !== undefined) { getLogger(this).debug(`Fetching remote config data with expiration ${expiration.toString()}`); - return this._native.fetchWithExpirationDuration(expiration); + return getNativeModule(this).fetchWithExpirationDuration(expiration); } getLogger(this).debug('Fetching remote config data'); - return this._native.fetch(); + return getNativeModule(this).fetch(); } /** @@ -83,7 +84,7 @@ export default class RemoteConfig extends ModuleBase { */ activateFetched() { getLogger(this).debug('Activating remote config'); - return this._native.activateFetched(); + return getNativeModule(this).activateFetched(); } /** @@ -100,7 +101,7 @@ export default class RemoteConfig extends ModuleBase { * } */ getValue(key: String) { - return this._native + return getNativeModule(this) .getValue(key || '') .then(this._nativeValueToJS); } @@ -120,7 +121,7 @@ export default class RemoteConfig extends ModuleBase { * } */ getValues(keys: Array) { - return this._native + return getNativeModule(this) .getValues(keys || []) .then((nativeValues) => { const values: { [String]: Object } = {}; @@ -137,7 +138,7 @@ export default class RemoteConfig extends ModuleBase { * @returns {*|Promise.>} */ getKeysByPrefix(prefix?: String) { - return this._native.getKeysByPrefix(prefix); + return getNativeModule(this).getKeysByPrefix(prefix); } /** @@ -145,7 +146,7 @@ export default class RemoteConfig extends ModuleBase { * @param defaults: A dictionary mapping a String key to a Object values. */ setDefaults(defaults: Object) { - this._native.setDefaults(defaults); + getNativeModule(this).setDefaults(defaults); } /** @@ -153,7 +154,7 @@ export default class RemoteConfig extends ModuleBase { * @param resource: The plist file name or resource ID */ setDefaultsFromResource(resource: String | number) { - this._native.setDefaultsFromResource(resource); + getNativeModule(this).setDefaultsFromResource(resource); } } diff --git a/lib/modules/core/firebase-app.js b/lib/modules/core/firebase-app.js index ae340e44..a10eb140 100644 --- a/lib/modules/core/firebase-app.js +++ b/lib/modules/core/firebase-app.js @@ -29,7 +29,7 @@ import type { const FirebaseCoreModule = NativeModules.RNFirebase; -export default class FirebaseApp { +export default class App { _extendedProps: { [string] : boolean }; _initialized: boolean = false; _name: string; @@ -119,6 +119,7 @@ export default class FirebaseApp { throw new Error(INTERNALS.STRINGS.ERROR_PROTECTED_PROP(key)); } + // $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 this[key] = props[key]; this._extendedProps[key] = true; } @@ -145,7 +146,7 @@ export default class FirebaseApp { * * @return {*} */ - onReady(): Promise { + onReady(): Promise { if (this._initialized) return Promise.resolve(this); return new Promise((resolve, reject) => { diff --git a/lib/modules/core/firebase.js b/lib/modules/core/firebase.js index 7bd151b6..72ff3eef 100644 --- a/lib/modules/core/firebase.js +++ b/lib/modules/core/firebase.js @@ -6,7 +6,7 @@ import { NativeModules } from 'react-native'; import APPS from '../../utils/apps'; import INTERNALS from '../../utils/internals'; -import FirebaseApp from './firebase-app'; +import App from './firebase-app'; // module imports import { statics as AdMobStatics, MODULE_NAME as AdmobModuleName } from '../admob'; @@ -88,7 +88,7 @@ class FirebaseCore { * @param name * @return {*} */ - initializeApp(options: FirebaseOptions, name: string): FirebaseApp { + initializeApp(options: FirebaseOptions, name: string): App { return APPS.initializeApp(options, name); } @@ -101,7 +101,7 @@ class FirebaseCore { * @param name * @return {*} */ - app(name?: string): FirebaseApp { + app(name?: string): App { return APPS.app(name); } @@ -109,7 +109,7 @@ class FirebaseCore { * A (read-only) array of all initialized apps. * @return {Array} */ - get apps(): Array { + get apps(): Array { return APPS.apps(); } } diff --git a/lib/modules/crash/index.js b/lib/modules/crash/index.js index 9d2a2042..48fbbea4 100644 --- a/lib/modules/crash/index.js +++ b/lib/modules/crash/index.js @@ -3,16 +3,17 @@ * Crash Reporting representation wrapper */ import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; import type { FirebaseError } from '../../types'; export const MODULE_NAME = 'RNFirebaseCrash'; export const NAMESPACE = 'crash'; export default class Crash extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { moduleName: MODULE_NAME, namespace: NAMESPACE, }); @@ -23,7 +24,7 @@ export default class Crash extends ModuleBase { * @param enabled */ setCrashCollectionEnabled(enabled: boolean): void { - this._native.setCrashCollectionEnabled(enabled); + getNativeModule(this).setCrashCollectionEnabled(enabled); } /** @@ -31,7 +32,7 @@ export default class Crash extends ModuleBase { * @returns {Promise.} */ isCrashCollectionEnabled(): Promise { - return this._native.isCrashCollectionEnabled(); + return getNativeModule(this).isCrashCollectionEnabled(); } /** @@ -39,7 +40,7 @@ export default class Crash extends ModuleBase { * @param {string} message */ log(message: string): void { - this._native.log(message); + getNativeModule(this).log(message); } /** @@ -50,7 +51,7 @@ export default class Crash extends ModuleBase { * @param {string} tag */ logcat(level: number, tag: string, message: string): void { - this._native.logcat(level, tag, message); + getNativeModule(this).logcat(level, tag, message); } /** @@ -77,7 +78,7 @@ export default class Crash extends ModuleBase { errorMessage = `${errorMessage} - ${stackRows[i]}\r\n`; } - this._native.report(errorMessage); + getNativeModule(this).report(errorMessage); } } diff --git a/lib/modules/database/index.js b/lib/modules/database/index.js index cfac1094..f40e7ac6 100644 --- a/lib/modules/database/index.js +++ b/lib/modules/database/index.js @@ -1,4 +1,4 @@ -/** +getNativeModule(this)/** * @flow * Database representation wrapper */ @@ -6,9 +6,10 @@ import { NativeModules } from 'react-native'; import Reference from './reference'; import TransactionHandler from './transaction'; -import ModuleBase from './../../utils/ModuleBase'; +import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; const NATIVE_EVENTS = [ 'database_transaction_event', @@ -26,19 +27,16 @@ export default class Database extends ModuleBase { _serverTimeOffset: number; _transactionHandler: TransactionHandler; - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, { - persistence: false, - ...options, - }, { + constructor(app: App, options: Object = {}) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, }); this._transactionHandler = new TransactionHandler(this); - if (this._options.persistence) { - this._native.setPersistence(this._options.persistence); + if (options.persistence) { + getNativeModule(this).setPersistence(options.persistence); } // server time listener @@ -66,14 +64,14 @@ export default class Database extends ModuleBase { * */ goOnline(): void { - this._native.goOnline(); + getNativeModule(this).goOnline(); } /** * */ goOffline(): void { - this._native.goOffline(); + getNativeModule(this).goOffline(); } /** diff --git a/lib/modules/database/reference.js b/lib/modules/database/reference.js index fbb2a7e2..42f41a96 100644 --- a/lib/modules/database/reference.js +++ b/lib/modules/database/reference.js @@ -6,6 +6,7 @@ import Query from './query.js'; import Snapshot from './snapshot'; import Disconnect from './disconnect'; import { getLogger } from '../../utils/log'; +import { getNativeModule } from '../../utils/native'; import ReferenceBase from '../../utils/ReferenceBase'; import { @@ -80,7 +81,7 @@ export default class Reference extends ReferenceBase { _refListeners: { [listenerId: number]: DatabaseListener }; constructor(database: Database, path: string, existingModifiers?: Array) { - super(path, database); + super(path); this._promise = null; this._refListeners = {}; this._database = database; @@ -99,7 +100,7 @@ export default class Reference extends ReferenceBase { * @returns {*} */ keepSynced(bool: boolean): Promise { - return this._database._native.keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool); + return getNativeModule(this._database).keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool); } /** @@ -112,7 +113,7 @@ export default class Reference extends ReferenceBase { */ set(value: any, onComplete?: Function): Promise { return promiseOrCallback( - this._database._native.set(this.path, this._serializeAnyType(value)), + getNativeModule(this._database).set(this.path, this._serializeAnyType(value)), onComplete, ); } @@ -129,7 +130,7 @@ export default class Reference extends ReferenceBase { const _priority = this._serializeAnyType(priority); return promiseOrCallback( - this._database._native.setPriority(this.path, _priority), + getNativeModule(this._database).setPriority(this.path, _priority), onComplete, ); } @@ -148,7 +149,7 @@ export default class Reference extends ReferenceBase { const _priority = this._serializeAnyType(priority); return promiseOrCallback( - this._database._native.setWithPriority(this.path, _value, _priority), + getNativeModule(this._database).setWithPriority(this.path, _value, _priority), onComplete, ); } @@ -165,7 +166,7 @@ export default class Reference extends ReferenceBase { const value = this._serializeObject(val); return promiseOrCallback( - this._database._native.update(this.path, value), + getNativeModule(this._database).update(this.path, value), onComplete, ); } @@ -179,7 +180,7 @@ export default class Reference extends ReferenceBase { */ remove(onComplete?: Function): Promise { return promiseOrCallback( - this._database._native.remove(this.path), + getNativeModule(this._database).remove(this.path), onComplete, ); } @@ -235,7 +236,7 @@ export default class Reference extends ReferenceBase { cancelOrContext: (error: FirebaseError) => void, context?: Object, ) { - return this._database._native.once(this._getRefKey(), this.path, this._query.getModifiers(), eventName) + return getNativeModule(this._database).once(this._getRefKey(), this.path, this._query.getModifiers(), eventName) .then(({ snapshot }) => { const _snapshot = new Snapshot(this, snapshot); @@ -270,7 +271,9 @@ export default class Reference extends ReferenceBase { // if callback provided then internally call the set promise with value if (isFunction(onComplete)) { return promise + // $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655 .then(() => onComplete(null, newRef)) + // $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655 .catch(error => onComplete(error, null)); } @@ -620,7 +623,7 @@ export default class Reference extends ReferenceBase { * * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on} */ - on(eventType: string, callback: () => any, cancelCallbackOrContext?: () => any, context?: Object): Function { + on(eventType: string, callback: (Snapshot) => any, cancelCallbackOrContext?: (Object) => any | Object, context?: Object): Function { if (!eventType) { throw new Error('Query.on failed: Function called with 0 arguments. Expects at least 2.'); } @@ -657,28 +660,29 @@ export default class Reference extends ReferenceBase { eventRegistrationKey, }; - SyncTree.addRegistration(registrationObj, _context ? callback.bind(_context) : callback); + SyncTree.addRegistration({ + ...registrationObj, + listener: _context ? callback.bind(_context) : callback, + }); - if (isFunction(cancelCallbackOrContext)) { + if (cancelCallbackOrContext && isFunction(cancelCallbackOrContext)) { // cancellations have their own separate registration // as these are one off events, and they're not guaranteed // to occur either, only happens on failure to register on native - SyncTree.addRegistration( - { - ref: this, - once: true, - path: this.path, - key: this._getRefKey(), - appName: this._database.app.name, - eventType: `${eventType}$cancelled`, - eventRegistrationKey: registrationCancellationKey, - }, - _context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext, - ); + SyncTree.addRegistration({ + ref: this, + once: true, + path: this.path, + key: this._getRefKey(), + appName: this._database.app.name, + eventType: `${eventType}$cancelled`, + eventRegistrationKey: registrationCancellationKey, + listener: _context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext, + }); } // initialise the native listener if not already listening - this._database._native.on({ + getNativeModule(this._database).on({ eventType, path: this.path, key: this._getRefKey(), diff --git a/lib/modules/database/transaction.js b/lib/modules/database/transaction.js index 79d7bcf3..1711d441 100644 --- a/lib/modules/database/transaction.js +++ b/lib/modules/database/transaction.js @@ -4,17 +4,27 @@ */ import { getAppEventName, SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; +import { getNativeModule } from '../../utils/native'; import type Database from './'; let transactionId = 0; +/** + * Uses the push id generator to create a transaction id + * @returns {number} + * @private + */ +const generateTransactionId = (): number => { + return transactionId++; +}; + /** * @class TransactionHandler */ export default class TransactionHandler { _database: Database; _transactionListener: Function; - _transactions: { [string]: Object } + _transactions: { [number]: Object } constructor(database: Database) { this._transactions = {}; @@ -34,7 +44,7 @@ export default class TransactionHandler { * @param applyLocally */ add(reference: Object, transactionUpdater: Function, onComplete?: Function, applyLocally?: boolean = false) { - const id = this._generateTransactionId(); + const id = generateTransactionId(); this._transactions[id] = { id, @@ -46,22 +56,13 @@ export default class TransactionHandler { started: true, }; - this._database._native.transactionStart(reference.path, id, applyLocally); + getNativeModule(this._database).transactionStart(reference.path, id, applyLocally); } /** * INTERNALS */ - /** - * Uses the push id generator to create a transaction id - * @returns {string} - * @private - */ - _generateTransactionId(): string { - return transactionId++; - } - /** * * @param event @@ -103,7 +104,7 @@ export default class TransactionHandler { abort = true; } - this._database._native.transactionTryCommit(id, { value: newValue, abort }); + getNativeModule(this._database).transactionTryCommit(id, { value: newValue, abort }); } } @@ -117,7 +118,7 @@ export default class TransactionHandler { if (transaction && !transaction.completed) { transaction.completed = true; try { - transaction.onComplete(new Error(event.error.message, event.error.code), null); + transaction.onComplete(event.error, false, null); } finally { setImmediate(() => { delete this._transactions[event.id]; diff --git a/lib/modules/fabric/crashlytics/index.js b/lib/modules/fabric/crashlytics/index.js index 5c55bb0c..789c9af8 100644 --- a/lib/modules/fabric/crashlytics/index.js +++ b/lib/modules/fabric/crashlytics/index.js @@ -3,15 +3,16 @@ * Crash Reporting representation wrapper */ import ModuleBase from '../../../utils/ModuleBase'; +import { getNativeModule } from '../../../utils/native'; -import type FirebaseApp from '../../core/firebase-app'; +import type App from '../../core/firebase-app'; export const MODULE_NAME = 'RNFirebaseCrashlytics'; export const NAMESPACE = 'crashlytics'; export default class Crashlytics extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { moduleName: MODULE_NAME, namespace: NAMESPACE, }); @@ -21,7 +22,7 @@ export default class Crashlytics extends ModuleBase { * Forces a crash. Useful for testing your application is set up correctly. */ crash(): void { - this._native.crash(); + getNativeModule(this).crash(); } /** @@ -29,7 +30,7 @@ export default class Crashlytics extends ModuleBase { * @param {string} message */ log(message: string): void { - this._native.log(message); + getNativeModule(this).log(message); } /** @@ -38,42 +39,42 @@ export default class Crashlytics extends ModuleBase { * @param {string} message */ recordError(code: number, message: string): void { - this._native.recordError(code, message); + getNativeModule(this).recordError(code, message); } /** * Set a boolean value to show alongside any subsequent crash reports. */ setBoolValue(key: string, value: boolean): void { - this._native.setBoolValue(key, value); + getNativeModule(this).setBoolValue(key, value); } /** * Set a float value to show alongside any subsequent crash reports. */ setFloatValue(key: string, value: number): void { - this._native.setFloatValue(key, value); + getNativeModule(this).setFloatValue(key, value); } /** * Set an integer value to show alongside any subsequent crash reports. */ setIntValue(key: string, value: number): void { - this._native.setIntValue(key, value); + getNativeModule(this).setIntValue(key, value); } /** * Set a string value to show alongside any subsequent crash reports. */ setStringValue(key: string, value: string): void { - this._native.setStringValue(key, value); + getNativeModule(this).setStringValue(key, value); } /** * Set the user ID to show alongside any subsequent crash reports. */ setUserIdentifier(userId: string): void { - this._native.setUserIdentifier(userId); + getNativeModule(this).setUserIdentifier(userId); } } diff --git a/lib/modules/firestore/CollectionReference.js b/lib/modules/firestore/CollectionReference.js index 87598b57..c3cba570 100644 --- a/lib/modules/firestore/CollectionReference.js +++ b/lib/modules/firestore/CollectionReference.js @@ -6,11 +6,10 @@ import DocumentReference from './DocumentReference'; import Query from './Query'; import { firestoreAutoId } from '../../utils'; -import type DocumentSnapshot from './DocumentSnapshot'; import type Firestore from './'; import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types'; import type Path from './Path'; -import type { Observer, QueryListenOptions } from './Query'; +import type { Observer, ObserverOnError, ObserverOnNext, QueryListenOptions } from './Query'; import type QuerySnapshot from './QuerySnapshot'; /** @@ -75,9 +74,9 @@ export default class CollectionReference { } onSnapshot( - optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void, - observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void, - onError?: (Object) => void, + optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext, + observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, + onError?: ObserverOnError, ): () => void { return this._query.onSnapshot(optionsOrObserverOrOnNext, observerOrOnNextOrOnError, onError); } diff --git a/lib/modules/firestore/DocumentReference.js b/lib/modules/firestore/DocumentReference.js index 0befcbfd..e401d4f1 100644 --- a/lib/modules/firestore/DocumentReference.js +++ b/lib/modules/firestore/DocumentReference.js @@ -8,6 +8,7 @@ import { buildNativeMap } from './utils/serialize'; import { getAppEventName, SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; import { firestoreAutoId, isFunction, isObject, isString } from '../../utils'; +import { getNativeModule } from '../../utils/native'; import type Firestore from './'; import type { FirestoreNativeDocumentSnapshot, FirestoreWriteOptions } from '../../types'; @@ -67,12 +68,12 @@ export default class DocumentReference { } delete(): Promise { - return this._firestore._native + return getNativeModule(this._firestore) .documentDelete(this.path); } get(): Promise { - return this._firestore._native + return getNativeModule(this._firestore) .documentGet(this.path) .then(result => new DocumentSnapshot(this._firestore, result)); } @@ -82,15 +83,18 @@ export default class DocumentReference { observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, onError?: ObserverOnError, ) { - let observer = {}; + let observer: Observer; let docListenOptions = {}; // Called with: onNext, ?onError if (isFunction(optionsOrObserverOrOnNext)) { - observer.next = optionsOrObserverOrOnNext; if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.'); } - observer.error = observerOrOnNextOrOnError; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: optionsOrObserverOrOnNext, + error: observerOrOnNextOrOnError, + }; } else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) { // Called with: Observer if (optionsOrObserverOrOnNext.next) { @@ -98,7 +102,11 @@ export default class DocumentReference { if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) { throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.'); } - observer = optionsOrObserverOrOnNext; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: optionsOrObserverOrOnNext.next, + error: optionsOrObserverOrOnNext.error, + }; } else { throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.'); } @@ -106,18 +114,24 @@ export default class DocumentReference { docListenOptions = optionsOrObserverOrOnNext; // Called with: Options, onNext, ?onError if (isFunction(observerOrOnNextOrOnError)) { - observer.next = observerOrOnNextOrOnError; if (onError && !isFunction(onError)) { throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.'); } - observer.error = onError; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: observerOrOnNextOrOnError, + error: onError, + }; // Called with Options, Observer } else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) { if (isFunction(observerOrOnNextOrOnError.next)) { if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) { throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.'); } - observer = observerOrOnNextOrOnError; + observer = { + next: observerOrOnNextOrOnError.next, + error: observerOrOnNextOrOnError.error, + }; } else { throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.'); } @@ -152,7 +166,7 @@ export default class DocumentReference { } // Add the native listener - this._firestore._native + getNativeModule(this._firestore) .documentOnSnapshot(this.path, listenerId, docListenOptions); // Return an unsubscribe method @@ -161,7 +175,7 @@ export default class DocumentReference { set(data: Object, writeOptions?: FirestoreWriteOptions): Promise { const nativeData = buildNativeMap(data); - return this._firestore._native + return getNativeModule(this._firestore) .documentSet(this.path, nativeData, writeOptions); } @@ -185,7 +199,7 @@ export default class DocumentReference { } } const nativeData = buildNativeMap(data); - return this._firestore._native + return getNativeModule(this._firestore) .documentUpdate(this.path, nativeData); } @@ -201,7 +215,7 @@ export default class DocumentReference { getLogger(this._firestore).info('Removing onDocumentSnapshot listener'); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), listener); - this._firestore._native + getNativeModule(this._firestore) .documentOffSnapshot(this.path, listenerId); } } diff --git a/lib/modules/firestore/Query.js b/lib/modules/firestore/Query.js index 5f5b9129..5d26f977 100644 --- a/lib/modules/firestore/Query.js +++ b/lib/modules/firestore/Query.js @@ -8,6 +8,7 @@ import { buildNativeArray, buildTypeMap } from './utils/serialize'; import { getAppEventName, SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; import { firestoreAutoId, isFunction, isObject } from '../../utils'; +import { getNativeModule } from '../../utils/native'; import type Firestore from './'; import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types'; @@ -53,9 +54,12 @@ export type QueryListenOptions = { includeQueryMetadataChanges: boolean, } +export type ObserverOnError = (Object) => void; +export type ObserverOnNext = (QuerySnapshot) => void; + export type Observer = { - next: (DocumentSnapshot) => void, - error?: (Object) => void, + error?: ObserverOnError, + next: ObserverOnNext, } /** @@ -119,7 +123,7 @@ export default class Query { } get(): Promise { - return this._firestore._native + return getNativeModule(this._firestore) .collectionGet( this._referencePath.relativeName, this._fieldFilters, @@ -147,19 +151,22 @@ export default class Query { } onSnapshot( - optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void, - observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void, - onError?: (Object) => void, + optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext, + observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, + onError?: ObserverOnError, ) { - let observer = {}; + let observer: Observer; let queryListenOptions = {}; // Called with: onNext, ?onError if (isFunction(optionsOrObserverOrOnNext)) { - observer.next = optionsOrObserverOrOnNext; if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { throw new Error('Query.onSnapshot failed: Second argument must be a valid function.'); } - observer.error = observerOrOnNextOrOnError; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: optionsOrObserverOrOnNext, + error: observerOrOnNextOrOnError, + }; } else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) { // Called with: Observer if (optionsOrObserverOrOnNext.next) { @@ -167,7 +174,11 @@ export default class Query { if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) { throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.'); } - observer = optionsOrObserverOrOnNext; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: optionsOrObserverOrOnNext.next, + error: optionsOrObserverOrOnNext.error, + }; } else { throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.'); } @@ -175,18 +186,24 @@ export default class Query { queryListenOptions = optionsOrObserverOrOnNext; // Called with: Options, onNext, ?onError if (isFunction(observerOrOnNextOrOnError)) { - observer.next = observerOrOnNextOrOnError; if (onError && !isFunction(onError)) { throw new Error('Query.onSnapshot failed: Third argument must be a valid function.'); } - observer.error = onError; + // $FlowBug: Not coping with the overloaded method signature + observer = { + next: observerOrOnNextOrOnError, + error: onError, + }; // Called with Options, Observer } else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) { if (isFunction(observerOrOnNextOrOnError.next)) { if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) { throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.'); } - observer = observerOrOnNextOrOnError; + observer = { + next: observerOrOnNextOrOnError.next, + error: observerOrOnNextOrOnError.error, + }; } else { throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.'); } @@ -199,7 +216,6 @@ export default class Query { } else { throw new Error('Query.onSnapshot failed: Called with invalid arguments.'); } - const listenerId = firestoreAutoId(); const listener = (nativeQuerySnapshot) => { @@ -222,7 +238,7 @@ export default class Query { } // Add the native listener - this._firestore._native + getNativeModule(this._firestore) .collectionOnSnapshot( this._referencePath.relativeName, this._fieldFilters, @@ -339,7 +355,7 @@ export default class Query { getLogger(this._firestore).info('Removing onQuerySnapshot listener'); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), listener); - this._firestore._native + getNativeModule(this._firestore) .collectionOffSnapshot( this._referencePath.relativeName, this._fieldFilters, diff --git a/lib/modules/firestore/WriteBatch.js b/lib/modules/firestore/WriteBatch.js index 6d687ac9..2b315de2 100644 --- a/lib/modules/firestore/WriteBatch.js +++ b/lib/modules/firestore/WriteBatch.js @@ -4,6 +4,7 @@ */ import { buildNativeMap } from './utils/serialize'; import { isObject, isString } from '../../utils'; +import { getNativeModule } from '../../utils/native'; import type DocumentReference from './DocumentReference'; import type Firestore from './'; @@ -29,8 +30,7 @@ export default class WriteBatch { } commit(): Promise { - return this._firestore._native - .documentBatch(this._writes); + return getNativeModule(this._firestore).documentBatch(this._writes); } delete(docRef: DocumentReference): WriteBatch { diff --git a/lib/modules/firestore/index.js b/lib/modules/firestore/index.js index ac78e497..7061ed4b 100644 --- a/lib/modules/firestore/index.js +++ b/lib/modules/firestore/index.js @@ -15,7 +15,7 @@ import WriteBatch from './WriteBatch'; import INTERNALS from '../../utils/internals'; import type DocumentSnapshot from './DocumentSnapshot'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; import type QuerySnapshot from './QuerySnapshot'; type CollectionSyncEvent = { @@ -48,8 +48,8 @@ export const NAMESPACE = 'firestore'; export default class Firestore extends ModuleBase { _referencePath: Path; - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, diff --git a/lib/modules/links/index.js b/lib/modules/links/index.js index 411a2427..1ca4f3ca 100644 --- a/lib/modules/links/index.js +++ b/lib/modules/links/index.js @@ -4,9 +4,10 @@ */ import { SharedEventEmitter } from '../../utils/events'; import ModuleBase from '../../utils/ModuleBase'; -import { areObjectKeysContainedInOther, isObject, isString } from './../../utils'; +import { areObjectKeysContainedInOther, isObject, isString } from '../../utils'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; const EVENT_TYPE = { Link: 'dynamic_link_received', @@ -70,8 +71,8 @@ function checkForMandatoryParameters(parameters: Object): void { * @class Links */ export default class Links extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, @@ -87,7 +88,7 @@ export default class Links extends ModuleBase { * @returns {Promise.} */ getInitialLink(): Promise { - return this._native.getInitialLink(); + return getNativeModule(this).getInitialLink(); } /** @@ -109,7 +110,7 @@ export default class Links extends ModuleBase { try { checkForMandatoryParameters(parameters); validateParameters(parameters); - return this._native.createDynamicLink(parameters); + return getNativeModule(this).createDynamicLink(parameters); } catch (error) { return Promise.reject(error); } @@ -124,7 +125,7 @@ export default class Links extends ModuleBase { try { checkForMandatoryParameters(parameters); validateParameters(parameters); - return this._native.createShortDynamicLink(parameters); + return getNativeModule(this).createShortDynamicLink(parameters); } catch (error) { return Promise.reject(error); } diff --git a/lib/modules/messaging/index.js b/lib/modules/messaging/index.js index ab365583..0686f860 100644 --- a/lib/modules/messaging/index.js +++ b/lib/modules/messaging/index.js @@ -6,8 +6,9 @@ import { Platform, NativeModules } from 'react-native'; import { SharedEventEmitter } from '../../utils/events'; import ModuleBase from '../../utils/ModuleBase'; import RemoteMessage from './RemoteMessage'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; const EVENT_TYPE = { RefreshToken: 'messaging_token_refreshed', @@ -86,8 +87,8 @@ export const NAMESPACE = 'messaging'; * @class Messaging */ export default class Messaging extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, @@ -115,7 +116,7 @@ export default class Messaging extends ModuleBase { * @returns {*} */ getInitialNotification(): Promise { - return this._native.getInitialNotification(); + return getNativeModule(this).getInitialNotification(); } /** @@ -123,7 +124,7 @@ export default class Messaging extends ModuleBase { * @returns {*|Promise.} */ getToken(): Promise { - return this._native.getToken(); + return getNativeModule(this).getToken(); } /** @@ -131,7 +132,7 @@ export default class Messaging extends ModuleBase { * @returns {*|Promise.<*>} */ deleteInstanceId(): Promise { - return this._native.deleteInstanceId(); + return getNativeModule(this).deleteInstanceId(); } /** @@ -143,7 +144,7 @@ export default class Messaging extends ModuleBase { const _notification = Object.assign({}, notification); _notification.id = _notification.id || new Date().getTime().toString(); _notification.local_notification = true; - return this._native.createLocalNotification(_notification); + return getNativeModule(this).createLocalNotification(_notification); } /** @@ -155,7 +156,7 @@ export default class Messaging extends ModuleBase { const _notification = Object.assign({}, notification); if (!notification.id) return Promise.reject(new Error('An id is required to schedule a local notification.')); _notification.local_notification = true; - return this._native.scheduleLocalNotification(_notification); + return getNativeModule(this).scheduleLocalNotification(_notification); } /** @@ -163,7 +164,7 @@ export default class Messaging extends ModuleBase { * @returns {Promise.} */ getScheduledLocalNotifications(): Promise { - return this._native.getScheduledLocalNotifications(); + return getNativeModule(this).getScheduledLocalNotifications(); } /** @@ -174,8 +175,8 @@ export default class Messaging extends ModuleBase { */ cancelLocalNotification(id: string): Promise { if (!id) return Promise.reject(new Error('Missing notification id')); - if (id === '*') return this._native.cancelAllLocalNotifications(); - return this._native.cancelLocalNotification(id); + if (id === '*') return getNativeModule(this).cancelAllLocalNotifications(); + return getNativeModule(this).cancelLocalNotification(id); } /** @@ -186,8 +187,8 @@ export default class Messaging extends ModuleBase { */ removeDeliveredNotification(id: string): Promise { if (!id) return Promise.reject(new Error('Missing notification id')); - if (id === '*') return this._native.removeAllDeliveredNotifications(); - return this._native.removeDeliveredNotification(id); + if (id === '*') return getNativeModule(this).removeAllDeliveredNotifications(); + return getNativeModule(this).removeDeliveredNotification(id); } /** @@ -196,7 +197,7 @@ export default class Messaging extends ModuleBase { * @returns {*|Promise.<*>} */ requestPermissions(): Promise { - return this._native.requestPermissions(); + return getNativeModule(this).requestPermissions(); } @@ -205,7 +206,7 @@ export default class Messaging extends ModuleBase { * @param n */ setBadgeNumber(n: number): void { - this._native.setBadgeNumber(n); + getNativeModule(this).setBadgeNumber(n); } /** @@ -213,7 +214,7 @@ export default class Messaging extends ModuleBase { * @returns {Promise.} */ getBadgeNumber(): Promise { - return this._native.getBadgeNumber(); + return getNativeModule(this).getBadgeNumber(); } /** @@ -254,7 +255,7 @@ export default class Messaging extends ModuleBase { * @param topic */ subscribeToTopic(topic: string): void { - this._native.subscribeToTopic(topic); + getNativeModule(this).subscribeToTopic(topic); } /** @@ -262,7 +263,7 @@ export default class Messaging extends ModuleBase { * @param topic */ unsubscribeFromTopic(topic: string): void { - this._native.unsubscribeFromTopic(topic); + getNativeModule(this).unsubscribeFromTopic(topic); } /** @@ -274,7 +275,7 @@ export default class Messaging extends ModuleBase { throw new Error('messaging().send requires an instance of RemoteMessage as the first argument.'); } - return this._native.send(remoteMessage.toJSON()); + return getNativeModule(this).send(remoteMessage.toJSON()); } } diff --git a/lib/modules/perf/Trace.js b/lib/modules/perf/Trace.js index 5b5614b1..5fd54608 100644 --- a/lib/modules/perf/Trace.js +++ b/lib/modules/perf/Trace.js @@ -2,26 +2,27 @@ * @flow * Trace representation wrapper */ +import { getNativeModule } from '../../utils/native'; import type PerformanceMonitoring from './'; export default class Trace { identifier: string; - perf: PerformanceMonitoring; + _perf: PerformanceMonitoring; constructor(perf: PerformanceMonitoring, identifier: string) { - this.perf = perf; + this._perf = perf; this.identifier = identifier; } start(): void { - this.perf._native.start(this.identifier); + getNativeModule(this._perf).start(this.identifier); } stop(): void { - this.perf._native.stop(this.identifier); + getNativeModule(this._perf).stop(this.identifier); } incrementCounter(event: string): void { - this.perf._native.incrementCounter(this.identifier, event); + getNativeModule(this._perf).incrementCounter(this.identifier, event); } } diff --git a/lib/modules/perf/index.js b/lib/modules/perf/index.js index 7ac349c3..165919ad 100644 --- a/lib/modules/perf/index.js +++ b/lib/modules/perf/index.js @@ -4,15 +4,16 @@ */ import Trace from './Trace'; import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; export const MODULE_NAME = 'RNFirebasePerformance'; export const NAMESPACE = 'perf'; export default class PerformanceMonitoring extends ModuleBase { - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { moduleName: MODULE_NAME, namespace: NAMESPACE, }); @@ -24,7 +25,7 @@ export default class PerformanceMonitoring extends ModuleBase { * @returns {*} */ setPerformanceCollectionEnabled(enabled: boolean): void { - this._native.setPerformanceCollectionEnabled(enabled); + getNativeModule(this).setPerformanceCollectionEnabled(enabled); } /** diff --git a/lib/modules/storage/index.js b/lib/modules/storage/index.js index 77f0400f..f0f86282 100644 --- a/lib/modules/storage/index.js +++ b/lib/modules/storage/index.js @@ -7,9 +7,10 @@ import { NativeModules } from 'react-native'; import StorageRef from './reference'; import { getAppEventName, SharedEventEmitter } from '../../utils/events'; import { getLogger } from '../../utils/log'; -import ModuleBase from './../../utils/ModuleBase'; +import ModuleBase from '../../utils/ModuleBase'; +import { getNativeModule } from '../../utils/native'; -import type FirebaseApp from '../core/firebase-app'; +import type App from '../core/firebase-app'; const FirebaseStorage = NativeModules.RNFirebaseStorage; @@ -24,11 +25,11 @@ export const NAMESPACE = 'storage'; export default class Storage extends ModuleBase { /** * - * @param firebaseApp + * @param app * @param options */ - constructor(firebaseApp: FirebaseApp, options: Object = {}) { - super(firebaseApp, options, { + constructor(app: App) { + super(app, { events: NATIVE_EVENTS, moduleName: MODULE_NAME, namespace: NAMESPACE, @@ -61,7 +62,7 @@ export default class Storage extends ModuleBase { * @param url * @returns {StorageReference} */ - refFromURL(url: string): Promise { + refFromURL(url: string): StorageRef { // TODO don't think this is correct? return new StorageRef(this, `url::${url}`); } @@ -72,7 +73,7 @@ export default class Storage extends ModuleBase { * @param time The new maximum operation retry time in milliseconds. */ setMaxOperationRetryTime(time: number): void { - this._native.setMaxOperationRetryTime(time); + getNativeModule(this).setMaxOperationRetryTime(time); } /** @@ -81,7 +82,7 @@ export default class Storage extends ModuleBase { * @param time The new maximum upload retry time in milliseconds. */ setMaxUploadRetryTime(time: number): void { - this._native.setMaxUploadRetryTime(time); + getNativeModule(this).setMaxUploadRetryTime(time); } /** @@ -90,7 +91,7 @@ export default class Storage extends ModuleBase { * @param time The new maximum download retry time in milliseconds. */ setMaxDownloadRetryTime(time: number): void { - this._native.setMaxDownloadRetryTime(time); + getNativeModule(this).setMaxDownloadRetryTime(time); } /** diff --git a/lib/modules/storage/reference.js b/lib/modules/storage/reference.js index d38c5d2a..8db997ad 100644 --- a/lib/modules/storage/reference.js +++ b/lib/modules/storage/reference.js @@ -4,6 +4,7 @@ */ import ReferenceBase from '../../utils/ReferenceBase'; import StorageTask, { UPLOAD_TASK, DOWNLOAD_TASK } from './task'; +import { getNativeModule } from '../../utils/native'; import type Storage from './'; @@ -14,7 +15,7 @@ export default class StorageReference extends ReferenceBase { _storage: Storage; constructor(storage: Storage, path: string) { - super(path, storage); + super(path); this._storage = storage; } @@ -40,7 +41,7 @@ export default class StorageReference extends ReferenceBase { * @returns {Promise.|*} */ delete(): Promise { - return this._storage._native.delete(this.path); + return getNativeModule(this._storage).delete(this.path); } /** @@ -48,7 +49,7 @@ export default class StorageReference extends ReferenceBase { * @returns {Promise.|*} */ getDownloadURL(): Promise { - return this._storage._native.getDownloadURL(this.path); + return getNativeModule(this._storage).getDownloadURL(this.path); } /** @@ -56,7 +57,7 @@ export default class StorageReference extends ReferenceBase { * @returns {Promise.|*} */ getMetadata(): Promise { - return this._storage._native.getMetadata(this.path); + return getNativeModule(this._storage).getMetadata(this.path); } /** @@ -65,7 +66,7 @@ export default class StorageReference extends ReferenceBase { * @returns {Promise.|*} */ updateMetadata(metadata: Object = {}): Promise { - return this._storage._native.updateMetadata(this.path, metadata); + return getNativeModule(this._storage).updateMetadata(this.path, metadata); } /** @@ -74,7 +75,7 @@ export default class StorageReference extends ReferenceBase { * @return {Promise} */ downloadFile(filePath: string): Promise { - return new StorageTask(DOWNLOAD_TASK, this._storage._native.downloadFile(this.path, filePath), this); + return new StorageTask(DOWNLOAD_TASK, getNativeModule(this._storage).downloadFile(this.path, filePath), this); } /** @@ -93,6 +94,6 @@ export default class StorageReference extends ReferenceBase { */ putFile(filePath: Object, metadata: Object = {}): Promise { const _filePath = filePath.replace('file://', ''); - return new StorageTask(UPLOAD_TASK, this._module._native.putFile(this.path, _filePath, metadata), this); + return new StorageTask(UPLOAD_TASK, getNativeModule(this._storage).putFile(this.path, _filePath, metadata), this); } } diff --git a/lib/modules/utils/index.js b/lib/modules/utils/index.js index 9e3cc5db..6b9ade59 100644 --- a/lib/modules/utils/index.js +++ b/lib/modules/utils/index.js @@ -25,25 +25,23 @@ export default class RNFirebaseUtils extends ModuleBase { * */ checkPlayServicesAvailability() { - if (isIOS) return null; + if (isIOS) return; - const { code } = this.playServicesAvailability; + const { status } = this.playServicesAvailability; if (!this.playServicesAvailability.isAvailable) { if (INTERNALS.OPTIONS.promptOnMissingPlayServices && this.playServicesAvailability.isUserResolvableError) { this.promptForPlayServices(); } else { - const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(code); + const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(status); if (INTERNALS.OPTIONS.errorOnMissingPlayServices) { - if (code === 2) console.warn(error); // only warn if it exists but may need an update + if (status === 2) console.warn(error); // only warn if it exists but may need an update else throw new Error(error); } else { console.warn(error); } } } - - return null; } promptForPlayServices() { @@ -64,10 +62,10 @@ export default class RNFirebaseUtils extends ModuleBase { /** * Set the global logging level for all logs. * - * @param booleanOrDebugString + * @param logLevel */ - set logLevel(booleanOrDebugString) { - INTERNALS.OPTIONS.logLevel = booleanOrDebugString; + set logLevel(logLevel: string) { + INTERNALS.OPTIONS.logLevel = logLevel; } /** diff --git a/lib/utils/ModuleBase.js b/lib/utils/ModuleBase.js index c93ba6ba..35ed7eb3 100644 --- a/lib/utils/ModuleBase.js +++ b/lib/utils/ModuleBase.js @@ -4,21 +4,18 @@ import { initialiseLogger } from './log'; import { initialiseNativeModule } from './native'; -import type FirebaseApp from '../modules/core/firebase-app'; +import type App from '../modules/core/firebase-app'; import type { FirebaseModuleConfig } from '../types'; export default class ModuleBase { - _firebaseApp: FirebaseApp; - _native: Object; - _options: Object; + _app: App; /** * - * @param firebaseApp - * @param options - * @param withEventEmitter + * @param app + * @param config */ - constructor(firebaseApp: FirebaseApp, options: Object, config: FirebaseModuleConfig) { + constructor(app: App, config: FirebaseModuleConfig) { if (!config.moduleName) { throw new Error('Missing module name'); } @@ -26,20 +23,18 @@ export default class ModuleBase { throw new Error('Missing namespace'); } const { moduleName } = config; - this._firebaseApp = firebaseApp; - this._options = options; + this._app = app; // check if native module exists as all native - // TODO: Get rid of this._native and change to using getNativeModule instead? - this._native = initialiseNativeModule(this, config); - initialiseLogger(this, `${firebaseApp.name}:${moduleName.replace('RNFirebase', '')}`); + initialiseNativeModule(this, config); + initialiseLogger(this, `${app.name}:${moduleName.replace('RNFirebase', '')}`); } /** - * Returns the FirebaseApp instance for current module + * Returns the App instance for current module * @return {*} */ - get app(): FirebaseApp { - return this._firebaseApp; + get app(): App { + return this._app; } } diff --git a/lib/utils/ReferenceBase.js b/lib/utils/ReferenceBase.js index 631d23a1..80e0eede 100644 --- a/lib/utils/ReferenceBase.js +++ b/lib/utils/ReferenceBase.js @@ -1,15 +1,10 @@ /** * @flow */ -import type Database from '../modules/database'; -import type Storage from '../modules/storage'; - export default class ReferenceBase { - _module: Database | Storage; path: string; - constructor(path: string, module: Database | Storage) { - this._module = module; + constructor(path: string) { this.path = path || '/'; } diff --git a/lib/utils/SyncTree.js b/lib/utils/SyncTree.js index c4213365..36c97c21 100644 --- a/lib/utils/SyncTree.js +++ b/lib/utils/SyncTree.js @@ -8,13 +8,15 @@ import DatabaseSnapshot from '../modules/database/snapshot'; import DatabaseReference from '../modules/database/reference'; import { isString, nativeToJSError } from '../utils'; +type Listener = (DatabaseSnapshot) => any; + type Registration = { key: string, path: string, once?: boolean, appName: string, eventType: string, - listener: Function, + listener: Listener, eventRegistrationKey: string, ref: DatabaseReference, } @@ -26,7 +28,7 @@ type Registration = { class SyncTree { _nativeEmitter: NativeEventEmitter; _reverseLookup: { [string]: Registration }; - _tree: { [string]: { [string]: { [string]: Function }}}; + _tree: { [string]: { [string]: { [string]: Listener }}}; constructor() { this._tree = {}; @@ -128,7 +130,7 @@ class SyncTree { * @param registrations * @return {number} */ - removeListenersForRegistrations(registrations: string | string[]) { + removeListenersForRegistrations(registrations: string | string[]): number { if (isString(registrations)) { this.removeRegistration(registrations); SharedEventEmitter.removeAllListeners(registrations); @@ -151,7 +153,7 @@ class SyncTree { * @param registrations * @return {Array} array of registrations removed */ - removeListenerRegistrations(listener, registrations: string[]) { + removeListenerRegistrations(listener: () => any, registrations: string[]) { if (!Array.isArray(registrations)) return []; const removed = []; @@ -181,7 +183,7 @@ class SyncTree { * @param path * @return {Array} */ - getRegistrationsByPath(path: string): Array { + getRegistrationsByPath(path: string): string[] { const out = []; const eventKeys = Object.keys(this._tree[path] || {}); @@ -199,7 +201,7 @@ class SyncTree { * @param eventType * @return {Array} */ - getRegistrationsByPathEvent(path: string, eventType: string): Array { + getRegistrationsByPathEvent(path: string, eventType: string): string[] { if (!this._tree[path]) return []; if (!this._tree[path][eventType]) return []; @@ -214,9 +216,9 @@ class SyncTree { * @param listener * @return {Array} */ - getOneByPathEventListener(path: string, eventType: string, listener: Function): Array { - if (!this._tree[path]) return []; - if (!this._tree[path][eventType]) return []; + getOneByPathEventListener(path: string, eventType: string, listener: Function): ?string { + if (!this._tree[path]) return null; + if (!this._tree[path][eventType]) return null; const registrationsForPathEvent = Object.entries(this._tree[path][eventType]); @@ -236,19 +238,20 @@ class SyncTree { * @param listener * @return {String} */ - addRegistration(parameters: Registration, listener: Function): string { + addRegistration(registration: Registration): string { const { - path, - eventType, eventRegistrationKey, + eventType, + listener, once, - } = parameters; + path, + } = registration; if (!this._tree[path]) this._tree[path] = {}; if (!this._tree[path][eventType]) this._tree[path][eventType] = {}; this._tree[path][eventType][eventRegistrationKey] = listener; - this._reverseLookup[eventRegistrationKey] = Object.assign({ listener }, parameters); + this._reverseLookup[eventRegistrationKey] = registration; if (once) { SharedEventEmitter.once( @@ -305,7 +308,7 @@ class SyncTree { * @private */ _onOnceRemoveRegistration(registration, listener) { - return (...args) => { + return (...args: any[]) => { this.removeRegistration(registration); listener(...args); }; diff --git a/lib/utils/apps.js b/lib/utils/apps.js index fcef8fa1..3be466e7 100644 --- a/lib/utils/apps.js +++ b/lib/utils/apps.js @@ -2,7 +2,7 @@ * @flow */ import { NativeModules } from 'react-native'; -import FirebaseApp from '../modules/core/firebase-app'; +import App from '../modules/core/firebase-app'; import INTERNALS from './internals'; import { isAndroid, isObject, isString } from './'; @@ -17,21 +17,22 @@ import type { const FirebaseCoreModule = NativeModules.RNFirebase; -const APPS: { [string]: FirebaseApp } = {}; -const APP_MODULES: { [FirebaseApp]: { [string]: FirebaseModule }} = {}; +const APPS: { [string]: App } = {}; +const APP_MODULES: { [App]: { [string]: FirebaseModule }} = {}; const DEFAULT_APP_NAME = '[DEFAULT]'; export default { DEFAULT_APP_NAME, - app(name?: string): FirebaseApp { + app(name?: string): App { const _name = name ? name.toUpperCase() : DEFAULT_APP_NAME; const app = APPS[_name]; if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name)); return app; }, - apps(): Array { + apps(): Array { + // $FlowBug: Object.values always returns mixed type: https://github.com/facebook/flow/issues/2221 return Object.values(APPS); }, @@ -42,10 +43,10 @@ export default { * @return {function()} * @private */ - appModule(firebaseApp: FirebaseApp, namespace: FirebaseNamespace, InstanceClass: Class): () => FirebaseModule { + appModule(app: App, namespace: FirebaseNamespace, InstanceClass: Class): () => FirebaseModule { return (): M => { - if (!APP_MODULES[firebaseApp]) { - APP_MODULES[firebaseApp] = {}; + if (!APP_MODULES[app]) { + APP_MODULES[app] = {}; } if (isAndroid && namespace !== 'utils' && !INTERNALS.FLAGS.checkedPlayServices) { @@ -53,11 +54,11 @@ export default { this.utils().checkPlayServicesAvailability(); } - if (!APP_MODULES[firebaseApp][namespace]) { - APP_MODULES[firebaseApp][namespace] = new InstanceClass(firebaseApp, firebaseApp.options); + if (!APP_MODULES[app][namespace]) { + APP_MODULES[app][namespace] = new InstanceClass(app, app.options); } - return APP_MODULES[firebaseApp][namespace]; + return APP_MODULES[app][namespace]; }; }, @@ -79,7 +80,7 @@ export default { * @param name * @return {*} */ - initializeApp(options: FirebaseOptions, name: string): FirebaseApp { + initializeApp(options: FirebaseOptions, name: string): App { if (name && !isString(name)) { throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME); } @@ -124,7 +125,7 @@ export default { throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('storageBucket')); } - APPS[_name] = new FirebaseApp(_name, options); + APPS[_name] = new App(_name, options); return APPS[_name]; }, @@ -137,7 +138,7 @@ export default { const app = FirebaseCoreModule.apps[i]; const options = Object.assign({}, app); delete options.name; - APPS[app.name] = new FirebaseApp(app.name, options, true); + APPS[app.name] = new App(app.name, options, true); } }, @@ -145,22 +146,23 @@ export default { * * @param statics * @param InstanceClass - * @return {function(FirebaseApp=)} + * @return {function(App=)} */ moduleAndStatics(namespace: FirebaseNamespace, statics: S, moduleName: FirebaseModuleName): FirebaseModuleAndStatics { - const getModule = (app?: FirebaseApp): FirebaseModule => { - let firebaseApp = app; + const getModule = (app?: App): FirebaseModule => { + let _app = app; // throw an error if it's not a valid app instance - if (firebaseApp && !(firebaseApp instanceof FirebaseApp)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace)); + if (_app && !(_app instanceof App)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace)); // default to the 'DEFAULT' app if no arg provided - will throw an error // if default app not initialized - else if (!firebaseApp) firebaseApp = this.app(DEFAULT_APP_NAME); + else if (!_app) _app = this.app(DEFAULT_APP_NAME); if (namespace === 'crashlytics') { - return firebaseApp.fabric[namespace](); + return _app.fabric[namespace](); } - const module = firebaseApp[namespace]; + // $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 + const module = _app[namespace]; return module(); }; diff --git a/lib/utils/events.js b/lib/utils/events.js index 659be82b..83152dba 100644 --- a/lib/utils/events.js +++ b/lib/utils/events.js @@ -13,7 +13,7 @@ const NATIVE_SUBSCRIPTIONS: { [string]: boolean } = {}; export const SharedEventEmitter = new EventEmitter(); export const getAppEventName = (module: ModuleBase, eventName: string): string => { - return `${module._firebaseApp._name}-${eventName}`; + return `${module.app.name}-${eventName}`; }; const getNativeEmitter = (moduleName: FirebaseModuleName, module: ModuleBase): NativeEventEmitter => { diff --git a/lib/utils/index.js b/lib/utils/index.js index cea0b5d2..994bab1d 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -371,21 +371,21 @@ export function objectToUniqueId(object: Object): string { * @param optionalCallback * @return {Promise} */ -export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Function) { +export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Function): Promise<*> { if (!isFunction(optionalCallback)) return promise; return promise.then((result) => { // some of firebase internal tests & methods only check/return one arg // see https://github.com/firebase/firebase-js-sdk/blob/master/src/utils/promise.ts#L62 - if (optionalCallback.length === 1) { + if (optionalCallback && optionalCallback.length === 1) { optionalCallback(null); - } else { + } else if (optionalCallback) { optionalCallback(null, result); } return Promise.resolve(result); }).catch((error) => { - optionalCallback(error); + if (optionalCallback) optionalCallback(error); return Promise.reject(error); }); } diff --git a/lib/utils/internals.js b/lib/utils/internals.js index 907c63da..13b7bedc 100644 --- a/lib/utils/internals.js +++ b/lib/utils/internals.js @@ -21,26 +21,32 @@ const GRADLE_DEPS = { }; const PLAY_SERVICES_CODES = { + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 1: { code: 'SERVICE_MISSING', message: 'Google Play services is missing on this device.', }, + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 2: { code: 'SERVICE_VERSION_UPDATE_REQUIRED', message: 'The installed version of Google Play services on this device is out of date.', }, + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 3: { code: 'SERVICE_DISABLED', message: 'The installed version of Google Play services has been disabled on this device.', }, + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 9: { code: 'SERVICE_INVALID', message: 'The version of the Google Play services installed on this device is not authentic.', }, + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 18: { code: 'SERVICE_UPDATING', message: 'Google Play services is currently being updated on this device.', }, + // $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 19: { code: 'SERVICE_MISSING_PERMISSION', message: 'Google Play service doesn\'t have one or more required permissions.', @@ -161,7 +167,7 @@ export default { * @return {string} */ ERROR_NOT_APP(namespace: string) { - return `Invalid FirebaseApp instance passed to firebase.${namespace}(app <--).`; + return `Invalid App instance passed to firebase.${namespace}(app <--).`; }, /** diff --git a/lib/utils/log.js b/lib/utils/log.js index e16eca99..75d21910 100644 --- a/lib/utils/log.js +++ b/lib/utils/log.js @@ -7,6 +7,7 @@ import type ModuleBase from './ModuleBase'; ((base) => { window = base || window; + // $FlowFixMe: Why are we using localStorage at all? if (!window.localStorage) window.localStorage = {}; })(windowOrGlobal);