Skip to content

Commit 6c00cc8

Browse files
authored
Merge pull request #312 from ParsePlatform/flow_typing
Flow typing
2 parents c96e8dd + c4193ca commit 6c00cc8

15 files changed

+171
-96
lines changed

src/.flowconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
[ignore]
2-
.*\/node_modules\/
2+
.*/node_modules/.*
33

44
[include]
5+
../package.json
56

67
[libs]
78
interfaces/

src/CoreManager.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
*/
1111

1212
import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations';
13+
import type ParseFile from './ParseFile';
1314
import type { FileSource } from './ParseFile';
1415
import type { Op } from './ParseOp';
1516
import type ParseObject from './ParseObject';
1617
import type ParsePromise from './ParsePromise';
1718
import type { QueryJSON } from './ParseQuery';
18-
import type { ParseUser, AuthData } from './ParseUser';
19+
import type ParseUser from './ParseUser';
20+
import type { AuthData } from './ParseUser';
1921
import type { PushData } from './Push';
2022

2123
type RequestOptions = {
@@ -41,9 +43,9 @@ type InstallationController = {
4143
currentInstallationId: () => ParsePromise;
4244
};
4345
type ObjectController = {
44-
fetch: (object: ParseObject, forceFetch: boolean, options: RequestOptions) => ParsePromise;
45-
save: (object: ParseObject, options: RequestOptions) => ParsePromise;
46-
destroy: (object: ParseObject, options: RequestOptions) => ParsePromise;
46+
fetch: (object: ParseObject | Array<ParseObject>, forceFetch: boolean, options: RequestOptions) => ParsePromise;
47+
save: (object: ParseObject | Array<ParseObject | ParseFile>, options: RequestOptions) => ParsePromise;
48+
destroy: (object: ParseObject | Array<ParseObject>, options: RequestOptions) => ParsePromise;
4749
};
4850
type ObjectStateController = {
4951
getState: (obj: any) => ?State;
@@ -62,6 +64,7 @@ type ObjectStateController = {
6264
commitServerChanges: (obj: any, changes: AttributeMap) => void;
6365
enqueueTask: (obj: any, task: () => ParsePromise) => ParsePromise;
6466
clearAllState: () => void;
67+
duplicateState: (source: any, dest: any) => void;
6568
};
6669
type PushController = {
6770
send: (data: PushData, options: RequestOptions) => ParsePromise;
@@ -107,21 +110,39 @@ type UserController = {
107110
updateUserOnDisk: (user: ParseUser) => ParsePromise;
108111
upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => ParsePromise;
109112
linkWith: (user: ParseUser, authData: AuthData) => ParsePromise;
113+
removeUserFromDisk: () => ParsePromise;
110114
};
111115
type HooksController = {
112116
get: (type: string, functionName?: string, triggerName?: string) => ParsePromise;
113117
create: (hook: mixed) => ParsePromise;
114118
delete: (hook: mixed) => ParsePromise;
115119
update: (hook: mixed) => ParsePromise;
116120
send: (method: string, path: string, body?: mixed) => ParsePromise;
117-
}
121+
};
122+
123+
type Config = {
124+
AnalyticsController?: AnalyticsController,
125+
CloudController?: CloudController,
126+
ConfigController?: ConfigController,
127+
FileController?: FileController,
128+
InstallationController?: InstallationController,
129+
ObjectController?: ObjectController,
130+
ObjectStateController?: ObjectStateController,
131+
PushController?: PushController,
132+
QueryController?: QueryController,
133+
RESTController?: RESTController,
134+
SessionController?: SessionController,
135+
StorageController?: StorageController,
136+
UserController?: UserController,
137+
HooksController?: HooksController,
138+
};
118139

119-
var config: { [key: string]: mixed } = {
140+
var config: Config & { [key: string]: mixed } = {
120141
// Defaults
121142
IS_NODE: (typeof process !== 'undefined' &&
122143
!!process.versions &&
123144
!!process.versions.node &&
124-
!process.version.electron),
145+
!process.versions.electron),
125146
REQUEST_ATTEMPT_LIMIT: 5,
126147
SERVER_URL: 'https://api.parse.com/1',
127148
LIVEQUERY_SERVER_URL: null,

src/ObjectStateMutations.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,18 @@ export function mergeFirstPendingState(pendingOps: Array<OpsMap>) {
8787
}
8888
}
8989

90-
export function estimateAttribute(serverData: AttributeMap, pendingOps: Array<OpsMap>, className: string, id: string, attr: string): mixed {
90+
export function estimateAttribute(serverData: AttributeMap, pendingOps: Array<OpsMap>, className: string, id: ?string, attr: string): mixed {
9191
let value = serverData[attr];
9292
for (let i = 0; i < pendingOps.length; i++) {
9393
if (pendingOps[i][attr]) {
9494
if (pendingOps[i][attr] instanceof RelationOp) {
95-
value = pendingOps[i][attr].applyTo(
96-
value,
97-
{ className: className, id: id },
98-
attr
99-
);
95+
if (id) {
96+
value = pendingOps[i][attr].applyTo(
97+
value,
98+
{ className: className, id: id },
99+
attr
100+
);
101+
}
100102
} else {
101103
value = pendingOps[i][attr].applyTo(value);
102104
}
@@ -105,7 +107,7 @@ export function estimateAttribute(serverData: AttributeMap, pendingOps: Array<Op
105107
return value;
106108
}
107109

108-
export function estimateAttributes(serverData: AttributeMap, pendingOps: Array<OpsMap>, className: string, id: string): AttributeMap {
110+
export function estimateAttributes(serverData: AttributeMap, pendingOps: Array<OpsMap>, className: string, id: ?string): AttributeMap {
109111
let data = {};
110112
let attr;
111113
for (attr in serverData) {
@@ -114,11 +116,13 @@ export function estimateAttributes(serverData: AttributeMap, pendingOps: Array<O
114116
for (let i = 0; i < pendingOps.length; i++) {
115117
for (attr in pendingOps[i]) {
116118
if (pendingOps[i][attr] instanceof RelationOp) {
117-
data[attr] = pendingOps[i][attr].applyTo(
118-
data[attr],
119-
{ className: className, id: id },
120-
attr
121-
);
119+
if (id) {
120+
data[attr] = pendingOps[i][attr].applyTo(
121+
data[attr],
122+
{ className: className, id: id },
123+
attr
124+
);
125+
}
122126
} else {
123127
data[attr] = pendingOps[i][attr].applyTo(data[attr]);
124128
}

src/ParseACL.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import ParseRole from './ParseRole';
1313
import ParseUser from './ParseUser';
1414

15+
type PermissionsMap = { [permission: string]: boolean };
16+
type ByIdMap = { [userId: string]: PermissionsMap };
17+
1518
var PUBLIC_KEY = '*';
1619

1720
/**
@@ -29,9 +32,9 @@ var PUBLIC_KEY = '*';
2932
* of your application.</p>
3033
*/
3134
export default class ParseACL {
32-
permissionsById: { [userId: string]: { [permission: string]: boolean } };
35+
permissionsById: ByIdMap;
3336

34-
constructor(arg1: mixed) {
37+
constructor(arg1: ParseUser | ByIdMap) {
3538
this.permissionsById = {};
3639
if (arg1 && typeof arg1 === 'object') {
3740
if (arg1 instanceof ParseUser) {
@@ -74,7 +77,7 @@ export default class ParseACL {
7477
* @method toJSON
7578
* @return {Object}
7679
*/
77-
toJSON(): { [key: string]: any } {
80+
toJSON(): ByIdMap {
7881
var permissions = {};
7982
for (var p in this.permissionsById) {
8083
permissions[p] = this.permissionsById[p];
@@ -88,7 +91,7 @@ export default class ParseACL {
8891
* @param other The other object to compare to
8992
* @return {Boolean}
9093
*/
91-
equals(other: mixed): boolean {
94+
equals(other: ParseACL): boolean {
9295
if (!(other instanceof ParseACL)) {
9396
return false;
9497
}
@@ -150,6 +153,9 @@ export default class ParseACL {
150153
): boolean {
151154
if (userId instanceof ParseUser) {
152155
userId = userId.id;
156+
if (!userId) {
157+
throw new Error('Cannot get access for a ParseUser without an ID');
158+
}
153159
} else if (userId instanceof ParseRole) {
154160
userId = 'role:' + userId.getName();
155161
}

src/ParseFile.js

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
import CoreManager from './CoreManager';
1313
import ParsePromise from './ParsePromise';
1414

15-
type FileData = Array<number> | { base64: string } | File;
15+
type Base64 = { base64: string };
16+
type FileData = Array<number> | Base64 | File;
1617
export type FileSource = {
1718
format: 'file';
1819
file: File;
@@ -86,38 +87,41 @@ export default class ParseFile {
8687

8788
this._name = name;
8889

89-
if (Array.isArray(data)) {
90-
this._source = {
91-
format: 'base64',
92-
base64: ParseFile.encodeBase64(data),
93-
type: specifiedType
94-
};
95-
} else if (typeof File !== 'undefined' && data instanceof File) {
96-
this._source = {
97-
format: 'file',
98-
file: data,
99-
type: specifiedType
100-
};
101-
} else if (data && data.hasOwnProperty('base64')) {
102-
var commaIndex = data.base64.indexOf(',');
103-
104-
if (commaIndex !== -1) {
105-
var matches = dataUriRegexp.exec(data.base64.slice(0, commaIndex + 1));
106-
// if data URI with type and charset, there will be 4 matches.
90+
if (data !== undefined) {
91+
if (Array.isArray(data)) {
10792
this._source = {
10893
format: 'base64',
109-
base64: data.base64.slice(commaIndex + 1),
110-
type: matches[1]
94+
base64: ParseFile.encodeBase64(data),
95+
type: specifiedType
11196
};
112-
} else {
97+
} else if (typeof File !== 'undefined' && data instanceof File) {
11398
this._source = {
114-
format: 'base64',
115-
base64: data.base64,
99+
format: 'file',
100+
file: data,
116101
type: specifiedType
117102
};
103+
} else if (data && typeof data.base64 !== 'undefined') {
104+
const base64 = data.base64;
105+
var commaIndex = base64.indexOf(',');
106+
107+
if (commaIndex !== -1) {
108+
var matches = dataUriRegexp.exec(base64.slice(0, commaIndex + 1));
109+
// if data URI with type and charset, there will be 4 matches.
110+
this._source = {
111+
format: 'base64',
112+
base64: base64.slice(commaIndex + 1),
113+
type: matches[1]
114+
};
115+
} else {
116+
this._source = {
117+
format: 'base64',
118+
base64: base64,
119+
type: specifiedType
120+
};
121+
}
122+
} else {
123+
throw new TypeError('Cannot create a Parse.File with that data.');
118124
}
119-
} else if (typeof data !== 'undefined') {
120-
throw new TypeError('Cannot create a Parse.File with that data.');
121125
}
122126
}
123127

src/ParseObject.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export default class ParseObject {
188188
/**
189189
* Returns a unique identifier used to pull data from the State Controller.
190190
*/
191-
_getStateIdentifier(): mixed {
191+
_getStateIdentifier(): ParseObject | {id: string, className: string} {
192192
if (singleInstance) {
193193
let id = this.id;
194194
if (!id) {
@@ -354,7 +354,7 @@ export default class ParseObject {
354354
}
355355
}
356356

357-
_handleSaveResponse(response, status: number) {
357+
_handleSaveResponse(response: AttributeMap, status: number) {
358358
var changes = {};
359359
var attr;
360360
var stateController = CoreManager.getObjectStateController();
@@ -410,7 +410,7 @@ export default class ParseObject {
410410
* @method toJSON
411411
* @return {Object}
412412
*/
413-
toJSON(seen: Array<any>): AttributeMap {
413+
toJSON(seen: Array<any> | void): AttributeMap {
414414
var seenEntry = this.id ? this.className + ':' + this.id : this;
415415
var seen = seen || [seenEntry];
416416
var json = {};
@@ -646,7 +646,9 @@ export default class ParseObject {
646646
) {
647647
newOps[k] = opFromJSON(changes[k]);
648648
} else if (k === 'objectId' || k === 'id') {
649-
this.id = changes[k];
649+
if (typeof changes[k] === 'string') {
650+
this.id = changes[k];
651+
}
650652
} else if (
651653
k === 'ACL' &&
652654
typeof changes[k] === 'object' &&
@@ -823,7 +825,9 @@ export default class ParseObject {
823825
}
824826

825827
let stateController = CoreManager.getObjectStateController();
826-
stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier());
828+
if (stateController) {
829+
stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier());
830+
}
827831
return clone;
828832
}
829833

@@ -1066,9 +1070,9 @@ export default class ParseObject {
10661070
options = options || {};
10671071
var saveOptions = {};
10681072
if (options.hasOwnProperty('useMasterKey')) {
1069-
saveOptions.useMasterKey = options.useMasterKey;
1073+
saveOptions.useMasterKey = !!options.useMasterKey;
10701074
}
1071-
if (options.hasOwnProperty('sessionToken')) {
1075+
if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') {
10721076
saveOptions.sessionToken = options.sessionToken;
10731077
}
10741078

@@ -1446,7 +1450,7 @@ export default class ParseObject {
14461450
* this method.
14471451
* @return {Class} A new subclass of Parse.Object.
14481452
*/
1449-
static extend(className: string, protoProps, classProps) {
1453+
static extend(className: any, protoProps: any, classProps: any) {
14501454
if (typeof className !== 'string') {
14511455
if (className && typeof className.className === 'string') {
14521456
return ParseObject.extend(className.className, className, protoProps);

src/ParseOp.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ export class RelationOp extends Op {
311311
relationsToAdd: Array<string>;
312312
relationsToRemove: Array<string>;
313313

314-
constructor(adds: Array<ParseObject>, removes: Array<ParseObject>) {
314+
constructor(
315+
adds: Array<ParseObject | string>,
316+
removes: Array<ParseObject | string>
317+
) {
315318
super();
316319
this._targetClassName = null;
317320

@@ -345,8 +348,11 @@ export class RelationOp extends Op {
345348
return obj.id;
346349
}
347350

348-
applyTo(value: mixed, object: { className: string, id: string }, key: string): ?ParseRelation {
351+
applyTo(value: mixed, object?: { className: string, id: ?string }, key?: string): ?ParseRelation {
349352
if (!value) {
353+
if (!object || !key) {
354+
throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key');
355+
}
350356
var parent = new ParseObject(object.className);
351357
if (object.id && object.id.indexOf('local') === 0) {
352358
parent._localId = object.id;

0 commit comments

Comments
 (0)