[types] Get flow type working again; Fix majority of firestore type issues

This commit is contained in:
Chris Bianca 2017-11-17 11:07:52 +00:00
parent 5c43c88f6a
commit 8bd9684644
24 changed files with 2743 additions and 953 deletions

View File

@ -34,7 +34,13 @@
"import/extensions": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": 0,
"react/jsx-filename-extension": 0
"react/jsx-filename-extension": 0,
"no-unused-expressions": 0,
"flowtype/no-unused-expressions": ['error', {
allowShortCircuit: false,
allowTernary: false,
allowTaggedTemplates: false,
}]
},
"globals": {
"__DEV__": true,

View File

@ -91,7 +91,7 @@ unsafe.enable_getters_and_setters=true
esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable
munge_underscores=true
munge_underscores=false
module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
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'
@ -105,4 +105,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-4]\\|1[0-9]\\|[0-9
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
[version]
^0.46.0
^0.56.0

View File

@ -1,3 +1,6 @@
/*
* @flow
*/
import { NativeModules } from 'react-native';
import INTERNALS from './internals';
@ -16,10 +19,31 @@ import Firestore, { statics as FirestoreStatics } from './modules/firestore';
import Links, { statics as LinksStatics } from './modules/links';
import Utils, { statics as UtilsStatics } from './modules/utils';
import type { FirebaseOptions } from './firebase';
const FirebaseCoreModule = NativeModules.RNFirebase;
export default class FirebaseApp {
constructor(name: string, options: Object = {}) {
_extendedProps: { [string] : boolean };
_initialized: boolean;
_name: string;
_namespaces: { [string]: Object };
_nativeInitialized: boolean;
_options: FirebaseOptions;
admob: () => AdMob;
auth: () => Auth;
analytics: () => Analytics;
config: () => RemoteConfig;
crash: () => Crash;
database: () => Database;
firestore: () => Firestore;
links: () => Links;
messaging: () => Messaging;
perf: () => Performance;
storage: () => Storage;
utils: () => Utils;
constructor(name: string, options: FirebaseOptions) {
this._name = name;
this._namespaces = {};
this._options = Object.assign({}, options);
@ -49,7 +73,7 @@ export default class FirebaseApp {
* @param native
* @private
*/
_initializeApp(native = false) {
_initializeApp(native: boolean = false) {
if (native) {
// for apps already initialized natively that
// we have info from RN constants
@ -67,7 +91,7 @@ export default class FirebaseApp {
*
* @return {*}
*/
get name() {
get name(): string {
if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME) {
// ios and android firebase sdk's return different
// app names - so we just return what the web sdk
@ -82,7 +106,7 @@ export default class FirebaseApp {
*
* @return {*}
*/
get options() {
get options(): FirebaseOptions {
return Object.assign({}, this._options);
}
@ -95,14 +119,14 @@ export default class FirebaseApp {
* @param props
*/
extendApp(props: Object) {
if (!isObject(props)) throw new Error(INTERNALS.ERROR_MISSING_ARG('Object', 'extendApp'));
if (!isObject(props)) throw new Error(INTERNALS.STRINGS.ERROR_MISSING_ARG('Object', 'extendApp'));
const keys = Object.keys(props);
for (let i = 0, len = keys.length; i < len; i++) {
const key = keys[i];
if (!this._extendedProps[key] && Object.hasOwnProperty.call(this, key)) {
throw new Error(INTERNALS.ERROR_PROTECTED_PROP(key));
throw new Error(INTERNALS.STRINGS.ERROR_PROTECTED_PROP(key));
}
this[key] = props[key];
@ -131,7 +155,7 @@ export default class FirebaseApp {
*
* @return {*}
*/
onReady(): Promise {
onReady(): Promise<FirebaseApp> {
if (this._initialized) return Promise.resolve(this);
return new Promise((resolve, reject) => {
@ -144,13 +168,12 @@ export default class FirebaseApp {
/**
*
* @param name
* @param statics
* @param InstanceClass
* @return {function()}
* @private
*/
_staticsOrModuleInstance(statics = {}, InstanceClass): Function {
_staticsOrModuleInstance(statics: Object = {}, InstanceClass: Class<*>) {
const getInstance = () => {
const _name = `_${InstanceClass._NAMESPACE}`;

View File

@ -6,7 +6,7 @@ import { NativeModules, NativeEventEmitter } from 'react-native';
import INTERNALS from './internals';
import FirebaseApp from './firebase-app';
import { isObject, isString, isAndroid } from './utils';
import { isObject, isString } from './utils';
// module imports
import AdMob, { statics as AdMobStatics } from './modules/admob';
@ -24,7 +24,31 @@ import Utils, { statics as UtilsStatics } from './modules/utils';
const FirebaseCoreModule = NativeModules.RNFirebase;
export type FirebaseOptions = {
apiKey: string,
appId: string,
databaseURL: string,
messagingSenderId: string,
projectId: string,
storageBucket: string,
}
class FirebaseCore {
_nativeEmitters: { [string]: NativeEventEmitter };
_nativeSubscriptions: { [string]: boolean };
admob: () => AdMob;
auth: () => Auth;
analytics: () => Analytics;
config: () => RemoteConfig;
crash: () => Crash;
database: () => Database;
firestore: () => Firestore;
links: () => Links;
messaging: () => Messaging;
perf: () => Performance;
storage: () => Storage;
utils: () => Utils;
constructor() {
this._nativeEmitters = {};
this._nativeSubscriptions = {};
@ -71,7 +95,7 @@ class FirebaseCore {
* @param name
* @return {*}
*/
initializeApp(options: Object = {}, name: string): FirebaseApp {
initializeApp(options: FirebaseOptions, name: string): FirebaseApp {
if (name && !isString(name)) {
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
}
@ -163,7 +187,7 @@ class FirebaseCore {
* @param nativeEmitter
* @private
*/
_subscribeForDistribution(eventName, nativeEmitter) {
_subscribeForDistribution(eventName: string, nativeEmitter: NativeEventEmitter) {
if (!this._nativeSubscriptions[eventName]) {
nativeEmitter.addListener(eventName, (event) => {
if (event.appName) {
@ -186,7 +210,7 @@ class FirebaseCore {
* @return {function(FirebaseApp=)}
* @private
*/
_appNamespaceOrStatics(statics = {}, InstanceClass): Function {
_appNamespaceOrStatics(statics: Object = {}, InstanceClass: Class<*>): Function {
const namespace = InstanceClass._NAMESPACE;
const getNamespace = (app?: FirebaseApp) => {
@ -215,14 +239,13 @@ class FirebaseCore {
* @return {*}
* @private
*/
_getOrSetNativeEmitter(name, nativeModule) {
_getOrSetNativeEmitter(name: string, nativeModule: Object): NativeEventEmitter {
if (this._nativeEmitters[name]) {
return this._nativeEmitters[name];
}
return this._nativeEmitters[name] = new NativeEventEmitter(nativeModule);
}
}
export default new FirebaseCore();

View File

@ -1,6 +1,10 @@
/**
* @flow
*/
import { Platform, NativeModules } from 'react-native';
import EventEmitter from './utils/emitter/EventEmitter';
import ModuleBase from './utils/ModuleBase';
import SyncTree from './utils/SyncTree';
const DEFAULT_APP_NAME = Platform.OS === 'ios' ? '__FIRAPP_DEFAULT' : '[DEFAULT]';
@ -92,35 +96,35 @@ export default {
/**
* @return {string}
*/
ERROR_MISSING_CB(method) {
ERROR_MISSING_CB(method: string) {
return `Missing required callback for method ${method}().`;
},
/**
* @return {string}
*/
ERROR_MISSING_ARG(type, method) {
ERROR_MISSING_ARG(type: string, method: string) {
return `Missing required argument of type '${type}' for method '${method}()'.`;
},
/**
* @return {string}
*/
ERROR_MISSING_ARG_NAMED(name, type, method) {
ERROR_MISSING_ARG_NAMED(name: string, type: string, method: string) {
return `Missing required argument '${name}' of type '${type}' for method '${method}()'.`;
},
/**
* @return {string}
*/
ERROR_ARG_INVALID_VALUE(name, expected, got) {
ERROR_ARG_INVALID_VALUE(name: string, expected: string, got: string) {
return `Invalid value for argument '${name}' expected value '${expected}' but got '${got}'.`;
},
/**
* @return {string}
*/
ERROR_PROTECTED_PROP(name) {
ERROR_PROTECTED_PROP(name: string) {
return `Property '${name}' is protected and can not be overridden by extendApp.`;
},
@ -129,7 +133,7 @@ export default {
* @param namespace
* @param nativeModule
*/
ERROR_MISSING_MODULE(namespace, nativeModule) {
ERROR_MISSING_MODULE(namespace: string, nativeModule: string) {
const snippet = `firebase.${namespace}()`;
if (Platform.OS === 'ios') {
return `You attempted to use a firebase module that's not installed natively on your iOS project by calling ${snippet}.` +
@ -151,7 +155,7 @@ export default {
/**
* @return {string}
*/
ERROR_APP_NOT_INIT(appName) {
ERROR_APP_NOT_INIT(appName: string) {
return `The [${appName}] firebase app has not been initialized!`;
},
@ -160,35 +164,35 @@ export default {
* @return {string}
* @constructor
*/
ERROR_MISSING_OPT(optName) {
ERROR_MISSING_OPT(optName: string) {
return `Failed to initialize app. FirebaseOptions missing or invalid '${optName}' property.`;
},
/**
* @return {string}
*/
ERROR_NOT_APP(namespace) {
ERROR_NOT_APP(namespace: string) {
return `Invalid FirebaseApp instance passed to firebase.${namespace}(app <--).`;
},
/**
* @return {string}
*/
ERROR_UNSUPPORTED_CLASS_METHOD(className, method) {
ERROR_UNSUPPORTED_CLASS_METHOD(className: string, method: string) {
return `${className}.${method}() is unsupported by the native Firebase SDKs.`;
},
/**
* @return {string}
*/
ERROR_UNSUPPORTED_CLASS_PROPERTY(className, property) {
ERROR_UNSUPPORTED_CLASS_PROPERTY(className: string, property: string) {
return `${className}.${property} is unsupported by the native Firebase SDKs.`;
},
/**
* @return {string}
*/
ERROR_UNSUPPORTED_MODULE_METHOD(module, method) {
ERROR_UNSUPPORTED_MODULE_METHOD(module: Class<ModuleBase>, method: string) {
return `firebase.${module._NAMESPACE}().${method}() is unsupported by the native Firebase SDKs.`;
},
@ -196,7 +200,7 @@ export default {
/**
* @return {string}
*/
ERROR_PLAY_SERVICES(statusCode) {
ERROR_PLAY_SERVICES(statusCode: number) {
const knownError = PLAY_SERVICES_CODES[statusCode];
let start = 'Google Play Services is required to run firebase services on android but a valid installation was not found on this device.';
@ -208,8 +212,8 @@ export default {
return `${start}\r\n\r\n` +
'-------------------------\r\n' +
(knownError ?
`${knownError.code}: ${knownError.message} (code ${statusCode})` :
`A specific play store availability reason reason was not available (unknown code: ${statusCode || null})`
`${knownError.code}: ${knownError.message} (code ${statusCode})` :
`A specific play store availability reason reason was not available (unknown code: ${statusCode})`
) +
'\r\n-------------------------' +
'\r\n\r\n' +
@ -226,9 +230,9 @@ export default {
SyncTree: NativeModules.RNFirebaseDatabase ? new SyncTree(NativeModules.RNFirebaseDatabase) : null,
// internal utils
deleteApp(name: String) {
deleteApp(name: String): Promise<boolean> {
const app = this.APPS[name];
if (!app) return Promise.resolve();
if (!app) return Promise.resolve(true);
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
return app.delete().then(() => {

View File

@ -3,19 +3,19 @@
* CollectionReference representation wrapper
*/
import DocumentReference from './DocumentReference';
import Path from './Path';
import Query from './Query';
import QuerySnapshot from './QuerySnapshot';
import Query, { type Direction, type Operator } from './Query';
import { firestoreAutoId } from '../../utils';
import type { Direction, Operator } from './Query';
import type Firestore from './';
import type Path from './Path';
import type QuerySnapshot from './QuerySnapshot';
/**
/**
* @class CollectionReference
*/
export default class CollectionReference {
_collectionPath: Path;
_firestore: Object;
_firestore: Firestore;
_query: Query;
constructor(firestore: Object, collectionPath: Path) {
@ -71,10 +71,6 @@ export default class CollectionReference {
return this._query.limit(n);
}
offset(n: number): Query {
return this._query.offset(n);
}
onSnapshot(onNext: () => any, onError?: () => any): () => void {
return this._query.onSnapshot(onNext, onError);
}
@ -91,10 +87,6 @@ export default class CollectionReference {
return this._query.startAt(fieldValues);
}
stream(): Stream<DocumentSnapshot> {
return this._query.stream();
}
where(fieldPath: string, opStr: Operator, value: any): Query {
return this._query.where(fieldPath, opStr, value);
}

View File

@ -2,17 +2,19 @@
* @flow
* DocumentChange representation wrapper
*/
import DocumentSnapshot from './DocumentSnapshot';
import DocumentSnapshot, { type DocumentSnapshotNativeData } from './DocumentSnapshot';
import type Firestore from './';
export type DocumentChangeNativeData = {
document: DocumentSnapshot,
document: DocumentSnapshotNativeData,
newIndex: number,
oldIndex: number,
type: string,
}
/**
/**
* @class DocumentChange
*/
export default class DocumentChange {
@ -21,7 +23,7 @@ export default class DocumentChange {
_oldIndex: number;
_type: string;
constructor(firestore: Object, nativeData: DocumentChangeNativeData) {
constructor(firestore: Firestore, nativeData: DocumentChangeNativeData) {
this._document = new DocumentSnapshot(firestore, nativeData.document);
this._newIndex = nativeData.newIndex;
this._oldIndex = nativeData.oldIndex;

View File

@ -3,11 +3,13 @@
* DocumentReference representation wrapper
*/
import CollectionReference from './CollectionReference';
import DocumentSnapshot from './DocumentSnapshot';
import Path from './Path';
import DocumentSnapshot, { type DocumentSnapshotNativeData } from './DocumentSnapshot';
import { buildNativeMap } from './utils/serialize';
import { firestoreAutoId, isFunction, isObject, isString } from '../../utils';
import type Firestore from './';
import type Path from './Path';
export type WriteOptions = {
merge?: boolean,
}
@ -16,24 +18,27 @@ type DocumentListenOptions = {
includeMetadataChanges: boolean,
}
type ObserverOnError = (Object) => void;
type ObserverOnNext = (DocumentSnapshot) => void;
type Observer = {
next: (DocumentSnapshot) => void,
error?: (Object) => void,
error?: ObserverOnError,
next: ObserverOnNext,
}
/**
/**
* @class DocumentReference
*/
export default class DocumentReference {
_documentPath: Path;
_firestore: Object;
_firestore: Firestore;
constructor(firestore: Object, documentPath: Path) {
constructor(firestore: Firestore, documentPath: Path) {
this._documentPath = documentPath;
this._firestore = firestore;
}
get firestore(): Object {
get firestore(): Firestore {
return this._firestore;
}
@ -43,6 +48,9 @@ export default class DocumentReference {
get parent(): CollectionReference {
const parentPath = this._documentPath.parent();
if (!parentPath) {
throw new Error('Invalid document path');
}
return new CollectionReference(this._firestore, parentPath);
}
@ -71,9 +79,9 @@ export default class DocumentReference {
}
onSnapshot(
optionsOrObserverOrOnNext: DocumentListenOptions | Observer | (DocumentSnapshot) => void,
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void,
onError?: (Object) => void
optionsOrObserverOrOnNext: DocumentListenOptions | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: ObserverOnError,
) {
let observer = {};
let docListenOptions = {};
@ -125,8 +133,8 @@ export default class DocumentReference {
}
const listenerId = firestoreAutoId();
const listener = (nativeDocumentSnapshot) => {
const documentSnapshot = new DocumentSnapshot(this, nativeDocumentSnapshot);
const listener = (nativeDocumentSnapshot: DocumentSnapshotNativeData) => {
const documentSnapshot = new DocumentSnapshot(this.firestore, nativeDocumentSnapshot);
observer.next(documentSnapshot);
};
@ -158,7 +166,7 @@ export default class DocumentReference {
.documentSet(this.path, nativeData, writeOptions);
}
update(...args: Object | string[]): Promise<void> {
update(...args: Array<any>): Promise<void> {
let data = {};
if (args.length === 1) {
if (!isObject(args[0])) {
@ -190,7 +198,7 @@ export default class DocumentReference {
* Remove document snapshot listener
* @param listener
*/
_offDocumentSnapshot(listenerId: number, listener: Function) {
_offDocumentSnapshot(listenerId: string, listener: Function) {
this._firestore.log.info('Removing onDocumentSnapshot listener');
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), listener);
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), listener);

View File

@ -4,7 +4,9 @@
*/
import DocumentReference from './DocumentReference';
import Path from './Path';
import { parseNativeMap } from './utils/serialize';
import { parseNativeMap, type TypeMap } from './utils/serialize';
import type Firestore from './';
export type SnapshotMetadata = {
fromCache: boolean,
@ -12,7 +14,7 @@ export type SnapshotMetadata = {
}
export type DocumentSnapshotNativeData = {
data: Object,
data: { [string]: TypeMap },
metadata: SnapshotMetadata,
path: string,
}
@ -21,11 +23,11 @@ export type DocumentSnapshotNativeData = {
* @class DocumentSnapshot
*/
export default class DocumentSnapshot {
_data: Object;
_data: Object | void;
_metadata: SnapshotMetadata;
_ref: DocumentReference;
constructor(firestore: Object, nativeData: DocumentSnapshotNativeData) {
constructor(firestore: Firestore, nativeData: DocumentSnapshotNativeData) {
this._data = parseNativeMap(firestore, nativeData.data);
this._metadata = nativeData.metadata;
this._ref = new DocumentReference(firestore, Path.fromName(nativeData.path));
@ -47,11 +49,11 @@ export default class DocumentSnapshot {
return this._ref;
}
data(): Object {
data(): Object | void {
return this._data;
}
get(fieldPath: string): any {
return this._data[fieldPath];
return this._data ? this._data[fieldPath] : undefined;
}
}

View File

@ -3,7 +3,7 @@
* GeoPoint representation wrapper
*/
/**
/**
* @class GeoPoint
*/
export default class GeoPoint {
@ -19,11 +19,11 @@ export default class GeoPoint {
this._longitude = longitude;
}
get latitude() {
get latitude(): number {
return this._latitude;
}
get longitude() {
get longitude(): number {
return this._longitude;
}
}

View File

@ -3,7 +3,7 @@
* Path representation wrapper
*/
/**
/**
* @class Path
*/
export default class Path {

View File

@ -2,12 +2,14 @@
* @flow
* Query representation wrapper
*/
import DocumentSnapshot from './DocumentSnapshot';
import Path from './Path';
import QuerySnapshot from './QuerySnapshot';
import { buildNativeArray, buildTypeMap } from './utils/serialize';
import { firestoreAutoId, isFunction, isObject } from '../../utils';
import type DocumentSnapshot from './DocumentSnapshot';
import type Firestore from './';
import type Path from './Path';
const DIRECTIONS = {
ASC: 'ASCENDING',
asc: 'ASCENDING',
@ -54,19 +56,25 @@ type Observer = {
error?: (Object) => void,
}
/**
/**
* @class Query
*/
export default class Query {
_fieldFilters: FieldFilter[];
_fieldOrders: FieldOrder[];
_firestore: Object;
_firestore: Firestore;
_iid: number;
_queryOptions: QueryOptions;
_referencePath: Path;
constructor(firestore: Object, path: Path, fieldFilters?: FieldFilter[],
fieldOrders?: FieldOrder[], queryOptions?: QueryOptions) {
constructor(
firestore: Firestore,
path: Path,
fieldFilters?:
FieldFilter[],
fieldOrders?: FieldOrder[],
queryOptions?: QueryOptions,
) {
this._fieldFilters = fieldFilters || [];
this._fieldOrders = fieldOrders || [];
this._firestore = firestore;
@ -78,24 +86,34 @@ export default class Query {
return this._firestore;
}
endAt(...snapshotOrVarArgs: any): Query {
endAt(...snapshotOrVarArgs: any[]): Query {
const options = {
...this._queryOptions,
endAt: this._buildOrderByOption(snapshotOrVarArgs),
};
return new Query(this.firestore, this._referencePath, this._fieldFilters,
this._fieldOrders, options);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
this._fieldOrders,
options,
);
}
endBefore(...snapshotOrVarArgs: any): Query {
endBefore(...snapshotOrVarArgs: any[]): Query {
const options = {
...this._queryOptions,
endBefore: this._buildOrderByOption(snapshotOrVarArgs),
};
return new Query(this.firestore, this._referencePath, this._fieldFilters,
this._fieldOrders, options);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
this._fieldOrders,
options,
);
}
get(): Promise<QuerySnapshot> {
@ -117,14 +135,19 @@ export default class Query {
...this._queryOptions,
limit,
};
return new Query(this.firestore, this._referencePath, this._fieldFilters,
this._fieldOrders, options);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
this._fieldOrders,
options,
);
}
onSnapshot(
optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void,
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void,
onError?: (Object) => void,
optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void,
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void,
onError?: (Object) => void,
) {
let observer = {};
let queryListenOptions = {};
@ -199,12 +222,12 @@ export default class Query {
// Add the native listener
this._firestore._native
.collectionOnSnapshot(
this._referencePath.relativeName,
this._fieldFilters,
this._fieldOrders,
this._queryOptions,
listenerId,
queryListenOptions,
this._referencePath.relativeName,
this._fieldFilters,
this._fieldOrders,
this._queryOptions,
listenerId,
queryListenOptions,
);
// Return an unsubscribe method
@ -226,28 +249,43 @@ export default class Query {
fieldPath,
};
const combinedOrders = this._fieldOrders.concat(newOrder);
return new Query(this.firestore, this._referencePath, this._fieldFilters,
combinedOrders, this._queryOptions);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
combinedOrders,
this._queryOptions,
);
}
startAfter(...snapshotOrVarArgs: any): Query {
startAfter(...snapshotOrVarArgs: any[]): Query {
const options = {
...this._queryOptions,
startAfter: this._buildOrderByOption(snapshotOrVarArgs),
};
return new Query(this.firestore, this._referencePath, this._fieldFilters,
this._fieldOrders, options);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
this._fieldOrders,
options,
);
}
startAt(...snapshotOrVarArgs: any): Query {
startAt(...snapshotOrVarArgs: any[]): Query {
const options = {
...this._queryOptions,
startAt: this._buildOrderByOption(snapshotOrVarArgs),
};
return new Query(this.firestore, this._referencePath, this._fieldFilters,
this._fieldOrders, options);
return new Query(
this.firestore,
this._referencePath,
this._fieldFilters,
this._fieldOrders,
options,
);
}
where(fieldPath: string, opStr: Operator, value: any): Query {
@ -261,8 +299,13 @@ export default class Query {
value: nativeValue,
};
const combinedFilters = this._fieldFilters.concat(newFilter);
return new Query(this.firestore, this._referencePath, combinedFilters,
this._fieldOrders, this._queryOptions);
return new Query(
this.firestore,
this._referencePath,
combinedFilters,
this._fieldOrders,
this._queryOptions,
);
}
/**
@ -290,7 +333,7 @@ export default class Query {
* Remove query snapshot listener
* @param listener
*/
_offCollectionSnapshot(listenerId: number, listener: Function) {
_offCollectionSnapshot(listenerId: string, listener: Function) {
this._firestore.log.info('Removing onQuerySnapshot listener');
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), listener);
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), listener);
@ -300,7 +343,7 @@ export default class Query {
this._fieldFilters,
this._fieldOrders,
this._queryOptions,
listenerId
listenerId,
);
}
}

View File

@ -2,12 +2,11 @@
* @flow
* QuerySnapshot representation wrapper
*/
import DocumentChange from './DocumentChange';
import DocumentSnapshot from './DocumentSnapshot';
import Query from './Query';
import DocumentChange, { type DocumentChangeNativeData } from './DocumentChange';
import DocumentSnapshot, { type DocumentSnapshotNativeData, type SnapshotMetadata } from './DocumentSnapshot';
import type { DocumentChangeNativeData } from './DocumentChange';
import type { DocumentSnapshotNativeData, SnapshotMetadata } from './DocumentSnapshot';
import type Firestore from './';
import type Query from './Query';
type QuerySnapshotNativeData = {
changes: DocumentChangeNativeData[],
@ -15,7 +14,7 @@ type QuerySnapshotNativeData = {
metadata: SnapshotMetadata,
}
/**
/**
* @class QuerySnapshot
*/
export default class QuerySnapshot {
@ -24,7 +23,7 @@ export default class QuerySnapshot {
_metadata: SnapshotMetadata;
_query: Query;
constructor(firestore: Object, query: Query, nativeData: QuerySnapshotNativeData) {
constructor(firestore: Firestore, query: Query, nativeData: QuerySnapshotNativeData) {
this._changes = nativeData.changes.map(change => new DocumentChange(firestore, change));
this._docs = nativeData.documents.map(doc => new DocumentSnapshot(firestore, doc));
this._metadata = nativeData.metadata;
@ -43,14 +42,14 @@ export default class QuerySnapshot {
return this._docs.length === 0;
}
get query(): Query {
return this._query;
}
get metadata(): SnapshotMetadata {
return this._metadata;
}
get query(): Query {
return this._query;
}
get size(): number {
return this._docs.length;
}
@ -59,8 +58,8 @@ export default class QuerySnapshot {
// TODO: Validation
// validate.isFunction('callback', callback);
for (const doc of this._docs) {
this._docs.forEach((doc) => {
callback(doc);
}
});
}
}

View File

@ -2,11 +2,11 @@
* @flow
* WriteBatch representation wrapper
*/
import DocumentReference from './DocumentReference';
import { buildNativeMap } from './utils/serialize';
import { isObject, isString } from '../../utils';
import type { WriteOptions } from './DocumentReference';
import type DocumentReference, { WriteOptions } from './DocumentReference';
import type Firestore from './';
type DocumentWrite = {
data?: Object,
@ -15,14 +15,14 @@ type DocumentWrite = {
type: 'DELETE' | 'SET' | 'UPDATE',
}
/**
/**
* @class WriteBatch
*/
export default class WriteBatch {
_firestore: Object;
_firestore: Firestore;
_writes: DocumentWrite[];
constructor(firestore: Object) {
constructor(firestore: Firestore) {
this._firestore = firestore;
this._writes = [];
}
@ -60,7 +60,7 @@ export default class WriteBatch {
return this;
}
update(docRef: DocumentReference, ...args: Object | string[]): WriteBatch {
update(docRef: DocumentReference, ...args: any[]): WriteBatch {
// TODO: Validation
// validate.isDocumentReference('docRef', docRef);
let data = {};

View File

@ -5,13 +5,16 @@
import ModuleBase from './../../utils/ModuleBase';
import CollectionReference from './CollectionReference';
import DocumentReference from './DocumentReference';
import DocumentSnapshot from './DocumentSnapshot';
import FieldValue from './FieldValue';
import GeoPoint from './GeoPoint';
import Path from './Path';
import WriteBatch from './WriteBatch';
import INTERNALS from './../../internals';
import type DocumentSnapshot from './DocumentSnapshot';
import type FirebaseApp from '../../firebase-app';
import type QuerySnapshot from './QuerySnapshot';
type CollectionSyncEvent = {
appName: string,
querySnapshot?: QuerySnapshot,
@ -37,21 +40,21 @@ export default class Firestore extends ModuleBase {
_referencePath: Path;
constructor(firebaseApp: Object, options: Object = {}) {
constructor(firebaseApp: FirebaseApp, options: Object = {}) {
super(firebaseApp, options, true);
this._referencePath = new Path([]);
this.addListener(
// sub to internal native event - this fans out to
// public event name: onCollectionSnapshot
this._getAppEventName('firestore_collection_sync_event'),
super._getAppEventName('firestore_collection_sync_event'),
this._onCollectionSyncEvent.bind(this),
);
this.addListener(
// sub to internal native event - this fans out to
// public event name: onDocumentSnapshot
this._getAppEventName('firestore_document_sync_event'),
super._getAppEventName('firestore_document_sync_event'),
this._onDocumentSyncEvent.bind(this),
);
}
@ -92,15 +95,15 @@ export default class Firestore extends ModuleBase {
throw new Error('Persistence is enabled by default on the Firestore SDKs');
}
runTransaction(updateFunction): Promise<any> {
runTransaction(): Promise<any> {
throw new Error('firebase.firestore().runTransaction() coming soon');
}
setLogLevel(logLevel: 'debug' | 'error' | 'silent'): void {
setLogLevel(): void {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Firestore, 'setLogLevel'));
}
settings(settings: Object): void {
settings(): void {
throw new Error('firebase.firestore().settings() coming soon');
}
@ -115,9 +118,9 @@ export default class Firestore extends ModuleBase {
*/
_onCollectionSyncEvent(event: CollectionSyncEvent) {
if (event.error) {
this.emit(this._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
this.emit(super._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
} else {
this.emit(this._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
this.emit(super._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
}
}
@ -128,9 +131,9 @@ export default class Firestore extends ModuleBase {
*/
_onDocumentSyncEvent(event: DocumentSyncEvent) {
if (event.error) {
this.emit(this._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
this.emit(super._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
} else {
this.emit(this._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
this.emit(super._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
}
}
}

View File

@ -1,4 +1,6 @@
// @flow
/**
* @flow
*/
import DocumentReference from '../DocumentReference';
import { DELETE_FIELD_VALUE, SERVER_TIMESTAMP_FIELD_VALUE } from '../FieldValue';
@ -6,8 +8,10 @@ import GeoPoint from '../GeoPoint';
import Path from '../Path';
import { typeOf } from '../../../utils';
type TypeMap = {
type: 'array' | 'boolean' | 'geopoint' | 'null' | 'number' | 'object' | 'reference' | 'string',
import type Firestore from '../';
export type TypeMap = {
type: 'array' | 'boolean' | 'date' | 'fieldvalue' | 'geopoint' | 'null' | 'number' | 'object' | 'reference' | 'string',
value: any,
}
@ -17,65 +21,86 @@ type TypeMap = {
* for transmission to the native side
*/
export const buildNativeMap = (data: Object): Object => {
export const buildNativeMap = (data: Object): { [string]: TypeMap } => {
const nativeData = {};
if (data) {
Object.keys(data).forEach((key) => {
nativeData[key] = buildTypeMap(data[key]);
const typeMap = buildTypeMap(data[key]);
if (typeMap) {
nativeData[key] = typeMap;
}
});
}
return nativeData;
};
export const buildNativeArray = (array: Object[]): any[] => {
export const buildNativeArray = (array: Object[]): TypeMap[] => {
const nativeArray = [];
if (array) {
array.forEach((value) => {
nativeArray.push(buildTypeMap(value));
const typeMap = buildTypeMap(value);
if (typeMap) {
nativeArray.push(typeMap);
}
});
}
return nativeArray;
};
export const buildTypeMap = (value: any): any => {
const typeMap = {};
export const buildTypeMap = (value: any): TypeMap | null => {
const type = typeOf(value);
if (value === null || value === undefined) {
typeMap.type = 'null';
typeMap.value = null;
return {
type: 'null',
value: null,
};
} else if (value === DELETE_FIELD_VALUE) {
typeMap.type = 'fieldvalue';
typeMap.value = 'delete';
return {
type: 'fieldvalue',
value: 'delete',
};
} else if (value === SERVER_TIMESTAMP_FIELD_VALUE) {
typeMap.type = 'fieldvalue';
typeMap.value = 'timestamp';
return {
type: 'fieldvalue',
value: 'timestamp',
};
} else if (type === 'boolean' || type === 'number' || type === 'string') {
typeMap.type = type;
typeMap.value = value;
return {
type,
value,
};
} else if (type === 'array') {
typeMap.type = type;
typeMap.value = buildNativeArray(value);
return {
type,
value: buildNativeArray(value),
};
} else if (type === 'object') {
if (value instanceof DocumentReference) {
typeMap.type = 'reference';
typeMap.value = value.path;
return {
type: 'reference',
value: value.path,
};
} else if (value instanceof GeoPoint) {
typeMap.type = 'geopoint';
typeMap.value = {
latitude: value.latitude,
longitude: value.longitude,
return {
type: 'geopoint',
value: {
latitude: value.latitude,
longitude: value.longitude,
},
};
} else if (value instanceof Date) {
typeMap.type = 'date';
typeMap.value = value.getTime();
} else {
typeMap.type = 'object';
typeMap.value = buildNativeMap(value);
return {
type: 'date',
value: value.getTime(),
};
}
} else {
console.warn(`Unknown data type received ${type}`);
return {
type: 'object',
value: buildNativeMap(value),
};
}
return typeMap;
console.warn(`Unknown data type received ${type}`);
return null;
};
/*
@ -83,7 +108,7 @@ export const buildTypeMap = (value: any): any => {
* side and converts to the correct Firestore JS types
*/
export const parseNativeMap = (firestore: Object, nativeData: Object): Object => {
export const parseNativeMap = (firestore: Firestore, nativeData: { [string]: TypeMap }): Object | void => {
let data;
if (nativeData) {
data = {};
@ -94,7 +119,7 @@ export const parseNativeMap = (firestore: Object, nativeData: Object): Object =>
return data;
};
const parseNativeArray = (firestore: Object, nativeArray: Object[]): any[] => {
const parseNativeArray = (firestore: Firestore, nativeArray: TypeMap[]): any[] => {
const array = [];
if (nativeArray) {
nativeArray.forEach((typeMap) => {
@ -104,7 +129,7 @@ const parseNativeArray = (firestore: Object, nativeArray: Object[]): any[] => {
return array;
};
const parseTypeMap = (firestore: Object, typeMap: TypeMap): any => {
const parseTypeMap = (firestore: Firestore, typeMap: TypeMap): any => {
const { type, value } = typeMap;
if (type === 'null') {
return null;

View File

@ -6,9 +6,10 @@ import { NativeModules } from 'react-native';
import Log from '../utils/log';
import INTERNALS from './../internals';
import FirebaseCore from './../firebase';
import FirebaseApp from '../firebase-app';
import { nativeWithApp } from './../utils';
import type FirebaseApp from '../firebase-app';
const logs = {};
// Firebase Native SDKs that support multiple app instances
@ -50,7 +51,7 @@ export default class ModuleBase {
_options: Object;
_appName: string;
_namespace: string;
_firebaseApp: Object;
_firebaseApp: FirebaseApp;
_eventEmitter: Object;
static _NAMESPACE: string;
static _NATIVE_MODULE: string;
@ -61,7 +62,7 @@ export default class ModuleBase {
* @param options
* @param withEventEmitter
*/
constructor(firebaseApp: Object, options: Object, withEventEmitter: boolean = false) {
constructor(firebaseApp: FirebaseApp, options: Object, withEventEmitter: boolean = false) {
this._module = this.constructor._NATIVE_MODULE.replace('RNFirebase', '');
this._firebaseApp = firebaseApp;
this._appName = firebaseApp._name;
@ -73,12 +74,7 @@ export default class ModuleBase {
const nativeModule = NativeModules[this.constructor._NATIVE_MODULE];
if (!nativeModule) {
throw new Error(
INTERNALS.STRINGS.ERROR_MISSING_MODULE(
this.constructor._NAMESPACE,
this.constructor._NATIVE_MODULE,
),
);
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(this.constructor._NAMESPACE, this.constructor._NATIVE_MODULE));
}
// used by the modules that extend ModuleBase
@ -100,7 +96,7 @@ export default class ModuleBase {
* @param moduleName
* @private
*/
_setupEventEmitter(nativeModule, moduleName) {
_setupEventEmitter(nativeModule: Object, moduleName: string) {
this._eventEmitter = FirebaseCore._getOrSetNativeEmitter(`${this._appName}-${this._module}`, nativeModule);
const events = NATIVE_MODULE_EVENTS[moduleName];
@ -117,7 +113,7 @@ export default class ModuleBase {
* @return {string}
* @private
*/
_getAppEventName(eventName) {
_getAppEventName(eventName: string) {
return `${this._appName}-${eventName}`;
}
@ -131,9 +127,7 @@ export default class ModuleBase {
get log(): Log {
if (logs[this._namespace]) return logs[this._namespace];
return logs[this._namespace] = Log.createLogger(
`🔥 ${this._namespace.toUpperCase()}`,
);
return logs[this._namespace] = Log.createLogger(`🔥 ${this._namespace.toUpperCase()}`);
}
/*

View File

@ -1,8 +1,16 @@
/**
* @flow
*/
import Log from './log';
import type Database from '../modules/database';
import type Storage from '../modules/storage';
export default class ReferenceBase {
constructor(path: string, module) {
_module: Database | Storage;
path: string;
constructor(path: string, module: Database | Storage) {
this._module = module;
this.path = path || '/';
}
@ -17,7 +25,7 @@ export default class ReferenceBase {
return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1);
}
get log() {
get log(): Log {
return this._module.log;
}
}

View File

@ -1,3 +1,6 @@
/**
* @flow
*/
import { NativeEventEmitter } from 'react-native';
import INTERNALS from './../internals';
@ -6,13 +9,13 @@ import DatabaseReference from './../modules/database/reference';
import { isString, nativeToJSError } from './../utils';
type Registration = {
key: String,
path: String,
once?: Boolean,
appName: String,
eventType: String,
key: string,
path: string,
once?: boolean,
appName: string,
eventType: string,
listener: Function,
eventRegistrationKey: String,
eventRegistrationKey: string,
ref: DatabaseReference,
}
@ -21,7 +24,12 @@ type Registration = {
* subscriptions and keep the listeners in sync in js vs native.
*/
export default class SyncTree {
constructor(databaseNative) {
_databaseNative: Object;
_nativeEmitter: NativeEventEmitter;
_reverseLookup: { [string]: Registration };
_tree: { [string]: { [string]: Array }};
constructor(databaseNative: Object) {
this._tree = {};
this._reverseLookup = {};
this._databaseNative = databaseNative;
@ -110,7 +118,7 @@ export default class SyncTree {
* @param registration
* @return {null}
*/
getRegistration(registration): Registration | null {
getRegistration(registration: string): Registration | null {
return this._reverseLookup[registration] ? Object.assign({}, this._reverseLookup[registration]) : null;
}
@ -120,7 +128,7 @@ export default class SyncTree {
* @param registrations
* @return {number}
*/
removeListenersForRegistrations(registrations) {
removeListenersForRegistrations(registrations: string | string[]) {
if (isString(registrations)) {
this.removeRegistration(registrations);
INTERNALS.SharedEventEmitter.removeAllListeners(registrations);
@ -143,7 +151,7 @@ export default class SyncTree {
* @param registrations
* @return {Array} array of registrations removed
*/
removeListenerRegistrations(listener, registrations) {
removeListenerRegistrations(listener, registrations: string[]) {
if (!Array.isArray(registrations)) return [];
const removed = [];
@ -173,7 +181,7 @@ export default class SyncTree {
* @param path
* @return {Array}
*/
getRegistrationsByPath(path): Array {
getRegistrationsByPath(path: string): Array {
const out = [];
const eventKeys = Object.keys(this._tree[path] || {});
@ -191,7 +199,7 @@ export default class SyncTree {
* @param eventType
* @return {Array}
*/
getRegistrationsByPathEvent(path, eventType): Array {
getRegistrationsByPathEvent(path: string, eventType: string): Array {
if (!this._tree[path]) return [];
if (!this._tree[path][eventType]) return [];
@ -228,8 +236,13 @@ export default class SyncTree {
* @param listener
* @return {String}
*/
addRegistration(parameters: Registration, listener): String {
const { path, eventType, eventRegistrationKey, once } = parameters;
addRegistration(parameters: Registration, listener: Function): string {
const {
path,
eventType,
eventRegistrationKey,
once,
} = parameters;
if (!this._tree[path]) this._tree[path] = {};
if (!this._tree[path][eventType]) this._tree[path][eventType] = {};
@ -256,7 +269,7 @@ export default class SyncTree {
* @param registration
* @return {boolean}
*/
removeRegistration(registration: String): Boolean {
removeRegistration(registration: string): boolean {
if (!this._reverseLookup[registration]) return false;
const { path, eventType, once } = this._reverseLookup[registration];
@ -298,4 +311,3 @@ export default class SyncTree {
};
}
}

View File

@ -6,18 +6,10 @@ import { Platform } from 'react-native';
// modeled after base64 web-safe chars, but ordered by ASCII
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
const AUTO_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const hasOwnProperty = Object.hasOwnProperty;
const { hasOwnProperty } = Object;
// const DEFAULT_CHUNK_SIZE = 50;
// Source: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical
const REGEXP_FIELD_NAME = new RegExp(
`^(?:\\.?((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))$`
);
const REGEXP_FIELD_PATH = new RegExp(
`^((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+)(?:\\.((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))*$`
);
/**
* Deep get a value from an object.
* @website https://github.com/Salakar/deeps
@ -26,9 +18,7 @@ const REGEXP_FIELD_PATH = new RegExp(
* @param joiner
* @returns {*}
*/
export function deepGet(object: Object,
path: string,
joiner?: string = '/'): any {
export function deepGet(object: Object, path: string, joiner?: string = '/'): any {
const keys = path.split(joiner);
let i = 0;
@ -52,9 +42,7 @@ export function deepGet(object: Object,
* @param joiner
* @returns {*}
*/
export function deepExists(object: Object,
path: string,
joiner?: string = '/'): boolean {
export function deepExists(object: Object, path: string, joiner?: string = '/'): boolean {
const keys = path.split(joiner);
let i = 0;
@ -98,7 +86,7 @@ export function areObjectKeysContainedInOther(obj1 : Object, obj2: Object): bool
* @param arr2
* @returns {boolean}
*/
export function isArrayContainedInOther(arr1: Array, arr2: Array): boolean {
export function isArrayContainedInOther(arr1: Array<*>, arr2: Array<*>): boolean {
if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
return false;
}
@ -112,8 +100,8 @@ export function isArrayContainedInOther(arr1: Array, arr2: Array): boolean {
* @param item
* @returns {boolean}
*/
export function isObject(item: any): boolean {
return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
export function isObject(item: mixed): boolean %checks {
return item ? (typeof item === 'object' && !Array.isArray(item) && item !== null) : false;
}
/**
@ -121,8 +109,8 @@ export function isObject(item: any): boolean {
* @param item
* @returns {*|boolean}
*/
export function isFunction(item?: any): boolean {
return Boolean(item && typeof item === 'function');
export function isFunction(item?: mixed): boolean %checks {
return item ? typeof item === 'function' : false;
}
/**
@ -130,20 +118,10 @@ export function isFunction(item?: any): boolean {
* @param value
* @return {boolean}
*/
export function isString(value: any): boolean {
export function isString(value: mixed): boolean %checks {
return typeof value === 'string';
}
/**
* Firestore field name/path validator.
* @param field
* @param paths
* @return {boolean}
*/
export function isValidFirestoreField(field, paths) {
return (paths ? REGEXP_FIELD_PATH : REGEXP_FIELD_NAME).test(field);
}
// platform checks
export const isIOS = Platform.OS === 'ios';
export const isAndroid = Platform.OS === 'android';
@ -167,7 +145,7 @@ export function tryJSONParse(string: string | null): any {
* @param data
* @returns {*}
*/
export function tryJSONStringify(data: any): string | null {
export function tryJSONStringify(data: mixed): string | null {
try {
return JSON.stringify(data);
} catch (jsonError) {

3070
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -75,13 +75,13 @@
"babel-preset-react-native": "^1.9.0",
"debug": "^2.2.0",
"enzyme": "^2.4.1",
"eslint": "^3.8.1",
"eslint-config-airbnb": "^12.0.0",
"eslint-plugin-flowtype": "^2.20.0",
"eslint-plugin-import": "^2.0.1",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.4.1",
"flow-bin": "^0.55.0",
"eslint": "^4.11.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-flowtype": "^2.39.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.4.0",
"flow-bin": "^0.56.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-native": "^0.48.0",

View File

@ -208,7 +208,7 @@ SPEC CHECKSUMS:
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
RNFirebase: a76befd482c5e84df7f69893358abda498ee9f76
RNFirebase: 1b8adf4dfe740fbc4a69a147715c2edfd041eb92
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45

View File

@ -1033,7 +1033,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
6AE1012F46FF8A4D1D818A12 /* [CP] Copy Pods Resources */ = {