diff --git a/package-lock.json b/package-lock.json
index 9e4808191..29df00318 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,6 +35,7 @@
"@semantic-release/github": "8.0.7",
"@semantic-release/npm": "9.0.2",
"@semantic-release/release-notes-generator": "10.0.3",
+ "@types/facebook-js-sdk": "3.3.9",
"babel-jest": "29.5.0",
"babel-plugin-inline-package-json": "2.0.0",
"babel-plugin-minify-dead-code-elimination": "0.5.2",
@@ -5049,6 +5050,12 @@
"@types/range-parser": "*"
}
},
+ "node_modules/@types/facebook-js-sdk": {
+ "version": "3.3.9",
+ "resolved": "https://registry.npmjs.org/@types/facebook-js-sdk/-/facebook-js-sdk-3.3.9.tgz",
+ "integrity": "sha512-uJiJ+ljEPzC7jHGXl8YT7gRUh0fGzzJYrdwyrjgwSqFvrcCwlWMu/nLLcJeIRoFA81uVBwZBOKQIkjXFknXPsA==",
+ "dev": true
+ },
"node_modules/@types/graceful-fs": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
@@ -31544,6 +31551,12 @@
"@types/range-parser": "*"
}
},
+ "@types/facebook-js-sdk": {
+ "version": "3.3.9",
+ "resolved": "https://registry.npmjs.org/@types/facebook-js-sdk/-/facebook-js-sdk-3.3.9.tgz",
+ "integrity": "sha512-uJiJ+ljEPzC7jHGXl8YT7gRUh0fGzzJYrdwyrjgwSqFvrcCwlWMu/nLLcJeIRoFA81uVBwZBOKQIkjXFknXPsA==",
+ "dev": true
+ },
"@types/graceful-fs": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
diff --git a/package.json b/package.json
index 22a92f152..12654f893 100644
--- a/package.json
+++ b/package.json
@@ -55,6 +55,7 @@
"@semantic-release/github": "8.0.7",
"@semantic-release/npm": "9.0.2",
"@semantic-release/release-notes-generator": "10.0.3",
+ "@types/facebook-js-sdk": "3.3.9",
"babel-jest": "29.5.0",
"babel-plugin-inline-package-json": "2.0.0",
"babel-plugin-minify-dead-code-elimination": "0.5.2",
diff --git a/src/Analytics.js b/src/Analytics.ts
similarity index 95%
rename from src/Analytics.js
rename to src/Analytics.ts
index 32f4cf82f..3a6b367c3 100644
--- a/src/Analytics.js
+++ b/src/Analytics.ts
@@ -44,7 +44,7 @@ import CoreManager from './CoreManager';
* @returns {Promise} A promise that is resolved when the round-trip
* to the server completes.
*/
-export function track(name: string, dimensions: { [key: string]: string }): Promise {
+export function track(name: string, dimensions: { [key: string]: string }): Promise
Parse.Error.
- * @param {string} message A detailed description of the error.
- */
- constructor(code, message) {
- super(message);
- this.code = code;
- let customMessage = message;
- CoreManager.get('PARSE_ERRORS').forEach((error) => {
- if (error.code === code && error.code) {
- customMessage = error.message;
- }
- });
- Object.defineProperty(this, 'message', {
- enumerable: true,
- value: customMessage,
- });
- }
-
- toString() {
- return 'ParseError: ' + this.code + ' ' + this.message;
- }
-}
-
-/**
- * Error code indicating some error other than those enumerated here.
- *
- * @property {number} OTHER_CAUSE
- * @static
- */
-ParseError.OTHER_CAUSE = -1;
-
-/**
- * Error code indicating that something has gone wrong with the server.
- *
- * @property {number} INTERNAL_SERVER_ERROR
- * @static
- */
-ParseError.INTERNAL_SERVER_ERROR = 1;
-
-/**
- * Error code indicating the connection to the Parse servers failed.
- *
- * @property {number} CONNECTION_FAILED
- * @static
- */
-ParseError.CONNECTION_FAILED = 100;
-
-/**
- * Error code indicating the specified object doesn't exist.
- *
- * @property {number} OBJECT_NOT_FOUND
- * @static
- */
-ParseError.OBJECT_NOT_FOUND = 101;
-
-/**
- * Error code indicating you tried to query with a datatype that doesn't
- * support it, like exact matching an array or object.
- *
- * @property {number} INVALID_QUERY
- * @static
- */
-ParseError.INVALID_QUERY = 102;
-
-/**
- * Error code indicating a missing or invalid classname. Classnames are
- * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the
- * only valid characters.
- *
- * @property {number} INVALID_CLASS_NAME
- * @static
- */
-ParseError.INVALID_CLASS_NAME = 103;
-
-/**
- * Error code indicating an unspecified object id.
- *
- * @property {number} MISSING_OBJECT_ID
- * @static
- */
-ParseError.MISSING_OBJECT_ID = 104;
-
-/**
- * Error code indicating an invalid key name. Keys are case-sensitive. They
- * must start with a letter, and a-zA-Z0-9_ are the only valid characters.
- *
- * @property {number} INVALID_KEY_NAME
- * @static
- */
-ParseError.INVALID_KEY_NAME = 105;
-
-/**
- * Error code indicating a malformed pointer. You should not see this unless
- * you have been mucking about changing internal Parse code.
- *
- * @property {number} INVALID_POINTER
- * @static
- */
-ParseError.INVALID_POINTER = 106;
-
-/**
- * Error code indicating that badly formed JSON was received upstream. This
- * either indicates you have done something unusual with modifying how
- * things encode to JSON, or the network is failing badly.
- *
- * @property {number} INVALID_JSON
- * @static
- */
-ParseError.INVALID_JSON = 107;
-
-/**
- * Error code indicating that the feature you tried to access is only
- * available internally for testing purposes.
- *
- * @property {number} COMMAND_UNAVAILABLE
- * @static
- */
-ParseError.COMMAND_UNAVAILABLE = 108;
-
-/**
- * You must call Parse.initialize before using the Parse library.
- *
- * @property {number} NOT_INITIALIZED
- * @static
- */
-ParseError.NOT_INITIALIZED = 109;
-
-/**
- * Error code indicating that a field was set to an inconsistent type.
- *
- * @property {number} INCORRECT_TYPE
- * @static
- */
-ParseError.INCORRECT_TYPE = 111;
-
-/**
- * Error code indicating an invalid channel name. A channel name is either
- * an empty string (the broadcast channel) or contains only a-zA-Z0-9_
- * characters and starts with a letter.
- *
- * @property {number} INVALID_CHANNEL_NAME
- * @static
- */
-ParseError.INVALID_CHANNEL_NAME = 112;
-
-/**
- * Error code indicating that push is misconfigured.
- *
- * @property {number} PUSH_MISCONFIGURED
- * @static
- */
-ParseError.PUSH_MISCONFIGURED = 115;
-
-/**
- * Error code indicating that the object is too large.
- *
- * @property {number} OBJECT_TOO_LARGE
- * @static
- */
-ParseError.OBJECT_TOO_LARGE = 116;
-
-/**
- * Error code indicating that the operation isn't allowed for clients.
- *
- * @property {number} OPERATION_FORBIDDEN
- * @static
- */
-ParseError.OPERATION_FORBIDDEN = 119;
-
-/**
- * Error code indicating the result was not found in the cache.
- *
- * @property {number} CACHE_MISS
- * @static
- */
-ParseError.CACHE_MISS = 120;
-
-/**
- * Error code indicating that an invalid key was used in a nested
- * JSONObject.
- *
- * @property {number} INVALID_NESTED_KEY
- * @static
- */
-ParseError.INVALID_NESTED_KEY = 121;
-
-/**
- * Error code indicating that an invalid filename was used for ParseFile.
- * A valid file name contains only a-zA-Z0-9_. characters and is between 1
- * and 128 characters.
- *
- * @property {number} INVALID_FILE_NAME
- * @static
- */
-ParseError.INVALID_FILE_NAME = 122;
-
-/**
- * Error code indicating an invalid ACL was provided.
- *
- * @property {number} INVALID_ACL
- * @static
- */
-ParseError.INVALID_ACL = 123;
-
-/**
- * Error code indicating that the request timed out on the server. Typically
- * this indicates that the request is too expensive to run.
- *
- * @property {number} TIMEOUT
- * @static
- */
-ParseError.TIMEOUT = 124;
-
-/**
- * Error code indicating that the email address was invalid.
- *
- * @property {number} INVALID_EMAIL_ADDRESS
- * @static
- */
-ParseError.INVALID_EMAIL_ADDRESS = 125;
-
-/**
- * Error code indicating a missing content type.
- *
- * @property {number} MISSING_CONTENT_TYPE
- * @static
- */
-ParseError.MISSING_CONTENT_TYPE = 126;
-
-/**
- * Error code indicating a missing content length.
- *
- * @property {number} MISSING_CONTENT_LENGTH
- * @static
- */
-ParseError.MISSING_CONTENT_LENGTH = 127;
-
-/**
- * Error code indicating an invalid content length.
- *
- * @property {number} INVALID_CONTENT_LENGTH
- * @static
- */
-ParseError.INVALID_CONTENT_LENGTH = 128;
-
-/**
- * Error code indicating a file that was too large.
- *
- * @property {number} FILE_TOO_LARGE
- * @static
- */
-ParseError.FILE_TOO_LARGE = 129;
-
-/**
- * Error code indicating an error saving a file.
- *
- * @property {number} FILE_SAVE_ERROR
- * @static
- */
-ParseError.FILE_SAVE_ERROR = 130;
-
-/**
- * Error code indicating that a unique field was given a value that is
- * already taken.
- *
- * @property {number} DUPLICATE_VALUE
- * @static
- */
-ParseError.DUPLICATE_VALUE = 137;
-
-/**
- * Error code indicating that a role's name is invalid.
- *
- * @property {number} INVALID_ROLE_NAME
- * @static
- */
-ParseError.INVALID_ROLE_NAME = 139;
-
-/**
- * Error code indicating that an application quota was exceeded. Upgrade to
- * resolve.
- *
- * @property {number} EXCEEDED_QUOTA
- * @static
- */
-ParseError.EXCEEDED_QUOTA = 140;
-
-/**
- * Error code indicating that a Cloud Code script failed.
- *
- * @property {number} SCRIPT_FAILED
- * @static
- */
-ParseError.SCRIPT_FAILED = 141;
-
-/**
- * Error code indicating that a Cloud Code validation failed.
- *
- * @property {number} VALIDATION_ERROR
- * @static
- */
-ParseError.VALIDATION_ERROR = 142;
-
-/**
- * Error code indicating that invalid image data was provided.
- *
- * @property {number} INVALID_IMAGE_DATA
- * @static
- */
-ParseError.INVALID_IMAGE_DATA = 143;
-
-/**
- * Error code indicating an unsaved file.
- *
- * @property {number} UNSAVED_FILE_ERROR
- * @static
- */
-ParseError.UNSAVED_FILE_ERROR = 151;
-
-/**
- * Error code indicating an invalid push time.
- *
- * @property {number} INVALID_PUSH_TIME_ERROR
- * @static
- */
-ParseError.INVALID_PUSH_TIME_ERROR = 152;
-
-/**
- * Error code indicating an error deleting a file.
- *
- * @property {number} FILE_DELETE_ERROR
- * @static
- */
-ParseError.FILE_DELETE_ERROR = 153;
-
-/**
- * Error code indicating an error deleting an unnamed file.
- *
- * @property {number} FILE_DELETE_UNNAMED_ERROR
- * @static
- */
-ParseError.FILE_DELETE_UNNAMED_ERROR = 161;
-
-/**
- * Error code indicating that the application has exceeded its request
- * limit.
- *
- * @property {number} REQUEST_LIMIT_EXCEEDED
- * @static
- */
-ParseError.REQUEST_LIMIT_EXCEEDED = 155;
-
-/**
- * Error code indicating that the request was a duplicate and has been discarded due to
- * idempotency rules.
- *
- * @property {number} DUPLICATE_REQUEST
- * @static
- */
-ParseError.DUPLICATE_REQUEST = 159;
-
-/**
- * Error code indicating an invalid event name.
- *
- * @property {number} INVALID_EVENT_NAME
- * @static
- */
-ParseError.INVALID_EVENT_NAME = 160;
-
-/**
- * Error code indicating that a field had an invalid value.
- *
- * @property {number} INVALID_VALUE
- * @static
- */
-ParseError.INVALID_VALUE = 162;
-
-/**
- * Error code indicating that the username is missing or empty.
- *
- * @property {number} USERNAME_MISSING
- * @static
- */
-ParseError.USERNAME_MISSING = 200;
-
-/**
- * Error code indicating that the password is missing or empty.
- *
- * @property {number} PASSWORD_MISSING
- * @static
- */
-ParseError.PASSWORD_MISSING = 201;
-
-/**
- * Error code indicating that the username has already been taken.
- *
- * @property {number} USERNAME_TAKEN
- * @static
- */
-ParseError.USERNAME_TAKEN = 202;
-
-/**
- * Error code indicating that the email has already been taken.
- *
- * @property {number} EMAIL_TAKEN
- * @static
- */
-ParseError.EMAIL_TAKEN = 203;
-
-/**
- * Error code indicating that the email is missing, but must be specified.
- *
- * @property {number} EMAIL_MISSING
- * @static
- */
-ParseError.EMAIL_MISSING = 204;
-
-/**
- * Error code indicating that a user with the specified email was not found.
- *
- * @property {number} EMAIL_NOT_FOUND
- * @static
- */
-ParseError.EMAIL_NOT_FOUND = 205;
-
-/**
- * Error code indicating that a user object without a valid session could
- * not be altered.
- *
- * @property {number} SESSION_MISSING
- * @static
- */
-ParseError.SESSION_MISSING = 206;
-
-/**
- * Error code indicating that a user can only be created through signup.
- *
- * @property {number} MUST_CREATE_USER_THROUGH_SIGNUP
- * @static
- */
-ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207;
-
-/**
- * Error code indicating that an an account being linked is already linked
- * to another user.
- *
- * @property {number} ACCOUNT_ALREADY_LINKED
- * @static
- */
-ParseError.ACCOUNT_ALREADY_LINKED = 208;
-
-/**
- * Error code indicating that the current session token is invalid.
- *
- * @property {number} INVALID_SESSION_TOKEN
- * @static
- */
-ParseError.INVALID_SESSION_TOKEN = 209;
-
-/**
- * Error code indicating an error enabling or verifying MFA
- *
- * @property {number} MFA_ERROR
- * @static
- */
-ParseError.MFA_ERROR = 210;
-
-/**
- * Error code indicating that a valid MFA token must be provided
- *
- * @property {number} MFA_TOKEN_REQUIRED
- * @static
- */
-ParseError.MFA_TOKEN_REQUIRED = 211;
-
-/**
- * Error code indicating that a user cannot be linked to an account because
- * that account's id could not be found.
- *
- * @property {number} LINKED_ID_MISSING
- * @static
- */
-ParseError.LINKED_ID_MISSING = 250;
-
-/**
- * Error code indicating that a user with a linked (e.g. Facebook) account
- * has an invalid session.
- *
- * @property {number} INVALID_LINKED_SESSION
- * @static
- */
-ParseError.INVALID_LINKED_SESSION = 251;
-
-/**
- * Error code indicating that a service being linked (e.g. Facebook or
- * Twitter) is unsupported.
- *
- * @property {number} UNSUPPORTED_SERVICE
- * @static
- */
-ParseError.UNSUPPORTED_SERVICE = 252;
-
-/**
- * Error code indicating an invalid operation occured on schema
- *
- * @property {number} INVALID_SCHEMA_OPERATION
- * @static
- */
-ParseError.INVALID_SCHEMA_OPERATION = 255;
-
-/**
- * Error code indicating that there were multiple errors. Aggregate errors
- * have an "errors" property, which is an array of error objects with more
- * detail about each error that occurred.
- *
- * @property {number} AGGREGATE_ERROR
- * @static
- */
-ParseError.AGGREGATE_ERROR = 600;
-
-/**
- * Error code indicating the client was unable to read an input file.
- *
- * @property {number} FILE_READ_ERROR
- * @static
- */
-ParseError.FILE_READ_ERROR = 601;
-
-/**
- * Error code indicating a real error code is unavailable because
- * we had to use an XDomainRequest object to allow CORS requests in
- * Internet Explorer, which strips the body from HTTP responses that have
- * a non-2XX status code.
- *
- * @property {number} X_DOMAIN_REQUEST
- * @static
- */
-ParseError.X_DOMAIN_REQUEST = 602;
-
-export default ParseError;
diff --git a/src/ParseError.ts b/src/ParseError.ts
new file mode 100644
index 000000000..1f8e4e0b1
--- /dev/null
+++ b/src/ParseError.ts
@@ -0,0 +1,559 @@
+import CoreManager from './CoreManager';
+import type ParseObject from './ParseObject';
+
+/**
+ * Constructs a new Parse.Error object with the given code and message.
+ *
+ * Parse.CoreManager.set('PARSE_ERRORS', [{ code, message }]) can be use to override error messages.
+ *
+ * @alias Parse.Error
+ */
+class ParseError extends Error {
+ code: number;
+ message: string;
+ /** In case an error is associated with an object */
+ object?: ParseObject;
+ /** In case of aggregate errors, this is populated */
+ errors?: Error[];
+ /**
+ * @param {number} code An error code constant from Parse.Error.
+ * @param {string} message A detailed description of the error.
+ */
+ constructor(code: number, message?: string) {
+ super(message);
+ this.code = code;
+ let customMessage = message;
+ CoreManager.get('PARSE_ERRORS').forEach((error: { code: number, message: string }) => {
+ if (error.code === code && error.code) {
+ customMessage = error.message;
+ }
+ });
+ Object.defineProperty(this, 'message', {
+ enumerable: true,
+ value: customMessage,
+ });
+ }
+
+ toString() {
+ return 'ParseError: ' + this.code + ' ' + this.message;
+ }
+
+
+ /**
+ * Error code indicating some error other than those enumerated here.
+ *
+ * @property {number} OTHER_CAUSE
+ * @static
+ */
+ static OTHER_CAUSE = -1;
+
+ /**
+ * Error code indicating that something has gone wrong with the server.
+ *
+ * @property {number} INTERNAL_SERVER_ERROR
+ * @static
+ */
+ static INTERNAL_SERVER_ERROR = 1;
+
+ /**
+ * Error code indicating the connection to the Parse servers failed.
+ *
+ * @property {number} CONNECTION_FAILED
+ * @static
+ */
+ static CONNECTION_FAILED = 100;
+
+ /**
+ * Error code indicating the specified object doesn't exist.
+ *
+ * @property {number} OBJECT_NOT_FOUND
+ * @static
+ */
+ static OBJECT_NOT_FOUND = 101;
+
+ /**
+ * Error code indicating you tried to query with a datatype that doesn't
+ * support it, like exact matching an array or object.
+ *
+ * @property {number} INVALID_QUERY
+ * @static
+ */
+ static INVALID_QUERY = 102;
+
+ /**
+ * Error code indicating a missing or invalid classname. Classnames are
+ * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the
+ * only valid characters.
+ *
+ * @property {number} INVALID_CLASS_NAME
+ * @static
+ */
+ static INVALID_CLASS_NAME = 103;
+
+ /**
+ * Error code indicating an unspecified object id.
+ *
+ * @property {number} MISSING_OBJECT_ID
+ * @static
+ */
+ static MISSING_OBJECT_ID = 104;
+
+ /**
+ * Error code indicating an invalid key name. Keys are case-sensitive. They
+ * must start with a letter, and a-zA-Z0-9_ are the only valid characters.
+ *
+ * @property {number} INVALID_KEY_NAME
+ * @static
+ */
+ static INVALID_KEY_NAME = 105;
+
+ /**
+ * Error code indicating a malformed pointer. You should not see this unless
+ * you have been mucking about changing internal Parse code.
+ *
+ * @property {number} INVALID_POINTER
+ * @static
+ */
+ static INVALID_POINTER = 106;
+
+ /**
+ * Error code indicating that badly formed JSON was received upstream. This
+ * either indicates you have done something unusual with modifying how
+ * things encode to JSON, or the network is failing badly.
+ *
+ * @property {number} INVALID_JSON
+ * @static
+ */
+ static INVALID_JSON = 107;
+
+ /**
+ * Error code indicating that the feature you tried to access is only
+ * available internally for testing purposes.
+ *
+ * @property {number} COMMAND_UNAVAILABLE
+ * @static
+ */
+ static COMMAND_UNAVAILABLE = 108;
+
+ /**
+ * You must call Parse.initialize before using the Parse library.
+ *
+ * @property {number} NOT_INITIALIZED
+ * @static
+ */
+ static NOT_INITIALIZED = 109;
+
+ /**
+ * Error code indicating that a field was set to an inconsistent type.
+ *
+ * @property {number} INCORRECT_TYPE
+ * @static
+ */
+ static INCORRECT_TYPE = 111;
+
+ /**
+ * Error code indicating an invalid channel name. A channel name is either
+ * an empty string (the broadcast channel) or contains only a-zA-Z0-9_
+ * characters and starts with a letter.
+ *
+ * @property {number} INVALID_CHANNEL_NAME
+ * @static
+ */
+ static INVALID_CHANNEL_NAME = 112;
+
+ /**
+ * Error code indicating that push is misconfigured.
+ *
+ * @property {number} PUSH_MISCONFIGURED
+ * @static
+ */
+ static PUSH_MISCONFIGURED = 115;
+
+ /**
+ * Error code indicating that the object is too large.
+ *
+ * @property {number} OBJECT_TOO_LARGE
+ * @static
+ */
+ static OBJECT_TOO_LARGE = 116;
+
+ /**
+ * Error code indicating that the operation isn't allowed for clients.
+ *
+ * @property {number} OPERATION_FORBIDDEN
+ * @static
+ */
+ static OPERATION_FORBIDDEN = 119;
+
+ /**
+ * Error code indicating the result was not found in the cache.
+ *
+ * @property {number} CACHE_MISS
+ * @static
+ */
+ static CACHE_MISS = 120;
+
+ /**
+ * Error code indicating that an invalid key was used in a nested
+ * JSONObject.
+ *
+ * @property {number} INVALID_NESTED_KEY
+ * @static
+ */
+ static INVALID_NESTED_KEY = 121;
+
+ /**
+ * Error code indicating that an invalid filename was used for ParseFile.
+ * A valid file name contains only a-zA-Z0-9_. characters and is between 1
+ * and 128 characters.
+ *
+ * @property {number} INVALID_FILE_NAME
+ * @static
+ */
+ static INVALID_FILE_NAME = 122;
+
+ /**
+ * Error code indicating an invalid ACL was provided.
+ *
+ * @property {number} INVALID_ACL
+ * @static
+ */
+ static INVALID_ACL = 123;
+
+ /**
+ * Error code indicating that the request timed out on the server. Typically
+ * this indicates that the request is too expensive to run.
+ *
+ * @property {number} TIMEOUT
+ * @static
+ */
+ static TIMEOUT = 124;
+
+ /**
+ * Error code indicating that the email address was invalid.
+ *
+ * @property {number} INVALID_EMAIL_ADDRESS
+ * @static
+ */
+ static INVALID_EMAIL_ADDRESS = 125;
+
+ /**
+ * Error code indicating a missing content type.
+ *
+ * @property {number} MISSING_CONTENT_TYPE
+ * @static
+ */
+ static MISSING_CONTENT_TYPE = 126;
+
+ /**
+ * Error code indicating a missing content length.
+ *
+ * @property {number} MISSING_CONTENT_LENGTH
+ * @static
+ */
+ static MISSING_CONTENT_LENGTH = 127;
+
+ /**
+ * Error code indicating an invalid content length.
+ *
+ * @property {number} INVALID_CONTENT_LENGTH
+ * @static
+ */
+ static INVALID_CONTENT_LENGTH = 128;
+
+ /**
+ * Error code indicating a file that was too large.
+ *
+ * @property {number} FILE_TOO_LARGE
+ * @static
+ */
+ static FILE_TOO_LARGE = 129;
+
+ /**
+ * Error code indicating an error saving a file.
+ *
+ * @property {number} FILE_SAVE_ERROR
+ * @static
+ */
+ static FILE_SAVE_ERROR = 130;
+
+ /**
+ * Error code indicating that a unique field was given a value that is
+ * already taken.
+ *
+ * @property {number} DUPLICATE_VALUE
+ * @static
+ */
+ static DUPLICATE_VALUE = 137;
+
+ /**
+ * Error code indicating that a role's name is invalid.
+ *
+ * @property {number} INVALID_ROLE_NAME
+ * @static
+ */
+ static INVALID_ROLE_NAME = 139;
+
+ /**
+ * Error code indicating that an application quota was exceeded. Upgrade to
+ * resolve.
+ *
+ * @property {number} EXCEEDED_QUOTA
+ * @static
+ */
+ static EXCEEDED_QUOTA = 140;
+
+ /**
+ * Error code indicating that a Cloud Code script failed.
+ *
+ * @property {number} SCRIPT_FAILED
+ * @static
+ */
+ static SCRIPT_FAILED = 141;
+
+ /**
+ * Error code indicating that a Cloud Code validation failed.
+ *
+ * @property {number} VALIDATION_ERROR
+ * @static
+ */
+ static VALIDATION_ERROR = 142;
+
+ /**
+ * Error code indicating that invalid image data was provided.
+ *
+ * @property {number} INVALID_IMAGE_DATA
+ * @static
+ */
+ static INVALID_IMAGE_DATA = 143;
+
+ /**
+ * Error code indicating an unsaved file.
+ *
+ * @property {number} UNSAVED_FILE_ERROR
+ * @static
+ */
+ static UNSAVED_FILE_ERROR = 151;
+
+ /**
+ * Error code indicating an invalid push time.
+ *
+ * @property {number} INVALID_PUSH_TIME_ERROR
+ * @static
+ */
+ static INVALID_PUSH_TIME_ERROR = 152;
+
+ /**
+ * Error code indicating an error deleting a file.
+ *
+ * @property {number} FILE_DELETE_ERROR
+ * @static
+ */
+ static FILE_DELETE_ERROR = 153;
+
+ /**
+ * Error code indicating an error deleting an unnamed file.
+ *
+ * @property {number} FILE_DELETE_UNNAMED_ERROR
+ * @static
+ */
+ static FILE_DELETE_UNNAMED_ERROR = 161;
+
+ /**
+ * Error code indicating that the application has exceeded its request
+ * limit.
+ *
+ * @property {number} REQUEST_LIMIT_EXCEEDED
+ * @static
+ */
+ static REQUEST_LIMIT_EXCEEDED = 155;
+
+ /**
+ * Error code indicating that the request was a duplicate and has been discarded due to
+ * idempotency rules.
+ *
+ * @property {number} DUPLICATE_REQUEST
+ * @static
+ */
+ static DUPLICATE_REQUEST = 159;
+
+ /**
+ * Error code indicating an invalid event name.
+ *
+ * @property {number} INVALID_EVENT_NAME
+ * @static
+ */
+ static INVALID_EVENT_NAME = 160;
+
+ /**
+ * Error code indicating that a field had an invalid value.
+ *
+ * @property {number} INVALID_VALUE
+ * @static
+ */
+ static INVALID_VALUE = 162;
+
+ /**
+ * Error code indicating that the username is missing or empty.
+ *
+ * @property {number} USERNAME_MISSING
+ * @static
+ */
+ static USERNAME_MISSING = 200;
+
+ /**
+ * Error code indicating that the password is missing or empty.
+ *
+ * @property {number} PASSWORD_MISSING
+ * @static
+ */
+ static PASSWORD_MISSING = 201;
+
+ /**
+ * Error code indicating that the username has already been taken.
+ *
+ * @property {number} USERNAME_TAKEN
+ * @static
+ */
+ static USERNAME_TAKEN = 202;
+
+ /**
+ * Error code indicating that the email has already been taken.
+ *
+ * @property {number} EMAIL_TAKEN
+ * @static
+ */
+ static EMAIL_TAKEN = 203;
+
+ /**
+ * Error code indicating that the email is missing, but must be specified.
+ *
+ * @property {number} EMAIL_MISSING
+ * @static
+ */
+ static EMAIL_MISSING = 204;
+
+ /**
+ * Error code indicating that a user with the specified email was not found.
+ *
+ * @property {number} EMAIL_NOT_FOUND
+ * @static
+ */
+ static EMAIL_NOT_FOUND = 205;
+
+ /**
+ * Error code indicating that a user object without a valid session could
+ * not be altered.
+ *
+ * @property {number} SESSION_MISSING
+ * @static
+ */
+ static SESSION_MISSING = 206;
+
+ /**
+ * Error code indicating that a user can only be created through signup.
+ *
+ * @property {number} MUST_CREATE_USER_THROUGH_SIGNUP
+ * @static
+ */
+ static MUST_CREATE_USER_THROUGH_SIGNUP = 207;
+
+ /**
+ * Error code indicating that an an account being linked is already linked
+ * to another user.
+ *
+ * @property {number} ACCOUNT_ALREADY_LINKED
+ * @static
+ */
+ static ACCOUNT_ALREADY_LINKED = 208;
+
+ /**
+ * Error code indicating that the current session token is invalid.
+ *
+ * @property {number} INVALID_SESSION_TOKEN
+ * @static
+ */
+ static INVALID_SESSION_TOKEN = 209;
+
+ /**
+ * Error code indicating an error enabling or verifying MFA
+ *
+ * @property {number} MFA_ERROR
+ * @static
+ */
+ static MFA_ERROR = 210;
+
+ /**
+ * Error code indicating that a valid MFA token must be provided
+ *
+ * @property {number} MFA_TOKEN_REQUIRED
+ * @static
+ */
+ static MFA_TOKEN_REQUIRED = 211;
+
+ /**
+ * Error code indicating that a user cannot be linked to an account because
+ * that account's id could not be found.
+ *
+ * @property {number} LINKED_ID_MISSING
+ * @static
+ */
+ static LINKED_ID_MISSING = 250;
+
+ /**
+ * Error code indicating that a user with a linked (e.g. Facebook) account
+ * has an invalid session.
+ *
+ * @property {number} INVALID_LINKED_SESSION
+ * @static
+ */
+ static INVALID_LINKED_SESSION = 251;
+
+ /**
+ * Error code indicating that a service being linked (e.g. Facebook or
+ * Twitter) is unsupported.
+ *
+ * @property {number} UNSUPPORTED_SERVICE
+ * @static
+ */
+ static UNSUPPORTED_SERVICE = 252;
+
+ /**
+ * Error code indicating an invalid operation occured on schema
+ *
+ * @property {number} INVALID_SCHEMA_OPERATION
+ * @static
+ */
+ static INVALID_SCHEMA_OPERATION = 255;
+
+ /**
+ * Error code indicating that there were multiple errors. Aggregate errors
+ * have an "errors" property, which is an array of error objects with more
+ * detail about each error that occurred.
+ *
+ * @property {number} AGGREGATE_ERROR
+ * @static
+ */
+ static AGGREGATE_ERROR = 600;
+
+ /**
+ * Error code indicating the client was unable to read an input file.
+ *
+ * @property {number} FILE_READ_ERROR
+ * @static
+ */
+ static FILE_READ_ERROR = 601;
+
+ /**
+ * Error code indicating a real error code is unavailable because
+ * we had to use an XDomainRequest object to allow CORS requests in
+ * Internet Explorer, which strips the body from HTTP responses that have
+ * a non-2XX status code.
+ *
+ * @property {number} X_DOMAIN_REQUEST
+ * @static
+ */
+ static X_DOMAIN_REQUEST = 602;
+}
+
+export default ParseError;
\ No newline at end of file
diff --git a/src/ParseFile.js b/src/ParseFile.ts
similarity index 86%
rename from src/ParseFile.js
rename to src/ParseFile.ts
index 1d7ff6945..cd397c8af 100644
--- a/src/ParseFile.js
+++ b/src/ParseFile.ts
@@ -4,10 +4,9 @@
/* global XMLHttpRequest, Blob */
import CoreManager from './CoreManager';
import type { FullOptions } from './RESTController';
+import ParseError from './ParseError'
-const ParseError = require('./ParseError').default;
-
-let XHR = null;
+let XHR: typeof XMLHttpRequest = null as any;
if (typeof XMLHttpRequest !== 'undefined') {
XHR = XMLHttpRequest;
}
@@ -20,22 +19,22 @@ type Uri = { uri: string };
type FileData = Array
* @returns {Promise} Promise that is resolved when the delete finishes.
*/
- destroy(options?: FullOptions = {}) {
+ destroy(options: FullOptions = {}) {
if (!this._name) {
throw new ParseError(ParseError.FILE_DELETE_UNNAMED_ERROR, 'Cannot delete an unnamed file.');
}
const destroyOptions = { useMasterKey: true };
if (options.hasOwnProperty('useMasterKey')) {
- destroyOptions.useMasterKey = options.useMasterKey;
+ destroyOptions.useMasterKey = options.useMasterKey!;
}
const controller = CoreManager.getFileController();
return controller.deleteFile(this._name, destroyOptions).then(() => {
- this._data = null;
+ this._data = undefined;
this._requestTask = null;
return this;
});
}
- toJSON(): { name: ?string, url: ?string } {
+ toJSON(): { __type: 'File', name?: string, url?: string } {
return {
__type: 'File',
name: this._name,
@@ -337,7 +342,7 @@ class ParseFile {
};
}
- equals(other: mixed): boolean {
+ equals(other: any): boolean {
if (this === other) {
return true;
}
@@ -409,8 +414,8 @@ class ParseFile {
return file;
}
- static encodeBase64(bytes: Array): string {
- const chunks = [];
+ static encodeBase64(bytes: Array | Uint8Array): string {
+ const chunks: string[] = [];
chunks.length = Math.ceil(bytes.length / 3);
for (let i = 0; i < chunks.length; i++) {
const b1 = bytes[i * 3];
@@ -437,10 +442,10 @@ const DefaultController = {
if (source.format !== 'file') {
throw new Error('saveFile can only be used with File-type sources.');
}
- const base64Data = await new Promise((res, rej) => {
+ const base64Data = await new Promise((res, rej) => {
// eslint-disable-next-line no-undef
const reader = new FileReader();
- reader.onload = () => res(reader.result);
+ reader.onload = () => res(reader.result as string);
reader.onerror = error => rej(error);
reader.readAsDataURL(source.file);
});
@@ -451,14 +456,14 @@ const DefaultController = {
// use the entire string instead
const data = second ? second : first;
const newSource = {
- format: 'base64',
+ format: 'base64' as const,
base64: data,
- type: source.type || (source.file ? source.file.type : null),
+ type: source.type || (source.file ? source.file.type : undefined),
};
return await DefaultController.saveBase64(name, newSource, options);
},
- saveBase64: function (name: string, source: FileSource, options?: FullOptions) {
+ saveBase64: function (name: string, source: FileSource, options: FileSaveOptions = {}) {
if (source.format !== 'base64') {
throw new Error('saveBase64 can only be used with Base64-type sources.');
}
@@ -469,16 +474,17 @@ const DefaultController = {
tags: { ...options.tags },
},
};
- delete options.metadata;
- delete options.tags;
+ const restOptions = { ...options };
+ delete restOptions.metadata;
+ delete restOptions.tags;
if (source.type) {
data._ContentType = source.type;
}
const path = 'files/' + name;
- return CoreManager.getRESTController().request('POST', path, data, options);
+ return CoreManager.getRESTController().request('POST', path, data, restOptions);
},
- download: function (uri, options) {
+ download: function (uri: string, options: any) {
if (XHR) {
return this.downloadAjax(uri, options);
} else if (process.env.PARSE_BUILD === 'node') {
@@ -506,7 +512,7 @@ const DefaultController = {
}
},
- downloadAjax: function (uri, options) {
+ downloadAjax: function (uri: string, options: any) {
return new Promise((resolve, reject) => {
const xhr = new XHR();
xhr.open('GET', uri, true);
@@ -536,7 +542,7 @@ const DefaultController = {
const headers = {
'X-Parse-Application-ID': CoreManager.get('APPLICATION_ID'),
};
- if (options.useMasterKey) {
+ if (options?.useMasterKey) {
headers['X-Parse-Master-Key'] = CoreManager.get('MASTER_KEY');
}
let url = CoreManager.get('SERVER_URL');
@@ -568,4 +574,3 @@ const DefaultController = {
CoreManager.setFileController(DefaultController);
export default ParseFile;
-exports.b64Digit = b64Digit;
diff --git a/src/ParseGeoPoint.js b/src/ParseGeoPoint.ts
similarity index 94%
rename from src/ParseGeoPoint.js
rename to src/ParseGeoPoint.ts
index 3af089e98..95cdd8e95 100644
--- a/src/ParseGeoPoint.js
+++ b/src/ParseGeoPoint.ts
@@ -102,7 +102,7 @@ class ParseGeoPoint {
};
}
- equals(other: mixed): boolean {
+ equals(other: any): boolean {
return (
other instanceof ParseGeoPoint &&
this.latitude === other.latitude &&
@@ -186,6 +186,9 @@ class ParseGeoPoint {
* @static
* @returns {Parse.GeoPoint} User's current location
*/
+ // TODO: Typescript; How does this thing work?
+ // Seems we're using the power of Javascript by returning a value from a synchronous callback, so the value ends up correct somehow in tests?
+ // Should this be `async` instead for safety? Since it's a callback pattern
static current() {
return navigator.geolocation.getCurrentPosition(location => {
return new ParseGeoPoint(location.coords.latitude, location.coords.longitude);
diff --git a/src/ParseHooks.js b/src/ParseHooks.ts
similarity index 54%
rename from src/ParseHooks.js
rename to src/ParseHooks.ts
index 8a5982687..c6edf219c 100644
--- a/src/ParseHooks.js
+++ b/src/ParseHooks.ts
@@ -10,52 +10,54 @@ export function getTriggers() {
return CoreManager.getHooksController().get('triggers');
}
-export function getFunction(name) {
+export function getFunction(name: string) {
return CoreManager.getHooksController().get('functions', name);
}
-export function getTrigger(className, triggerName) {
+export function getTrigger(className: string, triggerName: string) {
return CoreManager.getHooksController().get('triggers', className, triggerName);
}
-export function createFunction(functionName, url) {
+export function createFunction(functionName: string, url: string) {
return create({ functionName: functionName, url: url });
}
-export function createTrigger(className, triggerName, url) {
+export function createTrigger(className: string, triggerName: string, url: string) {
return create({ className: className, triggerName: triggerName, url: url });
}
-export function create(hook) {
+export function create(hook: HookDeclaration) {
return CoreManager.getHooksController().create(hook);
}
-export function updateFunction(functionName, url) {
+export function updateFunction(functionName: string, url: string) {
return update({ functionName: functionName, url: url });
}
-export function updateTrigger(className, triggerName, url) {
+export function updateTrigger(className: string, triggerName: string, url: string) {
return update({ className: className, triggerName: triggerName, url: url });
}
-export function update(hook) {
+export function update(hook: HookDeclaration) {
return CoreManager.getHooksController().update(hook);
}
-export function removeFunction(functionName) {
+export function removeFunction(functionName: string) {
return remove({ functionName: functionName });
}
-export function removeTrigger(className, triggerName) {
+export function removeTrigger(className: string, triggerName: string) {
return remove({ className: className, triggerName: triggerName });
}
-export function remove(hook) {
+export function remove(hook: HookDeleteArg) {
return CoreManager.getHooksController().remove(hook);
}
+export type HookDeclaration = { functionName: string, url: string } | { className: string, triggerName: string, url: string };
+export type HookDeleteArg = { functionName: string } | { className: string, triggerName: string };
const DefaultController = {
- get(type, functionName, triggerName) {
+ get(type: string, functionName?: string, triggerName?: string) {
let url = '/hooks/' + type;
if (functionName) {
url += '/' + functionName;
@@ -66,11 +68,11 @@ const DefaultController = {
return this.sendRequest('GET', url);
},
- create(hook) {
- let url;
- if (hook.functionName && hook.url) {
+ create(hook: HookDeclaration) {
+ let url: string;
+ if ('functionName' in hook && hook.url) {
url = '/hooks/functions';
- } else if (hook.className && hook.triggerName && hook.url) {
+ } else if ('className' in hook && hook.triggerName && hook.url) {
url = '/hooks/triggers';
} else {
return Promise.reject({ error: 'invalid hook declaration', code: 143 });
@@ -78,43 +80,45 @@ const DefaultController = {
return this.sendRequest('POST', url, hook);
},
- remove(hook) {
- let url;
- if (hook.functionName) {
+ remove(hook: { functionName: string } | { className: string, triggerName: string }) {
+ let url: string;
+ const putParams = { ...hook };
+ if ('functionName' in hook) {
url = '/hooks/functions/' + hook.functionName;
- delete hook.functionName;
+ delete (putParams as Partial).functionName;
} else if (hook.className && hook.triggerName) {
url = '/hooks/triggers/' + hook.className + '/' + hook.triggerName;
- delete hook.className;
- delete hook.triggerName;
+ delete (putParams as Partial).className;
+ delete (putParams as Partial).triggerName;
} else {
return Promise.reject({ error: 'invalid hook declaration', code: 143 });
}
return this.sendRequest('PUT', url, { __op: 'Delete' });
},
- update(hook) {
- let url;
- if (hook.functionName && hook.url) {
+ update(hook: HookDeclaration) {
+ let url: string;
+ const postParams = { ...hook };
+ if ('functionName' in hook && hook.url) {
url = '/hooks/functions/' + hook.functionName;
- delete hook.functionName;
- } else if (hook.className && hook.triggerName && hook.url) {
+ delete (postParams as Partial).functionName;
+ } else if ('className' in hook && hook.triggerName && hook.url) {
url = '/hooks/triggers/' + hook.className + '/' + hook.triggerName;
- delete hook.className;
- delete hook.triggerName;
+ delete (postParams as Partial).className;
+ delete (postParams as Partial).triggerName;
} else {
return Promise.reject({ error: 'invalid hook declaration', code: 143 });
}
- return this.sendRequest('PUT', url, hook);
+ return this.sendRequest('PUT', url, postParams);
},
- sendRequest(method, url, body) {
+ sendRequest(method: string, url: string, body?: any) {
return CoreManager.getRESTController()
.request(method, url, body, { useMasterKey: true })
.then(res => {
const decoded = decode(res);
if (decoded) {
- return Promise.resolve(decoded);
+ return Promise.resolve(decoded);
}
return Promise.reject(
new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.')
diff --git a/src/ParseInstallation.js b/src/ParseInstallation.ts
similarity index 91%
rename from src/ParseInstallation.js
rename to src/ParseInstallation.ts
index 380b5c8a9..c624aa27f 100644
--- a/src/ParseInstallation.js
+++ b/src/ParseInstallation.ts
@@ -7,7 +7,7 @@ import ParseObject from './ParseObject';
import type { AttributeMap } from './ObjectStateMutations';
export default class Installation extends ParseObject {
- constructor(attributes: ?AttributeMap) {
+ constructor(attributes?: AttributeMap) {
super('_Installation');
if (attributes && typeof attributes === 'object') {
if (!this.set(attributes || {})) {
diff --git a/src/ParseLiveQuery.js b/src/ParseLiveQuery.ts
similarity index 95%
rename from src/ParseLiveQuery.js
rename to src/ParseLiveQuery.ts
index eea9e59e2..0a507d6a6 100644
--- a/src/ParseLiveQuery.js
+++ b/src/ParseLiveQuery.ts
@@ -3,7 +3,7 @@
*/
import LiveQueryClient from './LiveQueryClient';
import CoreManager from './CoreManager';
-
+import type { EventEmitter } from 'events';
function getLiveQueryClient(): Promise {
return CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
}
@@ -36,6 +36,10 @@ function getLiveQueryClient(): Promise {
* @static
*/
class LiveQuery {
+ emitter: EventEmitter;
+ on: EventEmitter['on'];
+ emit: EventEmitter['emit'];
+
constructor() {
const EventEmitter = CoreManager.getEventEmitter();
this.emitter = new EventEmitter();
@@ -44,14 +48,14 @@ class LiveQuery {
// adding listener so process does not crash
// best practice is for developer to register their own listener
- this.on('error', () => {});
+ this.on('error', () => { });
}
/**
* After open is called, the LiveQuery will try to send a connect request
* to the LiveQuery server.
*/
- async open(): void {
+ async open() {
const liveQueryClient = await getLiveQueryClient();
liveQueryClient.open();
}
@@ -63,7 +67,7 @@ class LiveQuery {
* If you call query.subscribe() after this, we'll create a new WebSocket
* connection to the LiveQuery server.
*/
- async close(): void {
+ async close() {
const liveQueryClient = await getLiveQueryClient();
liveQueryClient.close();
}
diff --git a/src/ParseObject.js b/src/ParseObject.ts
similarity index 91%
rename from src/ParseObject.js
rename to src/ParseObject.ts
index 32701191b..270a0ba9e 100644
--- a/src/ParseObject.js
+++ b/src/ParseObject.ts
@@ -36,12 +36,13 @@ import unsavedChildren from './unsavedChildren';
import type { AttributeMap, OpsMap } from './ObjectStateMutations';
import type { RequestOptions, FullOptions } from './RESTController';
-const uuidv4 = require('./uuid');
+import uuidv4 from './uuid';
export type Pointer = {
__type: string,
className: string,
- objectId: string,
+ objectId?: string,
+ _localId?: string
};
type SaveParams = {
@@ -53,6 +54,7 @@ type SaveParams = {
export type SaveOptions = FullOptions & {
cascadeSave?: boolean,
context?: AttributeMap,
+ batchSize?: number
};
// Mapping of class names to constructors, so we can populate objects from the
@@ -80,6 +82,10 @@ function getServerUrlPath() {
return url.substr(url.indexOf('/'));
}
+type ObjectFetchOptions = {
+ useMasterKey?: boolean, sessionToken?: string, include?: string | string[], context?: AttributeMap,
+}
+
/**
* Creates a new model with defined attributes.
*
@@ -105,8 +111,8 @@ class ParseObject {
* @param {object} options The options for this object instance.
*/
constructor(
- className: ?string | { className: string, [attr: string]: mixed },
- attributes?: { [attr: string]: mixed },
+ className?: string | { className: string, [attr: string]: any },
+ attributes?: { [attr: string]: any },
options?: { ignoreValidation: boolean }
) {
// Enable legacy initializers
@@ -114,7 +120,7 @@ class ParseObject {
this.initialize.apply(this, arguments);
}
- let toSet = null;
+ let toSet: { [attr: string]: any } | null = null;
this._objCount = objectCount++;
if (typeof className === 'string') {
this.className = className;
@@ -130,7 +136,7 @@ class ParseObject {
}
}
if (attributes && typeof attributes === 'object') {
- options = attributes;
+ options = attributes as any;
}
}
if (toSet && !this.set(toSet, options)) {
@@ -143,10 +149,11 @@ class ParseObject {
*
* @property {string} id
*/
- id: ?string;
- _localId: ?string;
+ id?: string;
+ _localId?: string;
_objCount: number;
className: string;
+ static className: string;
/* Prototype getters / setters */
@@ -161,7 +168,7 @@ class ParseObject {
* @property {Date} createdAt
* @returns {Date}
*/
- get createdAt(): ?Date {
+ get createdAt(): Date | undefined {
return this._getServerData().createdAt;
}
@@ -171,7 +178,7 @@ class ParseObject {
* @property {Date} updatedAt
* @returns {Date}
*/
- get updatedAt(): ?Date {
+ get updatedAt(): Date | undefined {
return this._getServerData().updatedAt;
}
@@ -280,7 +287,7 @@ class ParseObject {
}
_toFullJSON(seen?: Array, offline?: boolean): AttributeMap {
- const json: { [key: string]: mixed } = this.toJSON(seen, offline);
+ const json: { [key: string]: any } = this.toJSON(seen, offline);
json.__type = 'Object';
json.className = this.className;
return json;
@@ -290,7 +297,7 @@ class ParseObject {
const pending = this._getPendingOps();
const dirtyObjects = this._getDirtyObjectAttributes();
const json = {};
- let attr;
+ let attr: string;
for (attr in dirtyObjects) {
let isDotNotation = false;
@@ -346,7 +353,12 @@ class ParseObject {
}
const stateController = CoreManager.getObjectStateController();
stateController.initializeState(this._getStateIdentifier());
- const decoded = {};
+ const decoded: Partial<{
+ createdAt?: Date,
+ updatedAt?: Date,
+ ACL?: any // TODO: Maybe type this better?
+ [key: string]: any
+ }> = {};
for (const attr in serverData) {
if (attr === 'ACL') {
decoded[attr] = new ParseACL(serverData[attr]);
@@ -358,10 +370,10 @@ class ParseObject {
}
}
if (decoded.createdAt && typeof decoded.createdAt === 'string') {
- decoded.createdAt = parseDate(decoded.createdAt);
+ decoded.createdAt = parseDate(decoded.createdAt) || undefined;
}
if (decoded.updatedAt && typeof decoded.updatedAt === 'string') {
- decoded.updatedAt = parseDate(decoded.updatedAt);
+ decoded.updatedAt = parseDate(decoded.updatedAt) || undefined;
}
if (!decoded.updatedAt && decoded.createdAt) {
decoded.updatedAt = decoded.createdAt;
@@ -395,16 +407,22 @@ class ParseObject {
}
_handleSaveResponse(response: AttributeMap, status: number) {
- const changes = {};
+ const changes: Partial<{
+ createdAt: string,
+ updatedAt: string,
+ [key: string]: any
+ }> = {};
let attr;
const stateController = CoreManager.getObjectStateController();
const pending = stateController.popPendingState(this._getStateIdentifier());
- for (attr in pending) {
- if (pending[attr] instanceof RelationOp) {
- changes[attr] = pending[attr].applyTo(undefined, this, attr);
- } else if (!(attr in response)) {
- // Only SetOps and UnsetOps should not come back with results
- changes[attr] = pending[attr].applyTo(undefined);
+ if (pending) {
+ for (attr in pending) {
+ if (pending[attr] instanceof RelationOp) {
+ changes[attr] = pending[attr].applyTo(undefined, this, attr);
+ } else if (!(attr in response)) {
+ // Only SetOps and UnsetOps should not come back with results
+ changes[attr] = pending[attr].applyTo(undefined);
+ }
}
}
for (attr in response) {
@@ -462,7 +480,7 @@ class ParseObject {
toJSON(seen: Array | void, offline?: boolean): AttributeMap {
const seenEntry = this.id ? this.className + ':' + this.id : this;
seen = seen || [seenEntry];
- const json = {};
+ const json: AttributeMap = {};
const attrs = this.attributes;
for (const attr in attrs) {
if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) {
@@ -488,7 +506,7 @@ class ParseObject {
* @param {object} other - An other object ot compare
* @returns {boolean}
*/
- equals(other: mixed): boolean {
+ equals(other: any): boolean {
if (this === other) {
return true;
}
@@ -602,7 +620,7 @@ class ParseObject {
* @param {string} attr The string name of an attribute.
* @returns {*}
*/
- get(attr: string): mixed {
+ get(attr: string): any {
return this.attributes[attr];
}
@@ -689,7 +707,8 @@ class ParseObject {
* The only supported option is error.
* @returns {(ParseObject|boolean)} true if the set succeeded.
*/
- set(key: mixed, value: mixed, options?: mixed): ParseObject | boolean {
+ set(key: any, value?: any, options?: any): ParseObject | boolean {
+ // TODO: Improve types here without breaking stuff.
let changes = {};
const newOps = {};
if (key && typeof key === 'object') {
@@ -698,13 +717,15 @@ class ParseObject {
} else if (typeof key === 'string') {
changes[key] = value;
} else {
+ // Key is weird; just return ourself
return this;
}
options = options || {};
- let readonly = [];
- if (typeof this.constructor.readOnlyAttributes === 'function') {
- readonly = readonly.concat(this.constructor.readOnlyAttributes());
+ /** Readonly attributes of the object class */
+ let readonly: string[] = [];
+ if (typeof ((this.constructor as any).readOnlyAttributes) === 'function') {
+ readonly = readonly.concat((this.constructor as any).readOnlyAttributes());
}
for (const k in changes) {
if (k === 'createdAt' || k === 'updatedAt') {
@@ -787,7 +808,7 @@ class ParseObject {
* @param options
* @returns {(ParseObject | boolean)}
*/
- unset(attr: string, options?: { [opt: string]: mixed }): ParseObject | boolean {
+ unset(attr: string, options?: { [opt: string]: any }): ParseObject | boolean {
options = options || {};
options.unset = true;
return this.set(attr, null, options);
@@ -837,7 +858,7 @@ class ParseObject {
* @param item {} The item to add.
* @returns {(ParseObject | boolean)}
*/
- add(attr: string, item: mixed): ParseObject | boolean {
+ add(attr: string, item: any): ParseObject | boolean {
return this.set(attr, new AddOp([item]));
}
@@ -849,7 +870,7 @@ class ParseObject {
* @param items {Object[]} The items to add.
* @returns {(ParseObject | boolean)}
*/
- addAll(attr: string, items: Array): ParseObject | boolean {
+ addAll(attr: string, items: Array): ParseObject | boolean {
return this.set(attr, new AddOp(items));
}
@@ -862,7 +883,7 @@ class ParseObject {
* @param item {} The object to add.
* @returns {(ParseObject | boolean)}
*/
- addUnique(attr: string, item: mixed): ParseObject | boolean {
+ addUnique(attr: string, item: any): ParseObject | boolean {
return this.set(attr, new AddUniqueOp([item]));
}
@@ -875,7 +896,7 @@ class ParseObject {
* @param items {Object[]} The objects to add.
* @returns {(ParseObject | boolean)}
*/
- addAllUnique(attr: string, items: Array): ParseObject | boolean {
+ addAllUnique(attr: string, items: Array): ParseObject | boolean {
return this.set(attr, new AddUniqueOp(items));
}
@@ -887,7 +908,7 @@ class ParseObject {
* @param item {} The object to remove.
* @returns {(ParseObject | boolean)}
*/
- remove(attr: string, item: mixed): ParseObject | boolean {
+ remove(attr: string, item: any): ParseObject | boolean {
return this.set(attr, new RemoveOp([item]));
}
@@ -899,7 +920,7 @@ class ParseObject {
* @param items {Object[]} The object to remove.
* @returns {(ParseObject | boolean)}
*/
- removeAll(attr: string, items: Array): ParseObject | boolean {
+ removeAll(attr: string, items: Array): ParseObject | boolean {
return this.set(attr, new RemoveOp(items));
}
@@ -912,7 +933,7 @@ class ParseObject {
* @param attr {String} The key.
* @returns {Parse.Op | undefined} The operation, or undefined if none.
*/
- op(attr: string): ?Op {
+ op(attr: string): Op | undefined {
const pending = this._getPendingOps();
for (let i = pending.length; i--;) {
if (pending[i][attr]) {
@@ -926,11 +947,11 @@ class ParseObject {
*
* @returns {Parse.Object}
*/
- clone(): any {
- const clone = new this.constructor(this.className);
+ clone(): typeof this {
+ const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className);
let attributes = this.attributes;
- if (typeof this.constructor.readOnlyAttributes === 'function') {
- const readonly = this.constructor.readOnlyAttributes() || [];
+ if (typeof (this.constructor as any).readOnlyAttributes === 'function') {
+ const readonly = (this.constructor as any).readOnlyAttributes() || [];
// Attributes are frozen, so we have to rebuild an object,
// rather than delete readonly keys
const copy = {};
@@ -953,7 +974,7 @@ class ParseObject {
* @returns {Parse.Object}
*/
newInstance(): any {
- const clone = new this.constructor(this.className);
+ const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className);
clone.id = this.id;
if (singleInstance) {
// Just return an object with the right id
@@ -1060,7 +1081,7 @@ class ParseObject {
* @returns {Parse.ACL|null} An instance of Parse.ACL.
* @see Parse.Object#get
*/
- getACL(): ?ParseACL {
+ getACL(): ParseACL | null {
const acl = this.get('ACL');
if (acl instanceof ParseACL) {
return acl;
@@ -1076,7 +1097,7 @@ class ParseObject {
* @returns {(ParseObject | boolean)} Whether the set passed validation.
* @see Parse.Object#set
*/
- setACL(acl: ParseACL, options?: mixed): ParseObject | boolean {
+ setACL(acl: ParseACL, options?: any): ParseObject | boolean {
return this.set('ACL', acl, options);
}
@@ -1109,8 +1130,8 @@ class ParseObject {
const attributes = this.attributes;
const erasable = {};
let readonly = ['createdAt', 'updatedAt'];
- if (typeof this.constructor.readOnlyAttributes === 'function') {
- readonly = readonly.concat(this.constructor.readOnlyAttributes());
+ if (typeof (this.constructor as any).readOnlyAttributes === 'function') {
+ readonly = readonly.concat((this.constructor as any).readOnlyAttributes());
}
for (const attr in attributes) {
if (readonly.indexOf(attr) < 0) {
@@ -1137,9 +1158,9 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the fetch
* completes.
*/
- fetch(options: RequestOptions): Promise {
+ fetch(options: ObjectFetchOptions): Promise {
options = options || {};
- const fetchOptions = {};
+ const fetchOptions: ObjectFetchOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
fetchOptions.useMasterKey = options.useMasterKey;
}
@@ -1154,13 +1175,13 @@ class ParseObject {
if (Array.isArray(options.include)) {
options.include.forEach(key => {
if (Array.isArray(key)) {
- fetchOptions.include = fetchOptions.include.concat(key);
+ fetchOptions.include = fetchOptions.include!.concat(key);
} else {
- fetchOptions.include.push(key);
+ (fetchOptions.include as string[]).push(key);
}
});
} else {
- fetchOptions.include.push(options.include);
+ fetchOptions.include.push(options.include!); // already checked hasOwnProperty('include')
}
}
const controller = CoreManager.getObjectController();
@@ -1185,7 +1206,7 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the fetch
* completes.
*/
- fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise {
+ fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise {
options = options || {};
options.include = keys;
return this.fetch(options);
@@ -1215,7 +1236,7 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the save
* completes.
*/
- async saveEventually(options: SaveOptions): Promise {
+ async saveEventually(options: SaveOptions): Promise {
try {
await this.save(null, options);
} catch (e) {
@@ -1291,14 +1312,14 @@ class ParseObject {
* completes.
*/
save(
- arg1: ?string | { [attr: string]: mixed },
- arg2: SaveOptions | mixed,
+ arg1: undefined | string | { [attr: string]: any } | null,
+ arg2: SaveOptions | any,
arg3?: SaveOptions
- ): Promise {
- let attrs;
- let options;
- if (typeof arg1 === 'object' || typeof arg1 === 'undefined') {
- attrs = arg1;
+ ): Promise {
+ let attrs: { [attr: string]: any } | null;
+ let options: SaveOptions | undefined;
+ if (typeof arg1 === 'object' || typeof arg1 === 'undefined' || arg1 == null) {
+ attrs = (arg1 as { [attr: string]: any }) || null;
if (typeof arg2 === 'object') {
options = arg2;
}
@@ -1317,7 +1338,7 @@ class ParseObject {
}
options = options || {};
- const saveOptions = {};
+ const saveOptions: SaveOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
saveOptions.useMasterKey = !!options.useMasterKey;
}
@@ -1334,7 +1355,7 @@ class ParseObject {
const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null;
return controller.save(unsaved, saveOptions).then(() => {
return controller.save(this, saveOptions);
- });
+ }) as Promise as Promise;
}
/**
@@ -1359,7 +1380,7 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the destroy
* completes.
*/
- async destroyEventually(options: RequestOptions): Promise {
+ async destroyEventually(options: RequestOptions): Promise {
try {
await this.destroy(options);
} catch (e) {
@@ -1385,9 +1406,9 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the destroy
* completes.
*/
- destroy(options: RequestOptions): Promise {
+ destroy(options: RequestOptions): Promise {
options = options || {};
- const destroyOptions = {};
+ const destroyOptions: RequestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
destroyOptions.useMasterKey = options.useMasterKey;
}
@@ -1400,7 +1421,7 @@ class ParseObject {
if (!this.id) {
return Promise.resolve();
}
- return CoreManager.getObjectController().destroy(this, destroyOptions);
+ return CoreManager.getObjectController().destroy(this, destroyOptions) as Promise;
}
/**
@@ -1552,7 +1573,7 @@ class ParseObject {
* @returns {Parse.Object[]}
*/
static fetchAll(list: Array, options: RequestOptions = {}) {
- const queryOptions = {};
+ const queryOptions: RequestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
queryOptions.useMasterKey = options.useMasterKey;
}
@@ -1662,10 +1683,8 @@ class ParseObject {
* @static
* @returns {Parse.Object[]}
*/
- static fetchAllIfNeeded(list: Array, options) {
- options = options || {};
-
- const queryOptions = {};
+ static fetchAllIfNeeded(list: Array, options: ObjectFetchOptions = {}) {
+ const queryOptions: ObjectFetchOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
queryOptions.useMasterKey = options.useMasterKey;
}
@@ -1678,8 +1697,8 @@ class ParseObject {
return CoreManager.getObjectController().fetch(list, false, queryOptions);
}
- static handleIncludeOptions(options) {
- let include = [];
+ static handleIncludeOptions(options: { include?: string | string[] }) {
+ let include: string[] = [];
if (Array.isArray(options.include)) {
options.include.forEach(key => {
if (Array.isArray(key)) {
@@ -1689,7 +1708,7 @@ class ParseObject {
}
});
} else {
- include.push(options.include);
+ include.push(options.include!);
}
return include;
}
@@ -1740,8 +1759,8 @@ class ParseObject {
* @returns {Promise} A promise that is fulfilled when the destroyAll
* completes.
*/
- static destroyAll(list: Array, options = {}) {
- const destroyOptions = {};
+ static destroyAll(list: Array, options: SaveOptions = {}) {
+ const destroyOptions: SaveOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
destroyOptions.useMasterKey = options.useMasterKey;
}
@@ -1775,8 +1794,8 @@ class ParseObject {
* @static
* @returns {Parse.Object[]}
*/
- static saveAll(list: Array, options: RequestOptions = {}) {
- const saveOptions = {};
+ static saveAll(list: Array, options: SaveOptions = {}) {
+ const saveOptions: SaveOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
saveOptions.useMasterKey = options.useMasterKey;
}
@@ -1806,7 +1825,7 @@ class ParseObject {
* @static
* @returns {Parse.Object} A Parse.Object reference.
*/
- static createWithoutData(id: string) {
+ static createWithoutData(id: string): ParseObject {
const obj = new this();
obj.id = id;
return obj;
@@ -1822,13 +1841,13 @@ class ParseObject {
* @static
* @returns {Parse.Object} A Parse.Object reference
*/
- static fromJSON(json: any, override?: boolean, dirty?: boolean) {
+ static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject {
if (!json.className) {
throw new Error('Cannot create an object without a className');
}
const constructor = classMap[json.className];
const o = constructor ? new constructor(json.className) : new ParseObject(json.className);
- const otherAttributes = {};
+ const otherAttributes: AttributeMap = {};
for (const attr in json) {
if (attr !== 'className' && attr !== '__type') {
otherAttributes[attr] = json[attr];
@@ -1877,7 +1896,7 @@ class ParseObject {
if (typeof constructor !== 'function') {
throw new TypeError(
'You must register the subclass constructor. ' +
- 'Did you attempt to register an instance of the subclass?'
+ 'Did you attempt to register an instance of the subclass?'
);
}
classMap[className] = constructor;
@@ -1935,7 +1954,7 @@ class ParseObject {
* this method.
* @returns {Parse.Object} A new subclass of Parse.Object.
*/
- static extend(className: any, protoProps: any, classProps: any) {
+ static extend(className: any, protoProps?: any, classProps?: any) {
if (typeof className !== 'string') {
if (className && typeof className.className === 'string') {
return ParseObject.extend(className.className, className, protoProps);
@@ -1950,7 +1969,7 @@ class ParseObject {
}
let parentProto = ParseObject.prototype;
- if (this.hasOwnProperty('__super__') && this.__super__) {
+ if (this.hasOwnProperty('__super__') && (this as any).__super__) {
parentProto = this.prototype;
}
let ParseObjectSubclass = function (attributes, options) {
@@ -1976,15 +1995,16 @@ class ParseObject {
if (classMap[adjustedClassName]) {
ParseObjectSubclass = classMap[adjustedClassName];
} else {
- ParseObjectSubclass.extend = function (name, protoProps, classProps) {
+ // TODO: Maybe there is a more elegant solution to this?
+ (ParseObjectSubclass as any).extend = function (name: string, protoProps: any, classProps: any) {
if (typeof name === 'string') {
return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps);
}
return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps);
};
- ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData;
- ParseObjectSubclass.className = adjustedClassName;
- ParseObjectSubclass.__super__ = parentProto;
+ (ParseObjectSubclass as any).createWithoutData = ParseObject.createWithoutData;
+ (ParseObjectSubclass as any).className = adjustedClassName;
+ (ParseObjectSubclass as any).__super__ = parentProto;
ParseObjectSubclass.prototype = Object.create(parentProto, {
constructor: {
value: ParseObjectSubclass,
@@ -2195,17 +2215,19 @@ const DefaultController = {
target: ParseObject | Array,
forceFetch: boolean,
options: RequestOptions
- ): Promise | ParseObject> {
+ ): Promise | ParseObject | undefined> {
const localDatastore = CoreManager.getLocalDatastore();
if (Array.isArray(target)) {
if (target.length < 1) {
return Promise.resolve([]);
}
- const objs = [];
- const ids = [];
- let className = null;
- const results = [];
- let error = null;
+ /** Resulting Parse.Objects that have data */
+ const objs: ParseObject[] = [];
+ /** IDs to fetch */
+ const ids: string[] = [];
+ let className: null | string = null;
+ const results: ParseObject[] = [];
+ let error: ParseError | null = null;
target.forEach(el => {
if (error) {
return;
@@ -2223,7 +2245,7 @@ const DefaultController = {
error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID');
}
if (forceFetch || !el.isDataAvailable()) {
- ids.push(el.id);
+ ids.push(el.id!); // Already checked e.id above.
objs.push(el);
}
results.push(el);
@@ -2231,16 +2253,17 @@ const DefaultController = {
if (error) {
return Promise.reject(error);
}
- const query = new ParseQuery(className);
+ // Construct a ParseQuery that finds objects with matching IDs
+ const query = new ParseQuery(className!);
query.containedIn('objectId', ids);
if (options && options.include) {
query.include(options.include);
}
query._limit = ids.length;
- return query.find(options).then(async objects => {
- const idMap = {};
+ return query.find(options).then(async (objects: ParseObject[]) => {
+ const idMap: Record = {};
objects.forEach(o => {
- idMap[o.id] = o;
+ idMap[o.id!] = o;
});
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
@@ -2253,7 +2276,7 @@ const DefaultController = {
}
}
if (!singleInstance) {
- // If single instance objects are disabled, we need to replace the
+ // If single instance objects are disabled, we need to replace the objects in the results array.
for (let i = 0; i < results.length; i++) {
const obj = results[i];
if (obj && obj.id && idMap[obj.id]) {
@@ -2275,7 +2298,7 @@ const DefaultController = {
);
}
const RESTController = CoreManager.getRESTController();
- const params = {};
+ const params: RequestOptions = {};
if (options && options.include) {
params.include = options.include.join();
}
@@ -2292,13 +2315,14 @@ const DefaultController = {
return target;
});
}
- return Promise.resolve();
+ // Not Array, and not ParseObject; return undefined/void.
+ return Promise.resolve(undefined);
},
async destroy(
target: ParseObject | Array,
- options: RequestOptions
- ): Promise | ParseObject> {
+ options: SaveOptions
+ ): Promise | ParseObject> {
const batchSize =
options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE');
const localDatastore = CoreManager.getLocalDatastore();
@@ -2308,7 +2332,7 @@ const DefaultController = {
if (target.length < 1) {
return Promise.resolve([]);
}
- const batches = [[]];
+ const batches: ParseObject[][] = [[]];
target.forEach(obj => {
if (!obj.id) {
return;
@@ -2323,7 +2347,7 @@ const DefaultController = {
batches.pop();
}
let deleteCompleted = Promise.resolve();
- const errors = [];
+ const errors: ParseError[] = [];
batches.forEach(batch => {
deleteCompleted = deleteCompleted.then(() => {
return RESTController.request(
@@ -2375,7 +2399,7 @@ const DefaultController = {
return Promise.resolve(target);
},
- save(target: ParseObject | Array, options: RequestOptions) {
+ save(target: ParseObject | Array | null, options: RequestOptions) {
const batchSize =
options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE');
const localDatastore = CoreManager.getLocalDatastore();
@@ -2394,13 +2418,14 @@ const DefaultController = {
let unsaved = target.concat();
for (let i = 0; i < target.length; i++) {
- if (target[i] instanceof ParseObject) {
- unsaved = unsaved.concat(unsavedChildren(target[i], true));
+ const target_i = target[i];
+ if (target_i instanceof ParseObject) {
+ unsaved = unsaved.concat(unsavedChildren(target_i, true));
}
}
unsaved = unique(unsaved);
- const filesSaved: Array = [];
+ const filesSaved: Array | undefined> = [];
let pending: Array = [];
unsaved.forEach(el => {
if (el instanceof ParseFile) {
@@ -2411,14 +2436,14 @@ const DefaultController = {
});
return Promise.all(filesSaved).then(() => {
- let objectError = null;
+ let objectError: null | ParseError = null;
return continueWhile(
() => {
return pending.length > 0;
},
() => {
- const batch = [];
- const nextPending = [];
+ const batch: ParseObject[] = [];
+ const nextPending: ParseObject[] = [];
pending.forEach(el => {
if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) {
throw new ParseError(
@@ -2442,11 +2467,11 @@ const DefaultController = {
// Queue up tasks for each object in the batch.
// When every task is ready, the API request will execute
- const batchReturned = new resolvingPromise();
- const batchReady = [];
- const batchTasks = [];
+ const batchReturned = resolvingPromise();
+ const batchReady: ReturnType>[] = [];
+ const batchTasks: Promise[] = [];
batch.forEach((obj, index) => {
- const ready = new resolvingPromise();
+ const ready = resolvingPromise();
batchReady.push(ready);
const task = function () {
ready.resolve();
@@ -2503,7 +2528,7 @@ const DefaultController = {
for (const object of target) {
// Make sure that it is a ParseObject before updating it into the localDataStore
if (object instanceof ParseObject) {
- await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object);
+ await localDatastore._updateLocalIdForObject(mapIdForPin[object.id!], object);
await localDatastore._updateObjectIfPinned(object);
}
}
diff --git a/src/ParseOp.js b/src/ParseOp.ts
similarity index 76%
rename from src/ParseOp.js
rename to src/ParseOp.ts
index a35485c60..5da8cde7f 100644
--- a/src/ParseOp.js
+++ b/src/ParseOp.ts
@@ -5,71 +5,73 @@
import arrayContainsObject from './arrayContainsObject';
import decode from './decode';
import encode from './encode';
-import ParseObject from './ParseObject';
+import ParseObject, { Pointer } from './ParseObject';
import ParseRelation from './ParseRelation';
import unique from './unique';
-export function opFromJSON(json: { [key: string]: any }): ?Op {
+export function opFromJSON(json: { [key: string]: any }): Op | null {
if (!json || !json.__op) {
return null;
}
switch (json.__op) {
- case 'Delete':
- return new UnsetOp();
- case 'Increment':
- return new IncrementOp(json.amount);
- case 'Add':
- return new AddOp(decode(json.objects));
- case 'AddUnique':
- return new AddUniqueOp(decode(json.objects));
- case 'Remove':
- return new RemoveOp(decode(json.objects));
- case 'AddRelation': {
- const toAdd = decode(json.objects);
- if (!Array.isArray(toAdd)) {
- return new RelationOp([], []);
- }
- return new RelationOp(toAdd, []);
- }
- case 'RemoveRelation': {
- const toRemove = decode(json.objects);
- if (!Array.isArray(toRemove)) {
- return new RelationOp([], []);
+ case 'Delete':
+ return new UnsetOp();
+ case 'Increment':
+ return new IncrementOp(json.amount);
+ case 'Add':
+ return new AddOp(decode(json.objects));
+ case 'AddUnique':
+ return new AddUniqueOp(decode(json.objects));
+ case 'Remove':
+ return new RemoveOp(decode(json.objects));
+ case 'AddRelation': {
+ const toAdd = decode(json.objects);
+ if (!Array.isArray(toAdd)) {
+ return new RelationOp([], []);
+ }
+ return new RelationOp(toAdd, []);
}
- return new RelationOp([], toRemove);
- }
- case 'Batch': {
- let toAdd = [];
- let toRemove = [];
- for (let i = 0; i < json.ops.length; i++) {
- if (json.ops[i].__op === 'AddRelation') {
- toAdd = toAdd.concat(decode(json.ops[i].objects));
- } else if (json.ops[i].__op === 'RemoveRelation') {
- toRemove = toRemove.concat(decode(json.ops[i].objects));
+ case 'RemoveRelation': {
+ const toRemove = decode(json.objects);
+ if (!Array.isArray(toRemove)) {
+ return new RelationOp([], []);
}
+ return new RelationOp([], toRemove);
+ }
+ case 'Batch': {
+ let toAdd = [];
+ let toRemove = [];
+ for (let i = 0; i < json.ops.length; i++) {
+ if (json.ops[i].__op === 'AddRelation') {
+ toAdd = toAdd.concat(decode(json.ops[i].objects));
+ } else if (json.ops[i].__op === 'RemoveRelation') {
+ toRemove = toRemove.concat(decode(json.ops[i].objects));
+ }
+ }
+ return new RelationOp(toAdd, toRemove);
}
- return new RelationOp(toAdd, toRemove);
- }
}
return null;
}
export class Op {
+ __op?: string;
+ objects?: any[];
// Empty parent class
- applyTo(value: mixed): mixed {} /* eslint-disable-line no-unused-vars */
- mergeWith(previous: Op): ?Op {} /* eslint-disable-line no-unused-vars */
- toJSON(): mixed {}
+ applyTo(...value: any): any { } /* eslint-disable-line no-unused-vars */
+ mergeWith(previous: Op): Op | void { } /* eslint-disable-line no-unused-vars */
+ toJSON(offline?: boolean): any { }
}
export class SetOp extends Op {
- _value: ?mixed;
+ _value: any;
- constructor(value: mixed) {
+ constructor(value: any) {
super();
this._value = value;
}
- applyTo(): mixed {
+ applyTo(): any {
return this._value;
}
@@ -77,7 +79,7 @@ export class SetOp extends Op {
return new SetOp(this._value);
}
- toJSON(offline?: boolean) {
+ toJSON(offline?: boolean) : any {
return encode(this._value, false, true, undefined, offline);
}
}
@@ -107,7 +109,7 @@ export class IncrementOp extends Op {
this._amount = amount;
}
- applyTo(value: ?mixed): number {
+ applyTo(value: any): number {
if (typeof value === 'undefined') {
return this._amount;
}
@@ -139,14 +141,14 @@ export class IncrementOp extends Op {
}
export class AddOp extends Op {
- _value: Array;
+ _value: Array;
- constructor(value: mixed | Array) {
+ constructor(value: any | Array) {
super();
this._value = Array.isArray(value) ? value : [value];
}
- applyTo(value: mixed): Array {
+ applyTo(value: any): Array {
if (value == null) {
return this._value;
}
@@ -172,25 +174,25 @@ export class AddOp extends Op {
throw new Error('Cannot merge Add Op with the previous Op');
}
- toJSON(): { __op: string, objects: mixed } {
+ toJSON(): { __op: string, objects: any } {
return { __op: 'Add', objects: encode(this._value, false, true) };
}
}
export class AddUniqueOp extends Op {
- _value: Array;
+ _value: Array;
- constructor(value: mixed | Array) {
+ constructor(value: any | Array) {
super();
this._value = unique(Array.isArray(value) ? value : [value]);
}
- applyTo(value: mixed | Array): Array {
+ applyTo(value: any | Array): Array {
if (value == null) {
return this._value || [];
}
if (Array.isArray(value)) {
- const toAdd = [];
+ const toAdd: any[] = [];
this._value.forEach(v => {
if (v instanceof ParseObject) {
if (!arrayContainsObject(value, v)) {
@@ -223,20 +225,20 @@ export class AddUniqueOp extends Op {
throw new Error('Cannot merge AddUnique Op with the previous Op');
}
- toJSON(): { __op: string, objects: mixed } {
+ toJSON(): { __op: string, objects: any } {
return { __op: 'AddUnique', objects: encode(this._value, false, true) };
}
}
export class RemoveOp extends Op {
- _value: Array;
+ _value: Array;
- constructor(value: mixed | Array) {
+ constructor(value: any | Array) {
super();
this._value = unique(Array.isArray(value) ? value : [value]);
}
- applyTo(value: mixed | Array): Array {
+ applyTo(value: any | Array): Array {
if (value == null) {
return [];
}
@@ -291,13 +293,13 @@ export class RemoveOp extends Op {
throw new Error('Cannot merge Remove Op with the previous Op');
}
- toJSON(): { __op: string, objects: mixed } {
+ toJSON(): { __op: string, objects: any } {
return { __op: 'Remove', objects: encode(this._value, false, true) };
}
}
export class RelationOp extends Op {
- _targetClassName: ?string;
+ _targetClassName: string | null;
relationsToAdd: Array;
relationsToRemove: Array;
@@ -327,16 +329,16 @@ export class RelationOp extends Op {
if (this._targetClassName !== obj.className) {
throw new Error(
'Tried to create a Relation with 2 different object types: ' +
- this._targetClassName +
- ' and ' +
- obj.className +
- '.'
+ this._targetClassName +
+ ' and ' +
+ obj.className +
+ '.'
);
}
return obj.id;
}
- applyTo(value: mixed, object?: { className: string, id: ?string }, key?: string): ?ParseRelation {
+ applyTo(value: any, object?: { className: string, id?: string }, key?: string): ParseRelation {
if (!value) {
if (!object || !key) {
throw new Error(
@@ -359,10 +361,10 @@ export class RelationOp extends Op {
if (this._targetClassName !== value.targetClassName) {
throw new Error(
'Related object must be a ' +
- value.targetClassName +
- ', but a ' +
- this._targetClassName +
- ' was passed in.'
+ value.targetClassName +
+ ', but a ' +
+ this._targetClassName +
+ ' was passed in.'
);
}
} else {
@@ -386,10 +388,10 @@ export class RelationOp extends Op {
if (previous._targetClassName && previous._targetClassName !== this._targetClassName) {
throw new Error(
'Related object must be of class ' +
- previous._targetClassName +
- ', but ' +
- (this._targetClassName || 'null') +
- ' was passed in.'
+ previous._targetClassName +
+ ', but ' +
+ (this._targetClassName || 'null') +
+ ' was passed in.'
);
}
const newAdd = previous.relationsToAdd.concat([]);
@@ -427,18 +429,19 @@ export class RelationOp extends Op {
throw new Error('Cannot merge Relation Op with the previous Op');
}
- toJSON(): { __op?: string, objects?: mixed, ops?: mixed } {
- const idToPointer = id => {
- return {
+ toJSON(): { __op?: string, objects?: any, ops?: any } {
+ const idToPointer = (id: string) => {
+ const ret: Pointer = {
__type: 'Pointer',
- className: this._targetClassName,
+ className: this._targetClassName!,
objectId: id,
};
+ return ret;
};
- let adds = null;
- let removes = null;
- let pointers = null;
+ let pointers: null | (Pointer[]) = null;
+ let adds: null | { __op: string, objects: null | (Pointer[]) } = null;
+ let removes: null | { __op: string, objects: null | (Pointer[]) } = null;
if (this.relationsToAdd.length > 0) {
pointers = this.relationsToAdd.map(idToPointer);
@@ -452,7 +455,6 @@ export class RelationOp extends Op {
if (adds && removes) {
return { __op: 'Batch', ops: [adds, removes] };
}
-
return adds || removes || {};
}
}
diff --git a/src/ParsePolygon.js b/src/ParsePolygon.ts
similarity index 94%
rename from src/ParsePolygon.js
rename to src/ParsePolygon.ts
index a7887ea02..27a8ed367 100644
--- a/src/ParsePolygon.js
+++ b/src/ParsePolygon.ts
@@ -24,12 +24,12 @@ import ParseGeoPoint from './ParseGeoPoint';
* @alias Parse.Polygon
*/
class ParsePolygon {
- _coordinates: Array>;
+ _coordinates: Array<[number, number]>;
/**
* @param {(number[][] | Parse.GeoPoint[])} coordinates An Array of coordinate pairs
*/
- constructor(coordinates: Array> | Array) {
+ constructor(coordinates: Array | [number, number]> | Array) {
this._coordinates = ParsePolygon._validate(coordinates);
}
@@ -67,7 +67,7 @@ class ParsePolygon {
* @param {(Parse.Polygon | object)} other
* @returns {boolean}
*/
- equals(other: mixed): boolean {
+ equals(other: ParsePolygon | any): boolean {
if (!(other instanceof ParsePolygon) || this.coordinates.length !== other.coordinates.length) {
return false;
}
@@ -138,14 +138,14 @@ class ParsePolygon {
* @throws {TypeError}
* @returns {number[][]} Array of coordinates if validated.
*/
- static _validate(coords: Array> | Array): Array> {
+ static _validate(coords: Array> | Array): Array<[number, number]> {
if (!Array.isArray(coords)) {
throw new TypeError('Coordinates must be an Array');
}
if (coords.length < 3) {
throw new TypeError('Polygon must have at least 3 GeoPoints or Points');
}
- const points = [];
+ const points: [number, number][] = [];
for (let i = 0; i < coords.length; i += 1) {
const coord = coords[i];
let geoPoint;
diff --git a/src/ParseQuery.js b/src/ParseQuery.ts
similarity index 92%
rename from src/ParseQuery.js
rename to src/ParseQuery.ts
index 9be6b37a9..70a8d9adb 100644
--- a/src/ParseQuery.js
+++ b/src/ParseQuery.ts
@@ -14,10 +14,47 @@ import { DEFAULT_PIN } from './LocalDatastoreUtils';
import type LiveQuerySubscription from './LiveQuerySubscription';
import type { RequestOptions, FullOptions } from './RESTController';
-type BatchOptions = FullOptions & { batchSize?: number };
+/**
+ * * batchSize: How many objects to yield in each batch (default: 100)
+ * useMasterKey: In Cloud Code and Node only, causes the Master Key to
+ * be used for this request.
+ * sessionToken: A valid session token, used for making a request on
+ * behalf of a specific user.
+ * context: A dictionary that is accessible in Cloud Code `beforeFind` trigger.
+ *
+ */
+type BatchOptions = FullOptions & {
+ batchSize?: number
+ useMasterKey?: boolean,
+ sessionToken?: string,
+ context?: { [key: string]: any },
+ json?: boolean
+};
+
+/**
+ * Valid options are:
+ * useMasterKey: In Cloud Code and Node only, causes the Master Key to be used for this request.
+ * sessionToken: A valid session token, used for making a request on behalf of a specific user.
+ * context: A dictionary that is accessible in Cloud Code `beforeFind` trigger.
+ * json: Return raw json without converting to Parse.Object
+ */
+type QueryOptions = {
+ useMasterKey?: boolean,
+ sessionToken?: string,
+ context?: { [key: string]: any },
+ json?: boolean
+}
+type FullTextQueryOptions = {
+ /** @param {string} options.language The language that determines the list of stop words for the search and the rules for the stemmer and tokenizer.*/
+ language?: string,
+ /** @param {boolean} options.caseSensitive A boolean flag to enable or disable case sensitive search.*/
+ caseSensitive?: boolean,
+ /** @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search.*/
+ diacriticSensitive?: boolean
+}
export type WhereClause = {
- [attr: string]: mixed,
+ [attr: string]: any,
};
export type QueryJSON = {
@@ -31,7 +68,7 @@ export type QueryJSON = {
order?: string,
className?: string,
count?: number,
- hint?: mixed,
+ hint?: any,
explain?: boolean,
readPreference?: string,
includeReadPreference?: string,
@@ -59,8 +96,8 @@ function quote(s: string): string {
* @private
* @returns {string}
*/
-function _getClassNameFromQueries(queries: Array): ?string {
- let className = null;
+function _getClassNameFromQueries(queries: Array): string | null {
+ let className: string | null = null;
queries.forEach(q => {
if (!className) {
className = q.className;
@@ -233,20 +270,20 @@ class ParseQuery {
_skip: number;
_count: boolean;
_order: Array;
- _readPreference: string;
- _includeReadPreference: string;
- _subqueryReadPreference: string;
+ _readPreference: string | null;
+ _includeReadPreference: string | null;
+ _subqueryReadPreference: string | null;
_queriesLocalDatastore: boolean;
_localDatastorePinName: any;
- _extraOptions: { [key: string]: mixed };
- _hint: mixed;
+ _extraOptions: { [key: string]: any };
+ _hint: any;
_explain: boolean;
_xhrRequest: any;
/**
* @param {(string | Parse.Object)} objectClass An instance of a subclass of Parse.Object, or a Parse className string.
*/
- constructor(objectClass: string | ParseObject) {
+ constructor(objectClass: string | ParseObject | (typeof ParseObject)) {
if (typeof objectClass === 'string') {
if (objectClass === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) {
this.className = '_User';
@@ -256,10 +293,11 @@ class ParseQuery {
} else if (objectClass instanceof ParseObject) {
this.className = objectClass.className;
} else if (typeof objectClass === 'function') {
- if (typeof objectClass.className === 'string') {
- this.className = objectClass.className;
+ const objectClz = (objectClass) as typeof ParseObject;
+ if (typeof objectClz.className === 'string') {
+ this.className = objectClz.className;
} else {
- const obj = new objectClass();
+ const obj = new objectClz();
this.className = obj.className;
}
} else {
@@ -281,7 +319,7 @@ class ParseQuery {
this._extraOptions = {};
this._xhrRequest = {
task: null,
- onchange: () => {},
+ onchange: () => { },
};
}
@@ -338,7 +376,7 @@ class ParseQuery {
* @param value
* @returns {Parse.Query}
*/
- _addCondition(key: string, condition: string, value: mixed): ParseQuery {
+ _addCondition(key: string, condition: string, value: any): ParseQuery {
if (!this._where[key] || typeof this._where[key] === 'string') {
this._where[key] = {};
}
@@ -356,7 +394,7 @@ class ParseQuery {
return '^' + quote(string);
}
- async _handleOfflineQuery(params: any) {
+ async _handleOfflineQuery(params: QueryJSON) {
OfflineQuery.validateQuery(this);
const localDatastore = CoreManager.getLocalDatastore();
const objects = await localDatastore._serializeObjectsFromPinName(this._localDatastorePinName);
@@ -609,10 +647,10 @@ class ParseQuery {
* @returns {Promise} A promise that is resolved with the result when
* the query completes.
*/
- get(objectId: string, options?: FullOptions): Promise {
+ get(objectId: string, options?: QueryOptions): Promise {
this.equalTo('objectId', objectId);
- const firstOptions = {};
+ const firstOptions: QueryOptions = {};
if (options && options.hasOwnProperty('useMasterKey')) {
firstOptions.useMasterKey = options.useMasterKey;
}
@@ -630,7 +668,6 @@ class ParseQuery {
if (response) {
return response;
}
-
const errorObject = new ParseError(ParseError.OBJECT_NOT_FOUND, 'Object not found.');
return Promise.reject(errorObject);
});
@@ -651,10 +688,10 @@ class ParseQuery {
* @returns {Promise} A promise that is resolved with the results when
* the query completes.
*/
- find(options?: FullOptions): Promise> {
+ find(options?: QueryOptions): Promise> {
options = options || {};
- const findOptions = {};
+ const findOptions: QueryOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
@@ -678,7 +715,7 @@ class ParseQuery {
if (this._explain) {
return response.results;
}
- const results = response.results.map(data => {
+ const results = response.results!.map(data => {
// In cases of relations, the server may send back a className
// on the top level of the payload
const override = response.className || this.className;
@@ -692,7 +729,7 @@ class ParseQuery {
if (select) {
handleSelectResult(data, select);
}
- if (options.json) {
+ if (options?.json) {
return data;
} else {
return ParseObject.fromJSON(data, !select);
@@ -702,7 +739,7 @@ class ParseQuery {
const count = response.count;
if (typeof count === 'number') {
- return { results, count };
+ return { results, count } as any;
} else {
return results;
}
@@ -744,10 +781,10 @@ class ParseQuery {
* @returns {Promise} A promise that is resolved with the count when
* the query completes.
*/
- count(options?: FullOptions): Promise {
+ count(options?: { useMasterKey?: boolean, sessionToken?: string }): Promise {
options = options || {};
- const findOptions = {};
+ const findOptions: { useMasterKey?: boolean, sessionToken?: string } = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
@@ -763,7 +800,7 @@ class ParseQuery {
params.count = 1;
return controller.find(this.className, params, findOptions).then(result => {
- return result.count;
+ return result.count!;
});
}
@@ -778,12 +815,10 @@ class ParseQuery {
*
* @returns {Promise} A promise that is resolved with the query completes.
*/
- distinct(key: string, options?: FullOptions): Promise> {
+ distinct(key: string, options?: { sessionToken?: string }): Promise> {
options = options || {};
- const distinctOptions = {};
- distinctOptions.useMasterKey = true;
-
+ const distinctOptions: { sessionToken?: string, useMasterKey: boolean } = { useMasterKey: true };
if (options.hasOwnProperty('sessionToken')) {
distinctOptions.sessionToken = options.sessionToken;
}
@@ -796,7 +831,7 @@ class ParseQuery {
hint: this._hint,
};
return controller.aggregate(this.className, params, distinctOptions).then(results => {
- return results.results;
+ return results.results!;
});
}
@@ -810,10 +845,9 @@ class ParseQuery {
*
* @returns {Promise} A promise that is resolved with the query completes.
*/
- aggregate(pipeline: mixed, options?: FullOptions): Promise> {
+ aggregate(pipeline: any, options?: { sessionToken?: string }): Promise> {
options = options || {};
- const aggregateOptions = {};
- aggregateOptions.useMasterKey = true;
+ const aggregateOptions: { sessionToken?: string, useMasterKey: boolean } = { useMasterKey: true };
if (options.hasOwnProperty('sessionToken')) {
aggregateOptions.sessionToken = options.sessionToken;
@@ -840,7 +874,7 @@ class ParseQuery {
readPreference: this._readPreference,
};
return controller.aggregate(this.className, params, aggregateOptions).then(results => {
- return results.results;
+ return results.results!;
});
}
@@ -860,10 +894,8 @@ class ParseQuery {
* @returns {Promise} A promise that is resolved with the object when
* the query completes.
*/
- first(options?: FullOptions): Promise {
- options = options || {};
-
- const findOptions = {};
+ first(options: QueryOptions = {}): Promise {
+ const findOptions: QueryOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
@@ -892,7 +924,7 @@ class ParseQuery {
}
return controller.find(this.className, params, findOptions).then(response => {
- const objects = response.results;
+ const objects = response.results!;
if (!objects[0]) {
return undefined;
}
@@ -936,7 +968,7 @@ class ParseQuery {
* iteration has completed.
*/
eachBatch(
- callback: (objs: Array) => Promise<*>,
+ callback: (objs: Array) => void,
options?: BatchOptions
): Promise {
options = options || {};
@@ -974,7 +1006,7 @@ class ParseQuery {
query.ascending('objectId');
- const findOptions = {};
+ const findOptions: BatchOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
findOptions.useMasterKey = options.useMasterKey;
}
@@ -989,7 +1021,7 @@ class ParseQuery {
}
let finished = false;
- let previousResults = [];
+ let previousResults: ParseObject[] = [];
return continueWhile(
() => {
return !finished;
@@ -1050,7 +1082,7 @@ class ParseQuery {
* @param {(string|object)} value String or Object of index that should be used when executing query
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- hint(value: mixed): ParseQuery {
+ hint(value: any): ParseQuery {
if (typeof value === 'undefined') {
delete this._hint;
}
@@ -1098,7 +1130,7 @@ class ParseQuery {
callback: (currentObject: ParseObject, index: number, query: ParseQuery) => any,
options?: BatchOptions
): Promise> {
- const array = [];
+ const array: any[] = [];
let index = 0;
await this.each(object => {
return Promise.resolve(callback(object, index, this)).then(result => {
@@ -1186,7 +1218,7 @@ class ParseQuery {
callback: (currentObject: ParseObject, index: number, query: ParseQuery) => boolean,
options?: BatchOptions
): Promise> {
- const array = [];
+ const array: ParseObject[] = [];
let index = 0;
await this.each(object => {
return Promise.resolve(callback(object, index, this)).then(flag => {
@@ -1209,16 +1241,16 @@ class ParseQuery {
* @param value The value that the Parse.Object must contain.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- equalTo(key: string | { [key: string]: any }, value: ?mixed): ParseQuery {
+ equalTo(key: string | { [key: string]: any }, value?: any): ParseQuery {
if (key && typeof key === 'object') {
Object.entries(key).forEach(([k, val]) => this.equalTo(k, val));
return this;
}
if (typeof value === 'undefined') {
- return this.doesNotExist(key);
+ return this.doesNotExist(key as string);
}
- this._where[key] = encode(value, false, true);
+ this._where[key as string] = encode(value, false, true);
return this;
}
@@ -1230,12 +1262,12 @@ class ParseQuery {
* @param value The value that must not be equalled.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- notEqualTo(key: string | { [key: string]: any }, value: ?mixed): ParseQuery {
+ notEqualTo(key: string | { [key: string]: any }, value?: any): ParseQuery {
if (key && typeof key === 'object') {
Object.entries(key).forEach(([k, val]) => this.notEqualTo(k, val));
return this;
}
- return this._addCondition(key, '$ne', value);
+ return this._addCondition(key as string, '$ne', value);
}
/**
@@ -1246,7 +1278,7 @@ class ParseQuery {
* @param value The value that provides an upper bound.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- lessThan(key: string, value: mixed): ParseQuery {
+ lessThan(key: string, value: any): ParseQuery {
return this._addCondition(key, '$lt', value);
}
@@ -1258,7 +1290,7 @@ class ParseQuery {
* @param value The value that provides an lower bound.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- greaterThan(key: string, value: mixed): ParseQuery {
+ greaterThan(key: string, value: any): ParseQuery {
return this._addCondition(key, '$gt', value);
}
@@ -1270,7 +1302,7 @@ class ParseQuery {
* @param value The value that provides an upper bound.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- lessThanOrEqualTo(key: string, value: mixed): ParseQuery {
+ lessThanOrEqualTo(key: string, value: any): ParseQuery {
return this._addCondition(key, '$lte', value);
}
@@ -1282,7 +1314,7 @@ class ParseQuery {
* @param {*} value The value that provides an lower bound.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- greaterThanOrEqualTo(key: string, value: mixed): ParseQuery {
+ greaterThanOrEqualTo(key: string, value: any): ParseQuery {
return this._addCondition(key, '$gte', value);
}
@@ -1294,7 +1326,7 @@ class ParseQuery {
* @param {Array<*>} value The values that will match.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- containedIn(key: string, value: Array): ParseQuery {
+ containedIn(key: string, value: Array): ParseQuery {
return this._addCondition(key, '$in', value);
}
@@ -1306,7 +1338,7 @@ class ParseQuery {
* @param {Array<*>} value The values that will not match.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- notContainedIn(key: string, value: Array): ParseQuery {
+ notContainedIn(key: string, value: Array): ParseQuery {
return this._addCondition(key, '$nin', value);
}
@@ -1318,7 +1350,7 @@ class ParseQuery {
* @param {Array} values The values that will match.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- containedBy(key: string, values: Array): ParseQuery {
+ containedBy(key: string, values: Array): ParseQuery {
return this._addCondition(key, '$containedBy', values);
}
@@ -1330,7 +1362,7 @@ class ParseQuery {
* @param {Array} values The values that will match.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- containsAll(key: string, values: Array): ParseQuery {
+ containsAll(key: string, values: Array): ParseQuery {
return this._addCondition(key, '$all', values);
}
@@ -1385,16 +1417,18 @@ class ParseQuery {
* @param {string} modifiers The regular expression mode.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- matches(key: string, regex: RegExp, modifiers: string): ParseQuery {
+ matches(key: string, regex: RegExp | string, modifiers: string): ParseQuery {
this._addCondition(key, '$regex', regex);
if (!modifiers) {
modifiers = '';
}
- if (regex.ignoreCase) {
- modifiers += 'i';
- }
- if (regex.multiline) {
- modifiers += 'm';
+ if (typeof regex != 'string') {
+ if (regex.ignoreCase) {
+ modifiers += 'i';
+ }
+ if (regex.multiline) {
+ modifiers += 'm';
+ }
}
if (modifiers.length) {
this._addCondition(key, '$options', modifiers);
@@ -1516,8 +1550,7 @@ class ParseQuery {
* @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- fullText(key: string, value: string, options: ?Object): ParseQuery {
- options = options || {};
+ fullText(key: string, value: string, options: FullTextQueryOptions = {}): ParseQuery {
if (!key) {
throw new Error('A key is required.');
@@ -1529,22 +1562,22 @@ class ParseQuery {
throw new Error('The value being searched for must be a string.');
}
- const fullOptions = {};
+ const fullOptions: { $term?: string, $language?: string, $caseSensitive?: boolean, $diacriticSensitive?: boolean } = {};
fullOptions.$term = value;
for (const option in options) {
switch (option) {
- case 'language':
- fullOptions.$language = options[option];
- break;
- case 'caseSensitive':
- fullOptions.$caseSensitive = options[option];
- break;
- case 'diacriticSensitive':
- fullOptions.$diacriticSensitive = options[option];
- break;
- default:
- throw new Error(`Unknown option: ${option}`);
+ case 'language':
+ fullOptions.$language = options[option];
+ break;
+ case 'caseSensitive':
+ fullOptions.$caseSensitive = options[option];
+ break;
+ case 'diacriticSensitive':
+ fullOptions.$diacriticSensitive = options[option];
+ break;
+ default:
+ throw new Error(`Unknown option: ${option}`);
}
}
@@ -1961,8 +1994,8 @@ class ParseQuery {
subqueryReadPreference?: string
): ParseQuery {
this._readPreference = readPreference;
- this._includeReadPreference = includeReadPreference;
- this._subqueryReadPreference = subqueryReadPreference;
+ this._includeReadPreference = includeReadPreference || null;
+ this._subqueryReadPreference = subqueryReadPreference || null;
return this;
}
@@ -1976,7 +2009,7 @@ class ParseQuery {
async subscribe(sessionToken?: string): Promise {
const currentUser = await CoreManager.getUserController().currentUserAsync();
if (!sessionToken) {
- sessionToken = currentUser ? currentUser.getSessionToken() : undefined;
+ sessionToken = currentUser ? currentUser.getSessionToken() || undefined : undefined;
}
const liveQueryClient = await CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
if (liveQueryClient.shouldOpen()) {
@@ -2002,7 +2035,7 @@ class ParseQuery {
*/
static or(...queries: Array): ParseQuery {
const className = _getClassNameFromQueries(queries);
- const query = new ParseQuery(className);
+ const query = new ParseQuery(className!);
query._orQuery(queries);
return query;
}
@@ -2021,7 +2054,7 @@ class ParseQuery {
*/
static and(...queries: Array): ParseQuery {
const className = _getClassNameFromQueries(queries);
- const query = new ParseQuery(className);
+ const query = new ParseQuery(className!);
query._andQuery(queries);
return query;
}
@@ -2040,7 +2073,7 @@ class ParseQuery {
*/
static nor(...queries: Array): ParseQuery {
const className = _getClassNameFromQueries(queries);
- const query = new ParseQuery(className);
+ const query = new ParseQuery(className!);
query._norQuery(queries);
return query;
}
@@ -2080,7 +2113,7 @@ class ParseQuery {
* @param {string} name The name of query source.
* @returns {Parse.Query} Returns the query, so you can chain this call.
*/
- fromPinWithName(name?: string): ParseQuery {
+ fromPinWithName(name?: string | null): ParseQuery {
const localDatastore = CoreManager.getLocalDatastore();
if (localDatastore.checkIfEnabled()) {
this._queriesLocalDatastore = true;
@@ -2099,10 +2132,11 @@ class ParseQuery {
this._xhrRequest.task._aborted = true;
this._xhrRequest.task.abort();
this._xhrRequest.task = null;
- this._xhrRequest.onchange = () => {};
+ this._xhrRequest.onchange = () => { };
return this;
}
- return (this._xhrRequest.onchange = () => this.cancel());
+ this._xhrRequest.onchange = () => this.cancel();
+ return this;
}
_setRequestTask(options) {
@@ -2114,12 +2148,12 @@ class ParseQuery {
}
const DefaultController = {
- find(className: string, params: QueryJSON, options: RequestOptions): Promise> {
+ find(className: string, params: QueryJSON, options: RequestOptions): Promise<{ results: Array }> {
const RESTController = CoreManager.getRESTController();
return RESTController.request('GET', 'classes/' + className, params, options);
},
- aggregate(className: string, params: any, options: RequestOptions): Promise> {
+ aggregate(className: string, params: any, options: RequestOptions): Promise<{ results: Array }> {
const RESTController = CoreManager.getRESTController();
return RESTController.request('GET', 'aggregate/' + className, params, options);
diff --git a/src/ParseRelation.js b/src/ParseRelation.ts
similarity index 92%
rename from src/ParseRelation.js
rename to src/ParseRelation.ts
index 50c8c09f1..23b9f5c19 100644
--- a/src/ParseRelation.js
+++ b/src/ParseRelation.ts
@@ -20,15 +20,15 @@ import ParseQuery from './ParseQuery';
* @alias Parse.Relation
*/
class ParseRelation {
- parent: ?ParseObject;
- key: ?string;
- targetClassName: ?string;
+ parent?: ParseObject;
+ key?: string;
+ targetClassName: string | null;
/**
* @param {Parse.Object} parent The parent of this relation.
* @param {string} key The key for this relation on the parent.
*/
- constructor(parent: ?ParseObject, key: ?string) {
+ constructor(parent?: ParseObject, key?: string) {
this.parent = parent;
this.key = key;
this.targetClassName = null;
@@ -77,7 +77,9 @@ class ParseRelation {
if (objects.length === 0) {
return parent;
}
- parent.set(this.key, change);
+ if (this.key) {
+ parent.set(this.key, change);
+ }
this.targetClassName = change._targetClassName;
return parent;
}
@@ -99,7 +101,9 @@ class ParseRelation {
if (objects.length === 0) {
return;
}
- this.parent.set(this.key, change);
+ if (this.key) {
+ this.parent.set(this.key, change);
+ }
this.targetClassName = change._targetClassName;
}
@@ -108,7 +112,7 @@ class ParseRelation {
*
* @returns {object} JSON representation of Relation
*/
- toJSON(): { __type: 'Relation', className: ?string } {
+ toJSON(): { __type: 'Relation', className: string | null } {
return {
__type: 'Relation',
className: this.targetClassName,
diff --git a/src/ParseRole.js b/src/ParseRole.ts
similarity index 94%
rename from src/ParseRole.js
rename to src/ParseRole.ts
index fee282395..9dbd00315 100644
--- a/src/ParseRole.js
+++ b/src/ParseRole.ts
@@ -2,9 +2,9 @@
* @flow
*/
+import ParseObject from './ParseObject';
import ParseACL from './ParseACL';
import ParseError from './ParseError';
-import ParseObject from './ParseObject';
import type { AttributeMap } from './ObjectStateMutations';
import type ParseRelation from './ParseRelation';
@@ -42,7 +42,7 @@ class ParseRole extends ParseObject {
*
* @returns {string} the name of the role.
*/
- getName(): ?string {
+ getName(): string | null {
const name = this.get('name');
if (name == null || typeof name === 'string') {
return name;
@@ -67,7 +67,7 @@ class ParseRole extends ParseObject {
* callbacks.
* @returns {(ParseObject|boolean)} true if the set succeeded.
*/
- setName(name: string, options?: mixed): ParseObject | boolean {
+ setName(name: string, options?: any): ParseObject | boolean {
this._validateName(name);
return this.set('name', name, options);
}
@@ -114,8 +114,8 @@ class ParseRole extends ParseObject {
}
}
- validate(attrs: AttributeMap, options?: mixed): ParseError | boolean {
- const isInvalid = super.validate(attrs, options);
+ validate(attrs: AttributeMap, options?: any): ParseError | boolean {
+ const isInvalid = (super.validate as typeof this['validate'])(attrs, options);
if (isInvalid) {
return isInvalid;
}
@@ -142,5 +142,4 @@ class ParseRole extends ParseObject {
}
ParseObject.registerSubclass('_Role', ParseRole);
-
export default ParseRole;
diff --git a/src/ParseSchema.js b/src/ParseSchema.ts
similarity index 93%
rename from src/ParseSchema.js
rename to src/ParseSchema.ts
index 089cddd32..b878736c6 100644
--- a/src/ParseSchema.js
+++ b/src/ParseSchema.ts
@@ -21,11 +21,13 @@ const FIELD_TYPES = [
'Object',
'Pointer',
'Relation',
-];
+] as const;
+type ValidFieldType = typeof FIELD_TYPES[number];
type FieldOptions = {
- required: boolean,
- defaultValue: mixed,
+ required?: boolean,
+ defaultValue?: any,
+ targetClass?: string,
};
/**
@@ -47,9 +49,9 @@ type FieldOptions = {
*/
class ParseSchema {
className: string;
- _fields: { [key: string]: mixed };
- _indexes: { [key: string]: mixed };
- _clp: { [key: string]: mixed };
+ _fields: { [key: string]: any };
+ _indexes: { [key: string]: any };
+ _clp: { [key: string]: any };
/**
* @param {string} className Parse Class string.
@@ -212,7 +214,7 @@ class ParseSchema {
*
* @returns {Parse.Schema} Returns the schema, so you can chain this call.
*/
- addField(name: string, type: string, options: FieldOptions = {}) {
+ addField(name: string, type: ValidFieldType, options: FieldOptions = {}) {
type = type || 'String';
if (!name) {
@@ -222,12 +224,14 @@ class ParseSchema {
throw new Error(`${type} is not a valid type.`);
}
if (type === 'Pointer') {
- return this.addPointer(name, options.targetClass, options);
+ return this.addPointer(name, options.targetClass!, options);
}
if (type === 'Relation') {
- return this.addRelation(name, options.targetClass, options);
+ return this.addRelation(name, options.targetClass);
}
- const fieldOptions = { type };
+ const fieldOptions: Partial & {
+ type: ValidFieldType,
+ } = { type };
if (typeof options.required === 'boolean') {
fieldOptions.required = options.required;
@@ -404,7 +408,9 @@ class ParseSchema {
if (!targetClass) {
throw new Error('You need to set the targetClass of the Pointer.');
}
- const fieldOptions = { type: 'Pointer', targetClass };
+ const fieldOptions: Partial & {
+ type: ValidFieldType,
+ } = { type: 'Pointer', targetClass };
if (typeof options.required === 'boolean') {
fieldOptions.required = options.required;
@@ -466,30 +472,30 @@ class ParseSchema {
}
const DefaultController = {
- send(className: string, method: string, params: any = {}): Promise {
+ send(className: string, method: string, params: any = {}): Promise {
const RESTController = CoreManager.getRESTController();
return RESTController.request(method, `schemas/${className}`, params, {
useMasterKey: true,
});
},
- get(className: string): Promise {
+ get(className: string): Promise<{ results: ParseSchema[] }> {
return this.send(className, 'GET');
},
- create(className: string, params: any): Promise {
+ create(className: string, params: any): Promise {
return this.send(className, 'POST', params);
},
- update(className: string, params: any): Promise {
+ update(className: string, params: any): Promise {
return this.send(className, 'PUT', params);
},
- delete(className: string): Promise {
+ delete(className: string): Promise {
return this.send(className, 'DELETE');
},
- purge(className: string): Promise {
+ purge(className: string): Promise {
const RESTController = CoreManager.getRESTController();
return RESTController.request('DELETE', `purge/${className}`, {}, { useMasterKey: true });
},
diff --git a/src/ParseSession.ts b/src/ParseSession.ts
index 51b001742..ab64e43a3 100644
--- a/src/ParseSession.ts
+++ b/src/ParseSession.ts
@@ -57,7 +57,7 @@ class ParseSession extends ParseObject {
options = options || {};
const controller = CoreManager.getSessionController();
- const sessionOptions = {};
+ const sessionOptions: FullOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
sessionOptions.useMasterKey = options.useMasterKey;
}
@@ -65,7 +65,7 @@ class ParseSession extends ParseObject {
if (!user) {
return Promise.reject('There is no current user.');
}
- sessionOptions.sessionToken = user.getSessionToken();
+ sessionOptions.sessionToken = user.getSessionToken() || undefined;
return controller.getSession(sessionOptions);
});
}
diff --git a/src/ParseUser.js b/src/ParseUser.ts
similarity index 92%
rename from src/ParseUser.js
rename to src/ParseUser.ts
index 8ba9ba8c0..1bd4bf1af 100644
--- a/src/ParseUser.js
+++ b/src/ParseUser.ts
@@ -12,14 +12,27 @@ import Storage from './Storage';
import type { AttributeMap } from './ObjectStateMutations';
import type { RequestOptions, FullOptions } from './RESTController';
-export type AuthData = ?{ [key: string]: mixed };
+export type AuthData = { [key: string]: any };
+
+export type AuthProviderType = {
+ authenticate?(options: {
+ error?: (provider: AuthProviderType, error: string | any) => void,
+ success?: (provider: AuthProviderType, result: AuthData) => void,
+ }): void,
+
+ restoreAuthentication(authData: any): boolean;
+ /** Returns the AuthType of this provider */
+ getAuthType(): string;
+ deauthenticate?(): void;
+};
+
const CURRENT_USER_KEY = 'currentUser';
let canUseCurrentUser = !CoreManager.get('IS_NODE');
let currentUserCacheMatchesDisk = false;
-let currentUserCache = null;
+let currentUserCache: ParseUser | null = null;
-const authProviders = {};
+const authProviders: { [key: string]: AuthProviderType } = {};
/**
* A Parse.User object is a local representation of a user persisted to the
@@ -35,7 +48,7 @@ class ParseUser extends ParseObject {
/**
* @param {object} attributes The initial set of data to store in the user.
*/
- constructor(attributes: ?AttributeMap) {
+ constructor(attributes?: AttributeMap) {
super('_User');
if (attributes && typeof attributes === 'object') {
if (!this.set(attributes || {})) {
@@ -54,7 +67,7 @@ class ParseUser extends ParseObject {
_upgradeToRevocableSession(options: RequestOptions): Promise {
options = options || {};
- const upgradeOptions = {};
+ const upgradeOptions: RequestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
upgradeOptions.useMasterKey = options.useMasterKey;
}
@@ -79,12 +92,12 @@ class ParseUser extends ParseObject {
* @returns {Promise} A promise that is fulfilled with the user is linked
*/
linkWith(
- provider: any,
- options: { authData?: AuthData },
- saveOpts?: FullOptions = {}
+ provider: AuthProviderType,
+ options: { authData?: AuthData | null },
+ saveOpts: FullOptions = {}
): Promise {
saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || '';
- let authType;
+ let authType: string;
if (typeof provider === 'string') {
authType = provider;
if (authProviders[provider]) {
@@ -121,9 +134,9 @@ class ParseUser extends ParseObject {
});
} else {
return new Promise((resolve, reject) => {
- provider.authenticate({
+ provider.authenticate!({
success: (provider, result) => {
- const opts = {};
+ const opts: { authData?: AuthData } = {};
opts.authData = result;
this.linkWith(provider, opts, saveOpts).then(
() => {
@@ -152,7 +165,7 @@ class ParseUser extends ParseObject {
_linkWith(
provider: any,
options: { authData?: AuthData },
- saveOpts?: FullOptions = {}
+ saveOpts: FullOptions = {}
): Promise {
return this.linkWith(provider, options, saveOpts);
}
@@ -163,7 +176,7 @@ class ParseUser extends ParseObject {
*
* @param provider
*/
- _synchronizeAuthData(provider: string) {
+ _synchronizeAuthData(provider: string | AuthProviderType) {
if (!this.isCurrent() || !provider) {
return;
}
@@ -336,7 +349,7 @@ class ParseUser extends ParseObject {
*
* @returns {string}
*/
- getUsername(): ?string {
+ getUsername(): string | null {
const username = this.get('username');
if (username == null || typeof username === 'string') {
return username;
@@ -368,7 +381,7 @@ class ParseUser extends ParseObject {
*
* @returns {string} User's Email
*/
- getEmail(): ?string {
+ getEmail(): string | null {
const email = this.get('email');
if (email == null || typeof email === 'string') {
return email;
@@ -393,7 +406,7 @@ class ParseUser extends ParseObject {
*
* @returns {string} the session token, or undefined
*/
- getSessionToken(): ?string {
+ getSessionToken(): string | null {
const token = this.get('sessionToken');
if (token == null || typeof token === 'string') {
return token;
@@ -424,10 +437,10 @@ class ParseUser extends ParseObject {
* @returns {Promise} A promise that is fulfilled when the signup
* finishes.
*/
- signUp(attrs: AttributeMap, options?: FullOptions): Promise {
+ signUp(attrs: AttributeMap, options?: FullOptions & { context?: AttributeMap }): Promise {
options = options || {};
- const signupOptions = {};
+ const signupOptions: FullOptions & { context?: AttributeMap } = {};
if (options.hasOwnProperty('useMasterKey')) {
signupOptions.useMasterKey = options.useMasterKey;
}
@@ -456,10 +469,9 @@ class ParseUser extends ParseObject {
* @returns {Promise} A promise that is fulfilled with the user when
* the login is complete.
*/
- logIn(options?: FullOptions): Promise {
- options = options || {};
+ logIn(options: FullOptions & { context?: AttributeMap } = {}): Promise {
- const loginOptions = { usePost: true };
+ const loginOptions: { usePost: boolean, context?: AttributeMap } & FullOptions = { usePost: true };
if (options.hasOwnProperty('useMasterKey')) {
loginOptions.useMasterKey = options.useMasterKey;
}
@@ -467,7 +479,7 @@ class ParseUser extends ParseObject {
loginOptions.installationId = options.installationId;
}
if (options.hasOwnProperty('usePost')) {
- loginOptions.usePost = options.usePost;
+ loginOptions.usePost = options.usePost!;
}
if (
options.hasOwnProperty('context') &&
@@ -486,11 +498,11 @@ class ParseUser extends ParseObject {
* @param {...any} args
* @returns {Promise}
*/
- async save(...args: Array): Promise {
+ async save(...args: Array): Promise {
await super.save.apply(this, args);
const current = await this.isCurrentAsync();
if (current) {
- return CoreManager.getUserController().updateUserOnDisk(this);
+ return CoreManager.getUserController().updateUserOnDisk(this) as Promise;
}
return this;
}
@@ -500,9 +512,9 @@ class ParseUser extends ParseObject {
* the current user when it is destroyed
*
* @param {...any} args
- * @returns {Parse.User}
+ * @returns {Parse.User|void}
*/
- async destroy(...args: Array): Promise {
+ async destroy(...args: Array): Promise {
await super.destroy.apply(this, args);
const current = await this.isCurrentAsync();
if (current) {
@@ -606,7 +618,7 @@ class ParseUser extends ParseObject {
* @static
* @returns {Parse.Object} The currently logged in Parse.User.
*/
- static current(): ?ParseUser {
+ static current(): ParseUser | null {
if (!canUseCurrentUser) {
return null;
}
@@ -621,7 +633,7 @@ class ParseUser extends ParseObject {
* @returns {Promise} A Promise that is resolved with the currently
* logged in Parse User
*/
- static currentAsync(): Promise {
+ static currentAsync(): Promise {
if (!canUseCurrentUser) {
return Promise.resolve(null);
}
@@ -758,7 +770,7 @@ class ParseUser extends ParseObject {
* @static
* @returns {Promise} A promise that is fulfilled with the user is fetched.
*/
- static me(sessionToken: string, options?: RequestOptions = {}) {
+ static me(sessionToken: string, options: RequestOptions = {}) {
const controller = CoreManager.getUserController();
const meOptions: RequestOptions = {
sessionToken: sessionToken,
@@ -833,7 +845,7 @@ class ParseUser extends ParseObject {
static requestPasswordReset(email: string, options?: RequestOptions) {
options = options || {};
- const requestOptions = {};
+ const requestOptions: { useMasterKey?: boolean } = {};
if (options.hasOwnProperty('useMasterKey')) {
requestOptions.useMasterKey = options.useMasterKey;
}
@@ -854,7 +866,7 @@ class ParseUser extends ParseObject {
static requestEmailVerification(email: string, options?: RequestOptions) {
options = options || {};
- const requestOptions = {};
+ const requestOptions: RequestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
requestOptions.useMasterKey = options.useMasterKey;
}
@@ -873,7 +885,7 @@ class ParseUser extends ParseObject {
* @returns {Promise} A promise that is fulfilled with a user
* when the password is correct.
*/
- static verifyPassword(username: string, password: string, options?: RequestOptions) {
+ static verifyPassword(username: string, password: string, options?: RequestOptions): Promise {
if (typeof username !== 'string') {
return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.'));
}
@@ -884,7 +896,7 @@ class ParseUser extends ParseObject {
options = options || {};
- const verificationOption = {};
+ const verificationOption: RequestOptions = {};
if (options.hasOwnProperty('useMasterKey')) {
verificationOption.useMasterKey = options.useMasterKey;
}
@@ -1032,7 +1044,7 @@ const DefaultController = {
return DefaultController.updateUserOnDisk(user);
},
- currentUser(): ?ParseUser {
+ currentUser(): ParseUser | null {
if (currentUserCache) {
return currentUserCache;
}
@@ -1042,7 +1054,7 @@ const DefaultController = {
if (Storage.async()) {
throw new Error(
'Cannot call currentUser() when using a platform with an async ' +
- 'storage system. Call currentUserAsync() instead.'
+ 'storage system. Call currentUserAsync() instead.'
);
}
const path = Storage.generatePath(CURRENT_USER_KEY);
@@ -1056,27 +1068,27 @@ const DefaultController = {
const crypto = CoreManager.getCryptoController();
userData = crypto.decrypt(userData, CoreManager.get('ENCRYPTED_KEY'));
}
- userData = JSON.parse(userData);
- if (!userData.className) {
- userData.className = '_User';
+ const userDataObj = JSON.parse(userData);
+ if (!userDataObj.className) {
+ userDataObj.className = '_User';
}
- if (userData._id) {
- if (userData.objectId !== userData._id) {
- userData.objectId = userData._id;
+ if (userDataObj._id) {
+ if (userDataObj.objectId !== userDataObj._id) {
+ userDataObj.objectId = userDataObj._id;
}
- delete userData._id;
+ delete userDataObj._id;
}
- if (userData._sessionToken) {
- userData.sessionToken = userData._sessionToken;
- delete userData._sessionToken;
+ if (userDataObj._sessionToken) {
+ userDataObj.sessionToken = userDataObj._sessionToken;
+ delete userDataObj._sessionToken;
}
- const current = ParseObject.fromJSON(userData);
+ const current = ParseObject.fromJSON(userDataObj) as ParseUser;
currentUserCache = current;
current._synchronizeAllAuthData();
return current;
},
- currentUserAsync(): Promise {
+ currentUserAsync(): Promise {
if (currentUserCache) {
return Promise.resolve(currentUserCache);
}
@@ -1094,21 +1106,21 @@ const DefaultController = {
const crypto = CoreManager.getCryptoController();
userData = crypto.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY'));
}
- userData = JSON.parse(userData);
- if (!userData.className) {
- userData.className = '_User';
+ const userDataObj = JSON.parse(userData);
+ if (!userDataObj.className) {
+ userDataObj.className = '_User';
}
- if (userData._id) {
- if (userData.objectId !== userData._id) {
- userData.objectId = userData._id;
+ if (userDataObj._id) {
+ if (userDataObj.objectId !== userDataObj._id) {
+ userDataObj.objectId = userDataObj._id;
}
- delete userData._id;
+ delete userDataObj._id;
}
- if (userData._sessionToken) {
- userData.sessionToken = userData._sessionToken;
- delete userData._sessionToken;
+ if (userDataObj._sessionToken) {
+ userDataObj.sessionToken = userDataObj._sessionToken;
+ delete userDataObj._sessionToken;
}
- const current = ParseObject.fromJSON(userData);
+ const current = ParseObject.fromJSON(userDataObj) as ParseUser;
currentUserCache = current;
current._synchronizeAllAuthData();
return Promise.resolve(current);
@@ -1206,7 +1218,7 @@ const DefaultController = {
});
},
- logOut(options: RequestOptions): Promise {
+ logOut(options: RequestOptions): Promise {
const RESTController = CoreManager.getRESTController();
if (options.sessionToken) {
return RESTController.request('POST', 'logout', {}, options);
@@ -1258,7 +1270,7 @@ const DefaultController = {
return Promise.resolve(user);
},
- linkWith(user: ParseUser, authData: AuthData, options: FullOptions) {
+ linkWith(user: ParseUser, authData: AuthData, options?: FullOptions) {
return user.save({ authData }, options).then(() => {
if (canUseCurrentUser) {
return DefaultController.setCurrentUser(user);
diff --git a/src/Push.js b/src/Push.ts
similarity index 86%
rename from src/Push.js
rename to src/Push.ts
index a565396be..d6b91b977 100644
--- a/src/Push.js
+++ b/src/Push.ts
@@ -3,6 +3,7 @@
*/
import CoreManager from './CoreManager';
+import ParseObject from './ParseObject';
import ParseQuery from './ParseQuery';
import type { WhereClause } from './ParseQuery';
@@ -49,9 +50,9 @@ export type PushData = {
* be used for this request.
*
* @returns {Promise} A promise that is fulfilled when the push request
- * completes.
+ * completes., returns `pushStatusId`
*/
-export function send(data: PushData, options?: FullOptions = {}): Promise {
+export function send(data: PushData, options: FullOptions = {}): Promise {
if (data.where && data.where instanceof ParseQuery) {
data.where = data.where.toJSON().where;
}
@@ -70,7 +71,7 @@ export function send(data: PushData, options?: FullOptions = {}): Promise {
const pushOptions = { useMasterKey: true };
if (options.hasOwnProperty('useMasterKey')) {
- pushOptions.useMasterKey = options.useMasterKey;
+ pushOptions.useMasterKey = options.useMasterKey!;
}
return CoreManager.getPushController().send(data, pushOptions);
@@ -89,10 +90,10 @@ export function send(data: PushData, options?: FullOptions = {}): Promise {
*
* @returns {Parse.Object} Status of Push.
*/
-export function getPushStatus(pushStatusId: string, options?: FullOptions = {}): Promise {
+export function getPushStatus(pushStatusId: string, options: FullOptions = {}): Promise {
const pushOptions = { useMasterKey: true };
if (options.hasOwnProperty('useMasterKey')) {
- pushOptions.useMasterKey = options.useMasterKey;
+ pushOptions.useMasterKey = options.useMasterKey!;
}
const query = new ParseQuery('_PushStatus');
return query.get(pushStatusId, pushOptions);
@@ -100,8 +101,8 @@ export function getPushStatus(pushStatusId: string, options?: FullOptions = {}):
const DefaultController = {
async send(data: PushData, options?: FullOptions) {
- options.returnStatus = true;
- const response = await CoreManager.getRESTController().request('POST', 'push', data, options);
+ const myOptions = { ...options, returnStatus: true };
+ const response = await CoreManager.getRESTController().request('POST', 'push', data, myOptions);
return response._headers?.['X-Parse-Push-Status-Id'];
},
};
diff --git a/src/RESTController.js b/src/RESTController.ts
similarity index 91%
rename from src/RESTController.js
rename to src/RESTController.ts
index 75b30a759..c0ce2649f 100644
--- a/src/RESTController.js
+++ b/src/RESTController.ts
@@ -2,7 +2,7 @@
* @flow
*/
/* global XMLHttpRequest, XDomainRequest */
-const uuidv4 = require('./uuid');
+import uuidv4 from './uuid';
import CoreManager from './CoreManager';
import ParseError from './ParseError';
@@ -28,9 +28,10 @@ export type FullOptions = {
installationId?: string,
progress?: any,
usePost?: boolean,
+ requestTask?: any,
};
-let XHR = null;
+let XHR: typeof XMLHttpRequest = null as any;
if (typeof XMLHttpRequest !== 'undefined') {
XHR = XMLHttpRequest;
}
@@ -42,12 +43,14 @@ if (process.env.PARSE_BUILD === 'weapp') {
}
let useXDomainRequest = false;
+// @ts-ignore
if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) {
useXDomainRequest = true;
}
function ajaxIE9(method: string, url: string, data: any, headers?: any, options?: FullOptions) {
return new Promise((resolve, reject) => {
+ // @ts-ignore
const xdr = new XDomainRequest();
xdr.onload = function () {
let response;
@@ -77,7 +80,9 @@ function ajaxIE9(method: string, url: string, data: any, headers?: any, options?
};
xdr.open(method, url);
xdr.send(data);
+ // @ts-ignore
if (options && typeof options.requestTask === 'function') {
+ // @ts-ignore
options.requestTask(xdr);
}
});
@@ -101,7 +106,7 @@ const RESTController = {
const xhr = new XHR();
xhr.onreadystatechange = function () {
- if (xhr.readyState !== 4 || handled || xhr._aborted) {
+ if (xhr.readyState !== 4 || handled || (xhr as any)._aborted) {
return;
}
handled = true;
@@ -112,8 +117,8 @@ const RESTController = {
response = JSON.parse(xhr.responseText);
headers = {};
if (typeof xhr.getResponseHeader === 'function' && xhr.getResponseHeader('access-control-expose-headers')) {
- const responseHeaders = xhr.getResponseHeader('access-control-expose-headers').split(', ');
- responseHeaders.forEach(header => {
+ const responseHeaders = xhr.getResponseHeader('access-control-expose-headers')?.split(', ');
+ responseHeaders?.forEach(header => {
headers[header] = xhr.getResponseHeader(header.toLowerCase());
});
}
@@ -203,7 +208,7 @@ const RESTController = {
return promise;
},
- request(method: string, path: string, data: mixed, options?: RequestOptions) {
+ request(method: string, path: string, data: any, options?: RequestOptions) {
options = options || {};
let url = CoreManager.get('SERVER_URL');
if (url[url.length - 1] !== '/') {
@@ -211,7 +216,18 @@ const RESTController = {
}
url += path;
- const payload = {};
+ type PayloadType = {
+ _context?: any,
+ _method?: string,
+ _ApplicationId: string,
+ _JavaScriptKey?: string,
+ _ClientVersion: string,
+ _MasterKey?: string,
+ _RevocableSession?: string,
+ _InstallationId?: string,
+ _SessionToken?: string,
+ };
+ const payload: Partial = {};
if (data && typeof data === 'object') {
for (const k in data) {
payload[k] = data[k];
@@ -254,7 +270,7 @@ const RESTController = {
}
const installationId = options.installationId;
- let installationIdPromise;
+ let installationIdPromise: Promise;
if (installationId && typeof installationId === 'string') {
installationIdPromise = Promise.resolve(installationId);
} else {
@@ -297,7 +313,7 @@ const RESTController = {
.catch(RESTController.handleError);
},
- handleError(response) {
+ handleError(response: any) {
// Transform the error into an instance of ParseError by trying to parse
// the error string as JSON
let error;
@@ -332,3 +348,4 @@ const RESTController = {
};
module.exports = RESTController;
+export default RESTController;
diff --git a/src/SingleInstanceStateController.js b/src/SingleInstanceStateController.ts
similarity index 92%
rename from src/SingleInstanceStateController.js
rename to src/SingleInstanceStateController.ts
index 3dd9c2cc7..3be62c78d 100644
--- a/src/SingleInstanceStateController.js
+++ b/src/SingleInstanceStateController.ts
@@ -18,7 +18,7 @@ let objectState: {
},
} = {};
-export function getState(obj: ObjectIdentifier): ?State {
+export function getState(obj: ObjectIdentifier): State | null {
const classData = objectState[obj.className];
if (classData) {
return classData[obj.id] || null;
@@ -41,7 +41,7 @@ export function initializeState(obj: ObjectIdentifier, initial?: State): State {
return state;
}
-export function removeState(obj: ObjectIdentifier): ?State {
+export function removeState(obj: ObjectIdentifier): State | null {
const state = getState(obj);
if (state === null) {
return null;
@@ -71,7 +71,7 @@ export function getPendingOps(obj: ObjectIdentifier): Array {
return [{}];
}
-export function setPendingOp(obj: ObjectIdentifier, attr: string, op: ?Op) {
+export function setPendingOp(obj: ObjectIdentifier, attr: string, op?: Op) {
const pendingOps = initializeState(obj).pendingOps;
ObjectStateMutations.setPendingOp(pendingOps, attr, op);
}
@@ -81,7 +81,7 @@ export function pushPendingState(obj: ObjectIdentifier) {
ObjectStateMutations.pushPendingState(pendingOps);
}
-export function popPendingState(obj: ObjectIdentifier): OpsMap {
+export function popPendingState(obj: ObjectIdentifier): OpsMap | undefined {
const pendingOps = initializeState(obj).pendingOps;
return ObjectStateMutations.popPendingState(pendingOps);
}
@@ -99,7 +99,7 @@ export function getObjectCache(obj: ObjectIdentifier): ObjectCache {
return {};
}
-export function estimateAttribute(obj: ObjectIdentifier, attr: string): mixed {
+export function estimateAttribute(obj: ObjectIdentifier, attr: string): any {
const serverData = getServerData(obj);
const pendingOps = getPendingOps(obj);
return ObjectStateMutations.estimateAttribute(
@@ -122,7 +122,7 @@ export function commitServerChanges(obj: ObjectIdentifier, changes: AttributeMap
ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes);
}
-export function enqueueTask(obj: ObjectIdentifier, task: () => Promise): Promise {
+export function enqueueTask(obj: ObjectIdentifier, task: () => Promise): Promise {
const state = initializeState(obj);
return state.tasks.enqueue(task);
}
diff --git a/src/Socket.weapp.js b/src/Socket.weapp.ts
similarity index 64%
rename from src/Socket.weapp.js
rename to src/Socket.weapp.ts
index d8d3884e7..239180300 100644
--- a/src/Socket.weapp.js
+++ b/src/Socket.weapp.ts
@@ -1,36 +1,51 @@
module.exports = class SocketWeapp {
- constructor(serverURL) {
+ onopen: () => void;
+ onmessage: () => void;
+ onclose: () => void;
+ onerror: () => void;
+
+ constructor(serverURL: string) {
this.onopen = () => {};
this.onmessage = () => {};
this.onclose = () => {};
this.onerror = () => {};
+ // @ts-ignore
wx.onSocketOpen(() => {
this.onopen();
});
+ // @ts-ignore
wx.onSocketMessage(msg => {
+ // @ts-ignore
this.onmessage(msg);
});
+ // @ts-ignore
wx.onSocketClose((event) => {
+ // @ts-ignore
this.onclose(event);
});
+ // @ts-ignore
wx.onSocketError(error => {
+ // @ts-ignore
this.onerror(error);
});
+ // @ts-ignore
wx.connectSocket({
url: serverURL,
});
}
send(data) {
+ // @ts-ignore
wx.sendSocketMessage({ data });
}
close() {
+ // @ts-ignore
wx.closeSocket();
}
};
diff --git a/src/Storage.js b/src/Storage.ts
similarity index 73%
rename from src/Storage.js
rename to src/Storage.ts
index 67392c249..bcbd094c9 100644
--- a/src/Storage.js
+++ b/src/Storage.ts
@@ -4,13 +4,39 @@
import CoreManager from './CoreManager';
+export type StorageController =
+ | {
+ async: 0,
+ getItem: (path: string) => string | null,
+ setItem: (path: string, value: string) => void,
+ removeItem: (path: string) => void,
+ getItemAsync?: (path: string) => Promise,
+ setItemAsync?: (path: string, value: string) => Promise,
+ removeItemAsync?: (path: string) => Promise,
+ clear: () => void,
+ getAllKeys?: () => Array
+ getAllKeysAsync?: () => Promise>
+ }
+ | {
+ async: 1,
+ getItem?: (path: string) => string | null,
+ setItem?: (path: string, value: string) => void,
+ removeItem?: (path: string) => void,
+ getItemAsync: (path: string) => Promise,
+ setItemAsync: (path: string, value: string) => Promise,
+ removeItemAsync: (path: string) => Promise,
+ clear: () => void,
+ getAllKeys?: () => Array
+ getAllKeysAsync?: () => Promise>
+ };
+
const Storage = {
async(): boolean {
const controller = CoreManager.getStorageController();
return !!controller.async;
},
- getItem(path: string): ?string {
+ getItem(path: string): string | null {
const controller = CoreManager.getStorageController();
if (controller.async === 1) {
throw new Error('Synchronous storage is not supported by the current storage controller');
@@ -18,7 +44,7 @@ const Storage = {
return controller.getItem(path);
},
- getItemAsync(path: string): Promise {
+ getItemAsync(path: string): Promise {
const controller = CoreManager.getStorageController();
if (controller.async === 1) {
return controller.getItemAsync(path);
@@ -63,15 +89,15 @@ const Storage = {
if (controller.async === 1) {
throw new Error('Synchronous storage is not supported by the current storage controller');
}
- return controller.getAllKeys();
+ return controller.getAllKeys!();
},
getAllKeysAsync(): Promise> {
const controller = CoreManager.getStorageController();
if (controller.async === 1) {
- return controller.getAllKeysAsync();
+ return controller.getAllKeysAsync!();
}
- return Promise.resolve(controller.getAllKeys());
+ return Promise.resolve(controller.getAllKeys!());
},
generatePath(path: string): string {
diff --git a/src/StorageController.browser.js b/src/StorageController.browser.ts
similarity index 80%
rename from src/StorageController.browser.js
rename to src/StorageController.browser.ts
index 0fdcd37b7..275d63715 100644
--- a/src/StorageController.browser.js
+++ b/src/StorageController.browser.ts
@@ -7,7 +7,7 @@
const StorageController = {
async: 0,
- getItem(path: string): ?string {
+ getItem(path: string): string | null {
return localStorage.getItem(path);
},
@@ -25,9 +25,9 @@ const StorageController = {
},
getAllKeys() {
- const keys = [];
+ const keys: string[] = [];
for (let i = 0; i < localStorage.length; i += 1) {
- keys.push(localStorage.key(i));
+ keys.push(localStorage.key(i) as string);
}
return keys;
},
@@ -38,3 +38,4 @@ const StorageController = {
};
module.exports = StorageController;
+export default StorageController;
diff --git a/src/StorageController.default.js b/src/StorageController.default.ts
similarity index 89%
rename from src/StorageController.default.js
rename to src/StorageController.default.ts
index cb21dd54f..c6ab92ceb 100644
--- a/src/StorageController.default.js
+++ b/src/StorageController.default.ts
@@ -8,7 +8,7 @@ const memMap = {};
const StorageController = {
async: 0,
- getItem(path: string): ?string {
+ getItem(path: string): string | null {
if (memMap.hasOwnProperty(path)) {
return memMap[path];
}
@@ -37,3 +37,4 @@ const StorageController = {
};
module.exports = StorageController;
+export default StorageController;
diff --git a/src/StorageController.react-native.js b/src/StorageController.react-native.ts
similarity index 51%
rename from src/StorageController.react-native.js
rename to src/StorageController.react-native.ts
index e3ee63dce..f44b72bbb 100644
--- a/src/StorageController.react-native.js
+++ b/src/StorageController.react-native.ts
@@ -7,33 +7,33 @@ import CoreManager from './CoreManager';
const StorageController = {
async: 1,
- getItemAsync(path: string): Promise {
+ getItemAsync(path: string): Promise {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().getItem(path, (err, value) => {
+ CoreManager.getAsyncStorage()!.getItem(path, (err, value) => {
if (err) {
reject(err);
} else {
- resolve(value);
+ resolve(value || null);
}
});
});
},
- setItemAsync(path: string, value: string): Promise {
+ setItemAsync(path: string, value: string): Promise {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().setItem(path, value, (err, value) => {
+ CoreManager.getAsyncStorage()!.setItem(path, value, (err) => {
if (err) {
reject(err);
} else {
- resolve(value);
+ resolve();
}
});
});
},
- removeItemAsync(path: string): Promise {
+ removeItemAsync(path: string): Promise {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().removeItem(path, err => {
+ CoreManager.getAsyncStorage()!.removeItem(path, err => {
if (err) {
reject(err);
} else {
@@ -43,33 +43,33 @@ const StorageController = {
});
},
- getAllKeysAsync(): Promise {
+ getAllKeysAsync(): Promise {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().getAllKeys((err, keys) => {
+ CoreManager.getAsyncStorage()!.getAllKeys((err, keys) => {
if (err) {
reject(err);
} else {
- resolve(keys);
+ resolve(keys || null);
}
});
});
},
- multiGet(keys: Array): Promise>> {
+ multiGet(keys: Array): Promise {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().multiGet(keys, (err, result) => {
+ CoreManager.getAsyncStorage()!.multiGet(keys, (err, result) => {
if (err) {
reject(err);
} else {
- resolve(result);
+ resolve(result || null);
}
});
});
},
- multiRemove(keys: Array): Promise {
+ multiRemove(keys: Array): Promise> {
return new Promise((resolve, reject) => {
- CoreManager.getAsyncStorage().multiRemove(keys, err => {
+ CoreManager.getAsyncStorage()!.multiRemove(keys, err => {
if (err) {
reject(err);
} else {
@@ -80,8 +80,9 @@ const StorageController = {
},
clear() {
- return CoreManager.getAsyncStorage().clear();
+ return CoreManager.getAsyncStorage()!.clear();
},
};
module.exports = StorageController;
+export default StorageController;
diff --git a/src/StorageController.weapp.js b/src/StorageController.weapp.ts
similarity index 78%
rename from src/StorageController.weapp.js
rename to src/StorageController.weapp.ts
index 321172c4e..c987c3b40 100644
--- a/src/StorageController.weapp.js
+++ b/src/StorageController.weapp.ts
@@ -6,12 +6,14 @@
const StorageController = {
async: 0,
- getItem(path: string): ?string {
+ getItem(path: string): string | null {
+ // @ts-ignore
return wx.getStorageSync(path);
},
setItem(path: string, value: string) {
try {
+ // @ts-ignore
wx.setStorageSync(path, value);
} catch (e) {
// Quota exceeded
@@ -19,15 +21,18 @@ const StorageController = {
},
removeItem(path: string) {
+ // @ts-ignore
wx.removeStorageSync(path);
},
getAllKeys() {
+ // @ts-ignore
const res = wx.getStorageInfoSync();
return res.keys;
},
clear() {
+ // @ts-ignore
wx.clearStorageSync();
},
};
diff --git a/src/TaskQueue.js b/src/TaskQueue.ts
similarity index 80%
rename from src/TaskQueue.js
rename to src/TaskQueue.ts
index eedd769fe..55d45b757 100644
--- a/src/TaskQueue.js
+++ b/src/TaskQueue.ts
@@ -4,8 +4,8 @@
import { resolvingPromise } from './promiseUtils';
type Task = {
- task: () => Promise,
- _completion: Promise,
+ task: () => Promise,
+ _completion: ReturnType>,
};
class TaskQueue {
@@ -15,8 +15,8 @@ class TaskQueue {
this.queue = [];
}
- enqueue(task: () => Promise): Promise {
- const taskComplete = new resolvingPromise();
+ enqueue(task: () => Promise): Promise {
+ const taskComplete = resolvingPromise();
this.queue.push({
task: task,
_completion: taskComplete,
@@ -55,3 +55,4 @@ class TaskQueue {
}
module.exports = TaskQueue;
+export default TaskQueue;
diff --git a/src/UniqueInstanceStateController.js b/src/UniqueInstanceStateController.ts
similarity index 92%
rename from src/UniqueInstanceStateController.js
rename to src/UniqueInstanceStateController.ts
index aaf21da10..56763e3ae 100644
--- a/src/UniqueInstanceStateController.js
+++ b/src/UniqueInstanceStateController.ts
@@ -11,7 +11,7 @@ import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMuta
let objectState = new WeakMap();
-export function getState(obj: ParseObject): ?State {
+export function getState(obj: ParseObject): State | null {
const classData = objectState.get(obj);
return classData || null;
}
@@ -35,7 +35,7 @@ export function initializeState(obj: ParseObject, initial?: State): State {
return state;
}
-export function removeState(obj: ParseObject): ?State {
+export function removeState(obj: ParseObject): State | null {
const state = getState(obj);
if (state === null) {
return null;
@@ -65,7 +65,7 @@ export function getPendingOps(obj: ParseObject): Array {
return [{}];
}
-export function setPendingOp(obj: ParseObject, attr: string, op: ?Op) {
+export function setPendingOp(obj: ParseObject, attr: string, op?: Op) {
const pendingOps = initializeState(obj).pendingOps;
ObjectStateMutations.setPendingOp(pendingOps, attr, op);
}
@@ -75,7 +75,7 @@ export function pushPendingState(obj: ParseObject) {
ObjectStateMutations.pushPendingState(pendingOps);
}
-export function popPendingState(obj: ParseObject): OpsMap {
+export function popPendingState(obj: ParseObject): OpsMap | undefined {
const pendingOps = initializeState(obj).pendingOps;
return ObjectStateMutations.popPendingState(pendingOps);
}
@@ -93,7 +93,7 @@ export function getObjectCache(obj: ParseObject): ObjectCache {
return {};
}
-export function estimateAttribute(obj: ParseObject, attr: string): mixed {
+export function estimateAttribute(obj: ParseObject, attr: string): any {
const serverData = getServerData(obj);
const pendingOps = getPendingOps(obj);
return ObjectStateMutations.estimateAttribute(
@@ -116,7 +116,7 @@ export function commitServerChanges(obj: ParseObject, changes: AttributeMap) {
ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes);
}
-export function enqueueTask(obj: ParseObject, task: () => Promise): Promise {
+export function enqueueTask(obj: ParseObject, task: () => Promise): Promise {
const state = initializeState(obj);
return state.tasks.enqueue(task);
}
diff --git a/src/Xhr.weapp.js b/src/Xhr.weapp.ts
similarity index 81%
rename from src/Xhr.weapp.js
rename to src/Xhr.weapp.ts
index cb9f90121..033fe5267 100644
--- a/src/Xhr.weapp.js
+++ b/src/Xhr.weapp.ts
@@ -1,4 +1,24 @@
module.exports = class XhrWeapp {
+ UNSENT: number;
+ OPENED: number;
+ HEADERS_RECEIVED: number;
+ LOADING: number;
+ DONE: number;
+ header: {};
+ readyState: any;
+ status: number;
+ response: string;
+ responseType: string;
+ responseText: string;
+ responseHeader: {};
+ method: string;
+ url: string;
+ onabort: () => void;
+ onprogress: () => void;
+ onerror: () => void;
+ onreadystatechange: () => void;
+ requestTask: any;
+
constructor() {
this.UNSENT = 0;
this.OPENED = 1;
@@ -55,6 +75,7 @@ module.exports = class XhrWeapp {
}
send(data) {
+ // @ts-ignore
this.requestTask = wx.request({
url: this.url,
method: this.method,
@@ -71,6 +92,7 @@ module.exports = class XhrWeapp {
},
fail: err => {
this.requestTask = null;
+ // @ts-ignore
this.onerror(err);
},
});
@@ -80,6 +102,7 @@ module.exports = class XhrWeapp {
loaded: res.totalBytesWritten,
total: res.totalBytesExpectedToWrite,
};
+ // @ts-ignore
this.onprogress(event);
});
}
diff --git a/src/__tests__/escape-test.js b/src/__tests__/escape-test.js
index 11e6e07af..767d5723a 100644
--- a/src/__tests__/escape-test.js
+++ b/src/__tests__/escape-test.js
@@ -1,6 +1,6 @@
jest.autoMockOff();
-const escape = require('../escape.js').default;
+const escape = require('../escape').default;
describe('escape', () => {
it('escapes special HTML characters', () => {
diff --git a/src/arrayContainsObject.js b/src/arrayContainsObject.ts
similarity index 96%
rename from src/arrayContainsObject.js
rename to src/arrayContainsObject.ts
index ca9356849..9682cf108 100644
--- a/src/arrayContainsObject.js
+++ b/src/arrayContainsObject.ts
@@ -1,7 +1,3 @@
-/**
- * @flow
- */
-
import ParseObject from './ParseObject';
export default function arrayContainsObject(array: Array, object: ParseObject): boolean {
diff --git a/src/canBeSerialized.js b/src/canBeSerialized.ts
similarity index 100%
rename from src/canBeSerialized.js
rename to src/canBeSerialized.ts
diff --git a/src/decode.js b/src/decode.ts
similarity index 90%
rename from src/decode.js
rename to src/decode.ts
index 557002015..4fc5efd6b 100644
--- a/src/decode.js
+++ b/src/decode.ts
@@ -1,7 +1,6 @@
/**
* @flow
*/
-import ParseACL from './ParseACL'; // eslint-disable-line no-unused-vars
import ParseFile from './ParseFile';
import ParseGeoPoint from './ParseGeoPoint';
import ParsePolygon from './ParsePolygon';
@@ -9,12 +8,13 @@ import ParseObject from './ParseObject';
import { opFromJSON } from './ParseOp';
import ParseRelation from './ParseRelation';
+/** Decodes values from storage type */
export default function decode(value: any): any {
if (value === null || typeof value !== 'object' || value instanceof Date) {
return value;
}
if (Array.isArray(value)) {
- const dup = [];
+ const dup: any[] = [];
value.forEach((v, i) => {
dup[i] = decode(v);
});
@@ -31,7 +31,7 @@ export default function decode(value: any): any {
}
if (value.__type === 'Relation') {
// The parent and key fields will be populated by the parent
- const relation = new ParseRelation(null, null);
+ const relation = new ParseRelation(null, null); // null, null; since tests expect this.
relation.targetClassName = value.className;
return relation;
}
diff --git a/src/encode.js b/src/encode.ts
similarity index 93%
rename from src/encode.js
rename to src/encode.ts
index 0214990f5..140d54aa5 100644
--- a/src/encode.js
+++ b/src/encode.ts
@@ -11,11 +11,11 @@ import { Op } from './ParseOp';
import ParseRelation from './ParseRelation';
function encode(
- value: mixed,
+ value: any,
disallowObjects: boolean,
forcePointers: boolean,
- seen: Array,
- offline: boolean
+ seen: Array,
+ offline?: boolean
): any {
if (value instanceof ParseObject) {
if (disallowObjects) {
@@ -56,7 +56,7 @@ function encode(
if (isNaN(value)) {
throw new Error('Tried to encode an invalid date.');
}
- return { __type: 'Date', iso: (value: any).toJSON() };
+ return { __type: 'Date', iso: (value as Date).toJSON() };
}
if (
Object.prototype.toString.call(value) === '[object RegExp]' &&
@@ -83,10 +83,10 @@ function encode(
}
export default function (
- value: mixed,
+ value: any,
disallowObjects?: boolean,
forcePointers?: boolean,
- seen?: Array,
+ seen?: Array,
offline?: boolean
): any {
return encode(value, !!disallowObjects, !!forcePointers, seen || [], offline);
diff --git a/src/equals.js b/src/equals.ts
similarity index 95%
rename from src/equals.js
rename to src/equals.ts
index 3af927c99..234141519 100644
--- a/src/equals.js
+++ b/src/equals.ts
@@ -3,7 +3,7 @@ import ParseFile from './ParseFile';
import ParseGeoPoint from './ParseGeoPoint';
import ParseObject from './ParseObject';
-export default function equals(a, b) {
+export default function equals(a: any, b: any): boolean {
const toString = Object.prototype.toString;
if (toString.call(a) === '[object Date]' || toString.call(b) === '[object Date]') {
const dateA = new Date(a);
diff --git a/src/escape.js b/src/escape.ts
similarity index 100%
rename from src/escape.js
rename to src/escape.ts
diff --git a/src/isRevocableSession.js b/src/isRevocableSession.ts
similarity index 100%
rename from src/isRevocableSession.js
rename to src/isRevocableSession.ts
diff --git a/src/parseDate.js b/src/parseDate.ts
similarity index 90%
rename from src/parseDate.js
rename to src/parseDate.ts
index 04ff6ea7f..8de789d67 100644
--- a/src/parseDate.js
+++ b/src/parseDate.ts
@@ -2,7 +2,7 @@
* @flow
*/
-export default function parseDate(iso8601: string): ?Date {
+export default function parseDate(iso8601: string): Date | null {
const regexp = new RegExp(
'^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' +
'T' +
diff --git a/src/promiseUtils.js b/src/promiseUtils.ts
similarity index 62%
rename from src/promiseUtils.js
rename to src/promiseUtils.ts
index 176c32a0b..1302776b2 100644
--- a/src/promiseUtils.js
+++ b/src/promiseUtils.ts
@@ -1,30 +1,31 @@
// Create Deferred Promise
-export function resolvingPromise() {
- let res;
- let rej;
- const promise = new Promise((resolve, reject) => {
+export function resolvingPromise() {
+ let res: (val: T) => void;
+ let rej: (err: any) => void;
+ const promise = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
- promise.resolve = res;
- promise.reject = rej;
- return promise;
+ const ret: typeof promise & { resolve: (res: T) => void, reject: (err: any) => void } = promise as any;
+ ret.resolve = res!;
+ ret.reject = rej!;
+ return ret;
}
-export function when(promises) {
- let objects;
+export function when(promises: Promise | (Promise[]), ...others: Promise[]) {
+ let objects: Promise[];
const arrayArgument = Array.isArray(promises);
if (arrayArgument) {
objects = promises;
} else {
- objects = arguments;
+ objects = arguments as any as Promise[];
}
let total = objects.length;
let hadError = false;
- const results = [];
+ const results: any[] = [];
const returnValue = arrayArgument ? [results] : results;
- const errors = [];
+ const errors: any[] = [];
results.length = objects.length;
errors.length = objects.length;
@@ -32,7 +33,7 @@ export function when(promises) {
return Promise.resolve(returnValue);
}
- const promise = new resolvingPromise();
+ const promise = resolvingPromise();
const resolveOne = function () {
total--;
@@ -45,7 +46,7 @@ export function when(promises) {
}
};
- const chain = function (object, index) {
+ const chain = function (object: Promise, index: number) {
if (object && typeof object.then === 'function') {
object.then(
function (result) {
@@ -66,11 +67,10 @@ export function when(promises) {
for (let i = 0; i < objects.length; i++) {
chain(objects[i], i);
}
-
return promise;
}
-export function continueWhile(test, emitter) {
+export function continueWhile(test: () => boolean, emitter: () => Promise) {
if (test()) {
return emitter().then(() => {
return continueWhile(test, emitter);
diff --git a/src/unique.js b/src/unique.ts
similarity index 94%
rename from src/unique.js
rename to src/unique.ts
index 169c288f5..1ee8f2cb1 100644
--- a/src/unique.js
+++ b/src/unique.ts
@@ -6,7 +6,7 @@ import arrayContainsObject from './arrayContainsObject';
import ParseObject from './ParseObject';
export default function unique(arr: Array): Array {
- const uniques = [];
+ const uniques: T[] = [];
arr.forEach(value => {
if (value instanceof ParseObject) {
if (!arrayContainsObject(uniques, value)) {
diff --git a/src/unsavedChildren.js b/src/unsavedChildren.ts
similarity index 90%
rename from src/unsavedChildren.js
rename to src/unsavedChildren.ts
index 088bd6084..9a55c722e 100644
--- a/src/unsavedChildren.js
+++ b/src/unsavedChildren.ts
@@ -24,7 +24,7 @@ export default function unsavedChildren(
allowDeepUnsaved?: boolean
): Array {
const encountered = {
- objects: {},
+ objects: {} as Record,
files: [],
};
const identifier = obj.className + ':' + obj._getId();
@@ -35,17 +35,17 @@ export default function unsavedChildren(
traverse(attributes[attr], encountered, false, !!allowDeepUnsaved);
}
}
- const unsaved = [];
+ const unsaved: ParseObject[] = [];
for (const id in encountered.objects) {
if (id !== identifier && encountered.objects[id] !== true) {
- unsaved.push(encountered.objects[id]);
+ unsaved.push(encountered.objects[id] as ParseObject);
}
}
return unsaved.concat(encountered.files);
}
function traverse(
- obj: ParseObject,
+ obj: ParseObject | ParseFile | ParseRelation | Array,
encountered: EncounterMap,
shouldThrow: boolean,
allowDeepUnsaved: boolean
diff --git a/src/uuid.js b/src/uuid.ts
similarity index 68%
rename from src/uuid.js
rename to src/uuid.ts
index 450d4976c..8308a37e6 100644
--- a/src/uuid.js
+++ b/src/uuid.ts
@@ -1,8 +1,8 @@
-let uuid = null;
+let uuid: () => string = null as any;
if (process.env.PARSE_BUILD === 'weapp') {
uuid = function () {
- const s = [];
+ const s: string[] = [];
const hexDigits = '0123456789abcdef';
for (let i = 0; i < 36; i++) {
@@ -10,9 +10,8 @@ if (process.env.PARSE_BUILD === 'weapp') {
}
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
- s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
+ s[19] = hexDigits.substr((Number(s[19]) & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = '-';
-
return s.join('');
};
} else {
@@ -21,3 +20,4 @@ if (process.env.PARSE_BUILD === 'weapp') {
}
module.exports = uuid;
+export default uuid;
diff --git a/tsconfig.json b/tsconfig.json
index 051477c29..b5166cc62 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,8 +8,7 @@
"noImplicitAny": false,
"allowJs": false
},
- "files": [
- "src/Parse.ts",
- "src/ParseSession.ts"
+ "include": [
+ "src/*.ts"
]
}