diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 180d1d7a6..2ff2ba821 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,10 +29,10 @@ jobs: - run: npm ci - name: Build Types run: npm run build:types - - name: Test Types - run: npm run test:types - name: Lint Types run: npm run lint:types + - name: Test Types + run: npm run test:types check-docs: name: Check Docs timeout-minutes: 10 diff --git a/package.json b/package.json index b6d87e80f..70d0233f2 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "test": "cross-env PARSE_BUILD=node jest", "test:mongodb": "npm run test:mongodb:runnerstart && npm run integration", "test:mongodb:runnerstart": "mongodb-runner start -- --port 27017", - "test:types": "dtslint --expectOnly types", + "test:types": "dtslint --expectOnly types 2>&1 | tee temp.txt; echo \"Type tests failed: $(grep 'ERROR:' temp.txt -c)\"; rm temp.txt;", "posttest:mongodb": "mongodb-runner stop --all", "lint": "eslint --cache src/ integration/", "lint:fix": "eslint --fix --cache src/ integration/", diff --git a/src/Parse.ts b/src/Parse.ts index 6838bfc14..0041b3d1e 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -37,101 +37,21 @@ import LocalDatastoreController from './LocalDatastoreController'; import StorageController from './StorageController'; import WebSocketController from './WebSocketController'; -/** - * Contains all Parse API classes and functions. - * - * @static - * @global - * @class - * @hideconstructor - */ -interface ParseType { - ACL: typeof ACL; - Parse?: ParseType; - Analytics: typeof Analytics; - AnonymousUtils: typeof AnonymousUtils; - Cloud: typeof Cloud & { - /** only available in server environments */ - useMasterKey?: () => void; - }; - CLP: typeof CLP; - CoreManager: typeof CoreManager; - Config: typeof Config; - Error: typeof ParseError; - EventuallyQueue: typeof EventuallyQueue; - FacebookUtils: typeof FacebookUtils; - File: typeof File; - GeoPoint: typeof GeoPoint; - Hooks?: any; - Polygon: typeof Polygon; - Installation: typeof Installation; - LocalDatastore: typeof LocalDatastore; - Object: typeof ParseObject; - Op: { - Set: typeof ParseOp.SetOp; - Unset: typeof ParseOp.UnsetOp; - Increment: typeof ParseOp.IncrementOp; - Add: typeof ParseOp.AddOp; - Remove: typeof ParseOp.RemoveOp; - AddUnique: typeof ParseOp.AddUniqueOp; - Relation: typeof ParseOp.RelationOp; - }; - Push: typeof Push; - Query: typeof Query; - Relation: typeof Relation; - Role: typeof Role; - Schema: typeof Schema; - Session: typeof Session; - Storage: typeof Storage; - User: typeof User; - LiveQuery: typeof ParseLiveQuery; - LiveQueryClient: typeof LiveQueryClient; - - initialize(applicationId: string, javaScriptKey: string): void; - _initialize(applicationId: string, javaScriptKey: string, masterKey?: string): void; - setAsyncStorage(storage: any): void; - setLocalDatastoreController(controller: any): void; - getServerHealth(): Promise; - - applicationId: string; - javaScriptKey: string; - masterKey: string; - serverURL: string; - serverAuthToken: string; - serverAuthType: string; - liveQueryServerURL: string; - encryptedUser: boolean; - secret: string; - idempotency: boolean; - allowCustomObjectId: boolean; - IndexedDB?: any; - _request(...args: any[]): void; - _ajax(...args: any[]): void; - _decode(...args: any[]): void; - _encode(...args: any[]): void; - _getInstallationId?(): Promise; - enableLocalDatastore(polling: boolean, ms: number): void; - isLocalDatastoreEnabled(): boolean; - dumpLocalDatastore(): void; - enableEncryptedUser(): void; - isEncryptedUserEnabled(): void; -} - -const Parse: ParseType = { - ACL: ACL, - Analytics: Analytics, - AnonymousUtils: AnonymousUtils, - Cloud: Cloud, - CLP: CLP, - CoreManager: CoreManager, - Config: Config, +const Parse = { + ACL, + Analytics, + AnonymousUtils, + Cloud, + CLP, + CoreManager, + Config, Error: ParseError, - FacebookUtils: FacebookUtils, - File: File, - GeoPoint: GeoPoint, - Polygon: Polygon, - Installation: Installation, - LocalDatastore: LocalDatastore, + FacebookUtils, + File, + GeoPoint, + Polygon, + Installation, + LocalDatastore, Object: ParseObject, Op: { Set: ParseOp.SetOp, @@ -142,15 +62,15 @@ const Parse: ParseType = { AddUnique: ParseOp.AddUniqueOp, Relation: ParseOp.RelationOp, }, - Push: Push, - Query: Query, - Relation: Relation, - Role: Role, - Schema: Schema, - Session: Session, - Storage: Storage, - User: User, - LiveQueryClient: LiveQueryClient, + Push, + Query, + Relation, + Role, + Schema, + Session, + Storage, + User, + LiveQueryClient, IndexedDB: undefined, Hooks: undefined, Parse: undefined, @@ -314,10 +234,10 @@ const Parse: ParseType = { * @member {ParseLiveQuery} Parse.LiveQuery * @static */ - set LiveQuery(liveQuery: typeof ParseLiveQuery) { + set LiveQuery(liveQuery: ParseLiveQuery) { CoreManager.setLiveQuery(liveQuery); }, - get LiveQuery() { + get LiveQuery(): ParseLiveQuery { return CoreManager.getLiveQuery(); }, @@ -404,15 +324,15 @@ const Parse: ParseType = { * @param [ms] Milliseconds to ping the server. Default 2000ms * @static */ - enableLocalDatastore(polling = true, ms = 2000) { + enableLocalDatastore(polling?: boolean, ms?: number) { if (!this.applicationId) { console.log("'enableLocalDataStore' must be called after 'initialize'"); return; } if (!this.LocalDatastore.isEnabled) { this.LocalDatastore.isEnabled = true; - if (polling) { - CoreManager.getEventuallyQueue().poll(ms); + if (polling || typeof polling === 'undefined') { + CoreManager.getEventuallyQueue().poll(ms || 2000); } } }, @@ -470,7 +390,7 @@ CoreManager.setRESTController(RESTController); if (process.env.PARSE_BUILD === 'node') { Parse.initialize = Parse._initialize; Parse.Cloud = Parse.Cloud || ({} as any); - Parse.Cloud.useMasterKey = function () { + (Parse.Cloud as any).useMasterKey = function () { CoreManager.set('USE_MASTER_KEY', true); }; Parse.Hooks = Hooks; diff --git a/types/Parse.d.ts b/types/Parse.d.ts index 34e369210..4500ea0ab 100644 --- a/types/Parse.d.ts +++ b/types/Parse.d.ts @@ -2,18 +2,15 @@ import EventuallyQueue from './EventuallyQueue'; import * as ParseOp from './ParseOp'; import ACL from './ParseACL'; import * as Analytics from './Analytics'; -import AnonymousUtils from './AnonymousUtils'; import * as Cloud from './Cloud'; import CLP from './ParseCLP'; -import CoreManager from './CoreManager'; import Config from './ParseConfig'; import ParseError from './ParseError'; -import FacebookUtils from './FacebookUtils'; import File from './ParseFile'; +import * as Hooks from './ParseHooks'; import GeoPoint from './ParseGeoPoint'; import Polygon from './ParsePolygon'; import Installation from './ParseInstallation'; -import LocalDatastore from './LocalDatastore'; import ParseObject from './ParseObject'; import * as Push from './Push'; import Query from './ParseQuery'; @@ -21,39 +18,751 @@ import Relation from './ParseRelation'; import Role from './ParseRole'; import Schema from './ParseSchema'; import Session from './ParseSession'; -import Storage from './Storage'; import User from './ParseUser'; import ParseLiveQuery from './ParseLiveQuery'; import LiveQueryClient from './LiveQueryClient'; -/** - * Contains all Parse API classes and functions. - * - * @static - * @global - * @class - * @hideconstructor - */ -interface ParseType { +declare const Parse: { ACL: typeof ACL; - Parse?: ParseType; Analytics: typeof Analytics; - AnonymousUtils: typeof AnonymousUtils; - Cloud: typeof Cloud & { - /** only available in server environments */ - useMasterKey?: () => void; + AnonymousUtils: { + isLinked(user: User): boolean; + logIn(options?: import('./RESTController').RequestOptions): Promise; + link(user: User, options?: import('./RESTController').RequestOptions): Promise; + isRegistered(): boolean; + _getAuthProvider(): { + restoreAuthentication(): boolean; + getAuthType(): string; + getAuthData(): { + authData: { + id: string; + }; + }; + }; }; + Cloud: typeof Cloud; CLP: typeof CLP; - CoreManager: typeof CoreManager; + CoreManager: { + get: (key: string) => any; + set: (key: string, value: any) => void; + setIfNeeded: (key: string, value: any) => any; + setAnalyticsController(controller: { + track: ( + name: string, + dimensions: { + [key: string]: string; + } + ) => Promise; + }): void; + getAnalyticsController(): { + track: ( + name: string, + dimensions: { + [key: string]: string; + } + ) => Promise; + }; + setCloudController(controller: { + run: ( + name: string, + data: any, + options: import('./RESTController').RequestOptions + ) => Promise; + getJobsData: (options: import('./RESTController').RequestOptions) => Promise; + startJob: ( + name: string, + data: any, + options: import('./RESTController').RequestOptions + ) => Promise; + }): void; + getCloudController(): { + run: ( + name: string, + data: any, + options: import('./RESTController').RequestOptions + ) => Promise; + getJobsData: (options: import('./RESTController').RequestOptions) => Promise; + startJob: ( + name: string, + data: any, + options: import('./RESTController').RequestOptions + ) => Promise; + }; + setConfigController(controller: { + current: () => Promise | Config; + get: (opts?: import('./RESTController').RequestOptions) => Promise; + save: ( + attrs: { + [key: string]: any; + }, + masterKeyOnlyFlags?: { + [key: string]: any; + } + ) => Promise; + }): void; + getConfigController(): { + current: () => Promise | Config; + get: (opts?: import('./RESTController').RequestOptions) => Promise; + save: ( + attrs: { + [key: string]: any; + }, + masterKeyOnlyFlags?: { + [key: string]: any; + } + ) => Promise; + }; + setCryptoController(controller: { + encrypt: (obj: any, secretKey: string) => string; + decrypt: (encryptedText: string, secretKey: any) => string; + }): void; + getCryptoController(): { + encrypt: (obj: any, secretKey: string) => string; + decrypt: (encryptedText: string, secretKey: any) => string; + }; + setEventEmitter(eventEmitter: any): void; + getEventEmitter(): any; + setFileController(controller: { + saveFile: ( + name: string, + source: import('./ParseFile').FileSource, + options?: import('./RESTController').FullOptions + ) => Promise; + saveBase64: ( + name: string, + source: import('./ParseFile').FileSource, + options?: import('./ParseFile').FileSaveOptions + ) => Promise<{ + name: string; + url: string; + }>; + download: ( + uri: string, + options?: any + ) => Promise<{ + base64?: string; + contentType?: string; + }>; + deleteFile: ( + name: string, + options?: { + useMasterKey?: boolean; + } + ) => Promise; + }): void; + setEventuallyQueue(controller: { + save: ( + object: ParseObject, + serverOptions: import('./ParseObject').SaveOptions + ) => Promise; + destroy: ( + object: ParseObject, + serverOptions: import('./RESTController').RequestOptions + ) => Promise; + poll: (ms?: number) => void; + }): void; + getEventuallyQueue(): { + save: ( + object: ParseObject, + serverOptions: import('./ParseObject').SaveOptions + ) => Promise; + destroy: ( + object: ParseObject, + serverOptions: import('./RESTController').RequestOptions + ) => Promise; + poll: (ms?: number) => void; + }; + getFileController(): { + saveFile: ( + name: string, + source: import('./ParseFile').FileSource, + options?: import('./RESTController').FullOptions + ) => Promise; + saveBase64: ( + name: string, + source: import('./ParseFile').FileSource, + options?: import('./ParseFile').FileSaveOptions + ) => Promise<{ + name: string; + url: string; + }>; + download: ( + uri: string, + options?: any + ) => Promise<{ + base64?: string; + contentType?: string; + }>; + deleteFile: ( + name: string, + options?: { + useMasterKey?: boolean; + } + ) => Promise; + }; + setInstallationController(controller: { + currentInstallationId: () => Promise; + currentInstallation: () => Promise; + updateInstallationOnDisk: (installation: Installation) => Promise; + }): void; + getInstallationController(): { + currentInstallationId: () => Promise; + currentInstallation: () => Promise; + updateInstallationOnDisk: (installation: Installation) => Promise; + }; + setLiveQuery(liveQuery: any): void; + getLiveQuery(): any; + setObjectController(controller: { + fetch: ( + object: ParseObject | Array, + forceFetch: boolean, + options: import('./RESTController').RequestOptions + ) => Promise | ParseObject | undefined>; + save: ( + object: ParseObject | Array | null, + options: import('./RESTController').RequestOptions + ) => Promise | File | undefined>; + destroy: ( + object: ParseObject | Array, + options: import('./RESTController').RequestOptions + ) => Promise>; + }): void; + getObjectController(): { + fetch: ( + object: ParseObject | Array, + forceFetch: boolean, + options: import('./RESTController').RequestOptions + ) => Promise | ParseObject | undefined>; + save: ( + object: ParseObject | Array | null, + options: import('./RESTController').RequestOptions + ) => Promise | File | undefined>; + destroy: ( + object: ParseObject | Array, + options: import('./RESTController').RequestOptions + ) => Promise>; + }; + setObjectStateController(controller: { + getState: (obj: any) => import('./ObjectStateMutations').State | null; + initializeState: ( + obj: any, + initial?: import('./ObjectStateMutations').State + ) => import('./ObjectStateMutations').State; + removeState: (obj: any) => import('./ObjectStateMutations').State | null; + getServerData: (obj: any) => import('./ObjectStateMutations').AttributeMap; + setServerData: (obj: any, attributes: import('./ObjectStateMutations').AttributeMap) => void; + getPendingOps: (obj: any) => Array; + setPendingOp: (obj: any, attr: string, op?: ParseOp.Op) => void; + pushPendingState: (obj: any) => void; + popPendingState: (obj: any) => import('./ObjectStateMutations').OpsMap | undefined; + mergeFirstPendingState: (obj: any) => void; + getObjectCache: (obj: any) => import('./ObjectStateMutations').ObjectCache; + estimateAttribute: (obj: any, attr: string) => any; + estimateAttributes: (obj: any) => import('./ObjectStateMutations').AttributeMap; + commitServerChanges: ( + obj: any, + changes: import('./ObjectStateMutations').AttributeMap + ) => void; + enqueueTask: (obj: any, task: () => Promise) => Promise; + clearAllState: () => void; + duplicateState: (source: any, dest: any) => void; + }): void; + getObjectStateController(): { + getState: (obj: any) => import('./ObjectStateMutations').State | null; + initializeState: ( + obj: any, + initial?: import('./ObjectStateMutations').State + ) => import('./ObjectStateMutations').State; + removeState: (obj: any) => import('./ObjectStateMutations').State | null; + getServerData: (obj: any) => import('./ObjectStateMutations').AttributeMap; + setServerData: (obj: any, attributes: import('./ObjectStateMutations').AttributeMap) => void; + getPendingOps: (obj: any) => Array; + setPendingOp: (obj: any, attr: string, op?: ParseOp.Op) => void; + pushPendingState: (obj: any) => void; + popPendingState: (obj: any) => import('./ObjectStateMutations').OpsMap | undefined; + mergeFirstPendingState: (obj: any) => void; + getObjectCache: (obj: any) => import('./ObjectStateMutations').ObjectCache; + estimateAttribute: (obj: any, attr: string) => any; + estimateAttributes: (obj: any) => import('./ObjectStateMutations').AttributeMap; + commitServerChanges: ( + obj: any, + changes: import('./ObjectStateMutations').AttributeMap + ) => void; + enqueueTask: (obj: any, task: () => Promise) => Promise; + clearAllState: () => void; + duplicateState: (source: any, dest: any) => void; + }; + setPushController(controller: { + send: (data: Push.PushData, options?: import('./RESTController').FullOptions) => Promise; + }): void; + getPushController(): { + send: (data: Push.PushData, options?: import('./RESTController').FullOptions) => Promise; + }; + setQueryController(controller: { + find( + className: string, + params: import('./ParseQuery').QueryJSON, + options: import('./RESTController').RequestOptions + ): Promise<{ + results?: Array; + className?: string; + count?: number; + }>; + aggregate( + className: string, + params: any, + options: import('./RESTController').RequestOptions + ): Promise<{ + results?: Array; + }>; + }): void; + getQueryController(): { + find( + className: string, + params: import('./ParseQuery').QueryJSON, + options: import('./RESTController').RequestOptions + ): Promise<{ + results?: Array; + className?: string; + count?: number; + }>; + aggregate( + className: string, + params: any, + options: import('./RESTController').RequestOptions + ): Promise<{ + results?: Array; + }>; + }; + setRESTController(controller: { + request: ( + method: string, + path: string, + data?: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + ajax: ( + method: string, + url: string, + data: any, + headers?: any, + options?: import('./RESTController').FullOptions + ) => Promise; + handleError: ( + err? /** + * Call this method to set your LocalDatastoreStorage engine + * If using React-Native use {@link Parse.setAsyncStorage Parse.setAsyncStorage()} + * + * @param {LocalDatastoreController} controller a data storage. + * @static + */ + : any + ) => void; + }): void; + getRESTController(): { + request: ( + method: string, + path: string, + data?: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + ajax: ( + method: string, + url: string, + data: any, + headers?: any, + options?: import('./RESTController').FullOptions + ) => Promise; + handleError: ( + err? /** + * Call this method to set your LocalDatastoreStorage engine + * If using React-Native use {@link Parse.setAsyncStorage Parse.setAsyncStorage()} + * + * @param {LocalDatastoreController} controller a data storage. + * @static + */ + : any + ) => void; + }; + setSchemaController(controller: { + purge: (className: string) => Promise; + get: ( + className: string, + options?: import('./RESTController').RequestOptions + ) => Promise<{ + results: Schema[]; + }>; + delete: ( + className: string, + options?: import('./RESTController').RequestOptions + ) => Promise; + create: ( + className: string, + params: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + update: ( + className: string, + params: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + send( + className: string, + method: string, + params: any, + options: import('./RESTController').RequestOptions + ): Promise; + }): void; + getSchemaController(): { + purge: (className: string) => Promise; + get: ( + className: string, + options?: import('./RESTController').RequestOptions + ) => Promise<{ + results: Schema[]; + }>; + delete: ( + className: string, + options?: import('./RESTController').RequestOptions + ) => Promise; + create: ( + className: string, + params: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + update: ( + className: string, + params: any, + options?: import('./RESTController').RequestOptions + ) => Promise; + send( + className: string, + method: string, + params: any, + options: import('./RESTController').RequestOptions + ): Promise; + }; + setSessionController(controller: { + getSession: (token: import('./RESTController').RequestOptions) => Promise; + }): void; + getSessionController(): { + getSession: (token: import('./RESTController').RequestOptions) => Promise; + }; + setStorageController( + controller: + | { + 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>; + } + ): void; + setLocalDatastoreController(controller: { + fromPinWithName: (name: string) => any | undefined; + pinWithName: (name: string, objects: any) => void; + unPinWithName: (name: string) => void; + getAllContents: () => any | undefined; + clear: () => void; + }): void; + getLocalDatastoreController(): { + fromPinWithName: (name: string) => any | undefined; + pinWithName: (name: string, objects: any) => void; + unPinWithName: (name: string) => void; + getAllContents: () => any | undefined; + clear: () => void; + }; + setLocalDatastore(store: any): void; + getLocalDatastore(): any; + getStorageController(): + | { + 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>; + }; + setAsyncStorage(storage: { + getItem: ( + key: string, + callback?: (error?: Error | null, result?: string | null) => void + ) => Promise; + setItem: ( + key: string, + value: string, + callback?: (error?: Error | null) => void + ) => Promise; + removeItem: (key: string, callback?: (error?: Error | null) => void) => Promise; + mergeItem: ( + key: string, + value: string, + callback?: (error?: Error | null) => void + ) => Promise; + clear: (callback?: (error?: Error | null) => void) => Promise; + getAllKeys: ( + callback?: (error?: Error | null, result?: readonly string[] | null) => void + ) => Promise; + multiGet: ( + keys: readonly string[], + callback?: ( + errors?: readonly (Error | null)[] | null, + result?: readonly [string, string][] + ) => void + ) => Promise; + multiSet: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + multiRemove: ( + keys: readonly string[], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + multiMerge: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + }): void; + getAsyncStorage(): { + getItem: ( + key: string, + callback?: (error?: Error | null, result?: string | null) => void + ) => Promise; + setItem: ( + key: string, + value: string, + callback?: (error?: Error | null) => void + ) => Promise; + removeItem: (key: string, callback?: (error?: Error | null) => void) => Promise; + mergeItem: ( + key: string, + value: string, + callback?: (error?: Error | null) => void + ) => Promise; + clear: (callback?: (error?: Error | null) => void) => Promise; + getAllKeys: ( + callback?: (error?: Error | null, result?: readonly string[] | null) => void + ) => Promise; + multiGet: ( + keys: readonly string[], + callback?: ( + errors?: readonly (Error | null)[] | null, + result?: readonly [string, string][] + ) => void + ) => Promise; + multiSet: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + multiRemove: ( + keys: readonly string[], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + multiMerge: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + }; + setWebSocketController( + controller: new ( + url: string | URL, + protocols?: string | string[] | undefined + ) => import('./CoreManager').WebSocketController + ): void; + getWebSocketController(): new ( + url: string | URL, + protocols?: string | string[] | undefined + ) => import('./CoreManager').WebSocketController; + setUserController(controller: { + setCurrentUser: (user: User) => Promise; + currentUser: () => User | null; + currentUserAsync: () => Promise; + signUp: ( + user: User, + attrs: import('./ObjectStateMutations').AttributeMap, + options: import('./RESTController').RequestOptions + ) => Promise; + logIn: (user: User, options: import('./RESTController').RequestOptions) => Promise; + loginAs: (user: User, userId: string) => Promise; + become: (user: User, options: import('./RESTController').RequestOptions) => Promise; + hydrate: ( + user: User, + userJSON: import('./ObjectStateMutations').AttributeMap + ) => Promise; + logOut: (options: import('./RESTController').RequestOptions) => Promise; + me: (user: User, options: import('./RESTController').RequestOptions) => Promise; + requestPasswordReset: ( + email: string, + options: import('./RESTController').RequestOptions + ) => Promise; + updateUserOnDisk: (user: User) => Promise; + upgradeToRevocableSession: ( + user: User, + options: import('./RESTController').RequestOptions + ) => Promise; + linkWith: ( + user: User, + authData: import('./ParseUser').AuthData, + options?: import('./RESTController').FullOptions + ) => Promise; + removeUserFromDisk: () => Promise; + verifyPassword: ( + username: string, + password: string, + options: import('./RESTController').RequestOptions + ) => Promise; + requestEmailVerification: ( + email: string, + options: import('./RESTController').RequestOptions + ) => Promise; + }): void; + getUserController(): { + setCurrentUser: (user: User) => Promise; + currentUser: () => User | null; + currentUserAsync: () => Promise; + signUp: ( + user: User, + attrs: import('./ObjectStateMutations').AttributeMap, + options: import('./RESTController').RequestOptions + ) => Promise; + logIn: (user: User, options: import('./RESTController').RequestOptions) => Promise; + loginAs: (user: User, userId: string) => Promise; + become: (user: User, options: import('./RESTController').RequestOptions) => Promise; + hydrate: ( + user: User, + userJSON: import('./ObjectStateMutations').AttributeMap + ) => Promise; + logOut: (options: import('./RESTController').RequestOptions) => Promise; + me: (user: User, options: import('./RESTController').RequestOptions) => Promise; + requestPasswordReset: ( + email: string, + options: import('./RESTController').RequestOptions + ) => Promise; + updateUserOnDisk: (user: User) => Promise; + upgradeToRevocableSession: ( + user: User, + options: import('./RESTController').RequestOptions + ) => Promise; + linkWith: ( + user: User, + authData: import('./ParseUser').AuthData, + options?: import('./RESTController').FullOptions + ) => Promise; + removeUserFromDisk: () => Promise; + verifyPassword: ( + username: string, + password: string, + options: import('./RESTController').RequestOptions + ) => Promise; + requestEmailVerification: ( + email: string, + options: import('./RESTController').RequestOptions + ) => Promise; + }; + setLiveQueryController(controller: { + setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void; + getDefaultLiveQueryClient(): Promise; + _clearCachedDefaultClient(): void; + }): void; + getLiveQueryController(): { + setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void; + getDefaultLiveQueryClient(): Promise; + _clearCachedDefaultClient(): void; + }; + setHooksController(controller: { + get: (type: string, functionName?: string, triggerName?: string) => Promise; + create: (hook: Hooks.HookDeclaration) => Promise; + remove: (hook: Hooks.HookDeleteArg) => Promise; + update: (hook: Hooks.HookDeclaration) => Promise; + sendRequest?: (method: string, path: string, body?: any) => Promise; + }): void; + getHooksController(): { + get: (type: string, functionName?: string, triggerName?: string) => Promise; + create: (hook: Hooks.HookDeclaration) => Promise; + remove: (hook: Hooks.HookDeleteArg) => Promise; + update: (hook: Hooks.HookDeclaration) => Promise; + sendRequest?: (method: string, path: string, body?: any) => Promise; + }; + setParseOp(op: any): void; + getParseOp(): any; + setParseObject(object: any): void; + getParseObject(): any; + setParseQuery(query: any): void; + getParseQuery(): any; + setParseRole(role: any): void; + getParseRole(): any; + setParseUser(user: any): void; + getParseUser(): any; + }; Config: typeof Config; Error: typeof ParseError; - EventuallyQueue: typeof EventuallyQueue; - FacebookUtils: typeof FacebookUtils; + FacebookUtils: { + init(options: any): void; + isLinked(user: any): any; + logIn(permissions: any, options: any): Promise; + link(user: any, permissions: any, options: any): any; + unlink: (user: any, options: any) => any; + _getAuthProvider(): import('./ParseUser').AuthProviderType; + }; File: typeof File; GeoPoint: typeof GeoPoint; - Hooks?: any; Polygon: typeof Polygon; Installation: typeof Installation; - LocalDatastore: typeof LocalDatastore; + LocalDatastore: { + isEnabled: boolean; + isSyncing: boolean; + fromPinWithName(name: string): Promise>; + pinWithName(name: string, value: any): Promise; + unPinWithName(name: string): Promise; + _getAllContents(): Promise; + _getRawStorage(): Promise; + _clear(): Promise; + _handlePinAllWithName(name: string, objects: Array): Promise; + _handleUnPinAllWithName(name: string, objects: Array): Promise; + _getChildren(object: ParseObject): any; + _traverse(object: any, encountered: any): void; + _serializeObjectsFromPinName(name: string): Promise; + _serializeObject(objectKey: string, localDatastore: any): Promise; + _updateObjectIfPinned(object: ParseObject): Promise; + _destroyObjectIfPinned(object: ParseObject): Promise; + _updateLocalIdForObject(localId: string, object: ParseObject): Promise; + updateFromServer(): Promise; + getKeyForObject(object: any): string; + getPinName(pinName?: string): string; + checkIfEnabled(): any; + }; Object: typeof ParseObject; Op: { Set: typeof ParseOp.SetOp; @@ -70,37 +779,169 @@ interface ParseType { Role: typeof Role; Schema: typeof Schema; Session: typeof Session; - Storage: typeof Storage; + Storage: { + async(): boolean; + getItem(path: string): string | null; + getItemAsync(path: string): Promise; + setItem(path: string, value: string): void; + setItemAsync(path: string, value: string): Promise; + removeItem(path: string): void; + removeItemAsync(path: string): Promise; + getAllKeys(): Array; + getAllKeysAsync(): Promise>; + generatePath(path: string): string; + _clear(): void; + }; User: typeof User; - LiveQuery: typeof ParseLiveQuery; LiveQueryClient: typeof LiveQueryClient; + IndexedDB: any; + Hooks: any; + Parse: any; + get EventuallyQueue(): any; + /** + * @member {EventuallyQueue} Parse.EventuallyQueue + * @static + */ + set EventuallyQueue(queue: typeof EventuallyQueue); + /** + * Call this method first to set up your authentication tokens for Parse. + * + * @param {string} applicationId Your Parse Application ID. + * @param {string} [javaScriptKey] Your Parse JavaScript Key (Not needed for parse-server) + * @param {string} [masterKey] Your Parse Master Key. (Node.js only!) + * @static + */ initialize(applicationId: string, javaScriptKey: string): void; _initialize(applicationId: string, javaScriptKey: string, masterKey?: string): void; + /** + * Call this method to set your AsyncStorage engine + * Starting Parse@1.11, the ParseSDK do not provide a React AsyncStorage as the ReactNative module + * is not provided at a stable path and changes over versions. + * + * @param {AsyncStorage} storage a react native async storage. + * @static + */ setAsyncStorage(storage: any): void; + /** + * Call this method to set your LocalDatastoreStorage engine + * If using React-Native use {@link Parse.setAsyncStorage Parse.setAsyncStorage()} + * + * @param {LocalDatastoreController} controller a data storage. + * @static + */ setLocalDatastoreController(controller: any): void; + /** + * Returns information regarding the current server's health + * + * @returns {Promise} + * @static + */ getServerHealth(): Promise; - applicationId: string; - javaScriptKey: string; - masterKey: string; - serverURL: string; - serverAuthToken: string; - serverAuthType: string; - liveQueryServerURL: string; + /** + * @member {string} Parse.applicationId + * @static + */ + applicationId: any; + /** + * @member {string} Parse.javaScriptKey + * @static + */ + javaScriptKey: any; + /** + * @member {string} Parse.masterKey + * @static + */ + masterKey: any; + /** + * @member {string} Parse.serverURL + * @static + */ + serverURL: any; + /** + * @member {string} Parse.serverAuthToken + * @static + */ + serverAuthToken: any; + /** + * @member {string} Parse.serverAuthType + * @static + */ + serverAuthType: any; + /** + * @member {ParseLiveQuery} Parse.LiveQuery + * @static + */ + LiveQuery: ParseLiveQuery; + /** + * @member {string} Parse.liveQueryServerURL + * @static + */ + liveQueryServerURL: any; + /** + * @member {boolean} Parse.encryptedUser + * @static + */ encryptedUser: boolean; - secret: string; - idempotency: boolean; - allowCustomObjectId: boolean; - IndexedDB?: any; - _request(...args: any[]): void; - _ajax(...args: any[]): void; - _decode(...args: any[]): void; - _encode(...args: any[]): void; - _getInstallationId?(): Promise; - enableLocalDatastore(polling: boolean, ms: number): void; - isLocalDatastoreEnabled(): boolean; - dumpLocalDatastore(): void; + /** + * @member {string} Parse.secret + * @static + */ + secret: any; + /** + * @member {boolean} Parse.idempotency + * @static + */ + idempotency: any; + /** + * @member {boolean} Parse.allowCustomObjectId + * @static + */ + allowCustomObjectId: any; + _request(...args: any[]): any; + _ajax(...args: any[]): any; + _decode(_: any, value: any): any; + _encode(value: any, _: any, disallowObjects: any): any; + _getInstallationId(): Promise; + /** + * Enable pinning in your application. + * This must be called after `Parse.initialize` in your application. + * + * @param [polling] Allow pinging the server /health endpoint. Default true + * @param [ms] Milliseconds to ping the server. Default 2000ms + * @static + */ + enableLocalDatastore(polling?: boolean, ms?: number): void; + /** + * Flag that indicates whether Local Datastore is enabled. + * + * @static + * @returns {boolean} + */ + isLocalDatastoreEnabled(): any; + /** + * Gets all contents from Local Datastore + * + *
+   * await Parse.dumpLocalDatastore();
+   * 
+ * + * @static + * @returns {object} + */ + dumpLocalDatastore(): Promise; + /** + * Enable the current user encryption. + * This must be called before login any user. + * + * @static + */ enableEncryptedUser(): void; - isEncryptedUserEnabled(): void; -} -declare const Parse: ParseType; + /** + * Flag that indicates whether Encrypted User is enabled. + * + * @static + * @returns {boolean} + */ + isEncryptedUserEnabled(): any; +}; export default Parse; diff --git a/types/ParseQuery.d.ts b/types/ParseQuery.d.ts index b58a105e5..968f13f80 100644 --- a/types/ParseQuery.d.ts +++ b/types/ParseQuery.d.ts @@ -237,6 +237,7 @@ declare class ParseQuery { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • json: Return raw JSON without converting to Parse.Object. * * @returns {Promise} A promise that is resolved with the results when * the query completes. diff --git a/types/index.d.ts b/types/index.d.ts index c53fea3f7..651f033f3 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,7 +1,66 @@ // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b23a36e669fa127d1035e22ca93faab85b98e49f/types/parse/index.d.ts#L11 -/// -/// - import parse from './Parse'; export default parse; + +// All exports beyond this point will be included in the Parse namespace +export as namespace Parse; +import ACL from './ParseACL'; +import * as Analytics from './Analytics'; +import AnonymousUtils from './AnonymousUtils'; +import * as Cloud from './Cloud'; +import CLP from './ParseCLP'; +import CoreManager from './CoreManager'; +import Config from './ParseConfig'; +import Error from './ParseError'; +import FacebookUtils from './FacebookUtils'; +import File from './ParseFile'; +import GeoPoint from './ParseGeoPoint'; +import * as Hooks from './ParseHooks'; +import IndexedDB from './IndexedDBStorageController'; +import Polygon from './ParsePolygon'; +import Installation from './ParseInstallation'; +import LiveQuery from './ParseLiveQuery'; +import LiveQueryClient from './LiveQueryClient'; +import LocalDatastore from './LocalDatastore'; +import Object from './ParseObject'; +import * as Push from './Push'; +import Query from './ParseQuery'; +import Relation from './ParseRelation'; +import Role from './ParseRole'; +import Schema from './ParseSchema'; +import Session from './ParseSession'; +import Storage from './Storage'; +import User from './ParseUser'; + +export type { AuthProvider, AuthData } from './ParseUser'; +export type { Pointer } from './ParseObject'; +export { + ACL, + Analytics, + AnonymousUtils, + Cloud, + CLP, + CoreManager, + Config, + Error, + FacebookUtils, + File, + GeoPoint, + Polygon, + Installation, + LiveQuery, + LocalDatastore, + Object, + Push, + Query, + Relation, + Role, + Schema, + Session, + Storage, + User, + LiveQueryClient, + IndexedDB, + Hooks, +}; diff --git a/types/tests.ts b/types/tests.ts index efcee7a0e..e7c28b3a7 100644 --- a/types/tests.ts +++ b/types/tests.ts @@ -1,2062 +1,2093 @@ -import Parse from 'parse'; -// Parse is a global type, but it can also be imported - -// class GameScore extends Parse.Object { -// constructor(options?: any) { -// super('GameScore', options); -// } -// } - -// class Game extends Parse.Object { -// constructor(options?: any) { -// super('Game', options); -// } -// } - -// function test_config() { -// Parse.Config.save({ foo: 'bar' }, { foo: true }); -// Parse.Config.get({ useMasterKey: true }); -// } - -// function test_object() { -// const game = new Game(); -// game.save(null, { -// useMasterKey: true, -// sessionToken: 'sometoken', -// cascadeSave: false, -// }).then(result => result); - -// if (!game.isNew()) { - -// } - -// if (game.toPointer().className !== 'Game') { - -// } - -// game.fetch({}); - -// // Create a new instance of that class. -// const gameScore = new GameScore(); - -// gameScore.set('score', 1337); -// gameScore.set('playerName', 'Sean Plott'); -// gameScore.set('cheatMode', false); - -// // Setting attrs using object -// gameScore.set({ -// level: '10', -// difficult: 15, -// }); - -// const score = gameScore.get('score'); -// const playerName = gameScore.get('playerName'); -// const cheatMode = gameScore.get('cheatMode'); - -// gameScore.increment('score'); -// gameScore.addUnique('skills', 'flying'); -// gameScore.addUnique('skills', 'kungfu'); -// gameScore.addAll('skills', ['kungfu']); -// gameScore.addAllUnique('skills', ['kungfu']); -// gameScore.remove('skills', 'flying'); -// gameScore.removeAll('skills', ['kungFu']); -// game.set('gameScore', gameScore); - -// const gameCopy = Game.fromJSON(JSON.parse(JSON.stringify(game)), true); - -// const object = new Parse.Object('TestObject'); -// object.equals(gameScore); -// object.fetchWithInclude(['key1', 'key2']); -// } - -// function test_errors() { -// try { -// throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'sdfds'); -// } catch (error) { -// if (error.code !== 1) { - -// } -// } -// } - -// function test_query() { -// const gameScore = new GameScore(); - -// const query = new Parse.Query(GameScore); -// query.equalTo('playerName', 'Dan Stemkoski'); -// query.notEqualTo('playerName', 'Michael Yabuti'); -// query.fullText('playerName', 'dan', { language: 'en', caseSensitive: false, diacriticSensitive: true }); -// query.greaterThan('playerAge', 18); -// query.eachBatch(objs => Promise.resolve(), { batchSize: 10 }); -// query.each(score => Promise.resolve()); -// query.hint('_id_'); -// query.explain(true); -// query.limit(10); -// query.skip(10); - -// // Sorts the results in ascending order by the score field -// query.ascending('score'); - -// // Sorts the results in descending order by the score field -// query.descending('score'); - -// // Restricts to wins < 50 -// query.lessThan('wins', 50); - -// // Restricts to wins <= 50 -// query.lessThanOrEqualTo('wins', 50); - -// // Restricts to wins > 50 -// query.greaterThan('wins', 50); - -// // Restricts to wins >= 50 -// query.greaterThanOrEqualTo('wins', 50); - -// query.containedBy('place', ['1', '2']); -// // Finds scores from any of Jonathan, Dario, or Shawn -// query.containedIn('playerName', ['Jonathan Walsh', 'Dario Wunsch', 'Shawn Simon']); - -// // Finds scores from anyone who is neither Jonathan, Dario, nor Shawn -// query.notContainedIn('playerName', ['Jonathan Walsh', 'Dario Wunsch', 'Shawn Simon']); - -// // Finds objects that have the score set -// query.exists('score'); - -// // Finds objects that don't have the score set -// query.doesNotExist('score'); -// query.matchesKeyInQuery('hometown', 'city', query); -// query.doesNotMatchKeyInQuery('hometown', 'city', query); -// query.select('score', 'playerName'); - -// // Find objects where the array in arrayKey contains 2. -// query.equalTo('arrayKey', 2); - -// // Find objects where the array in arrayKey contains all of the elements 2, 3, and 4. -// query.containsAll('arrayKey', [2, 3, 4]); -// query.containsAllStartingWith('arrayKey', ['2', '3', '4']); - -// query.startsWith('name', "Big Daddy's"); -// query.equalTo('score', gameScore); -// query.exists('score'); -// query.include('score'); -// query.include(['score.team']); -// query.includeAll(); -// query.sortByTextScore(); -// // Find objects that match the aggregation pipeline -// query.aggregate({ -// group: { -// objectId: '$name', -// }, -// }); - -// query.aggregate({ -// count: 'total', -// }); - -// query.aggregate({ -// lookup: { -// from: 'Collection', -// foreignField: 'id', -// localField: 'id', -// as: 'result', -// }, -// }); -// query.aggregate({ -// lookup: { -// from: 'Target', -// let: { foo: 'bar', baz: 123 }, -// pipeline: [], -// as: 'result', -// }, -// }); - -// query.aggregate({ -// graphLookup: { -// from: 'Target', -// connectFromField: 'objectId', -// connectToField: 'newId', -// as: 'result', -// }, -// }); - -// query.aggregate({ -// facet: { -// foo: [ -// { -// count: 'total', -// }, -// ], -// bar: [ -// { -// group: { -// objectId: '$name', -// }, -// }, -// ], -// }, -// }); - -// query.aggregate({ -// unwind: '$field', -// }); - -// query.aggregate({ -// unwind: { -// path: '$field', -// includeArrayIndex: 'newIndex', -// preserveNullAndEmptyArrays: true, -// }, -// }); - -// // Find objects with distinct key -// query.distinct('name'); - -// const testQuery = Parse.Query.or(query, query); -// } - -// function test_query_exclude() { -// const gameScore = new GameScore(); - -// const query = new Parse.Query(GameScore); - -// // Show all keys, except the specified key. -// query.exclude('place'); - -// const testQuery = Parse.Query.or(query, query); -// } - -// async function test_query_promise() { -// // Test promise with a query -// const findQuery = new Parse.Query('Test'); -// findQuery -// .find() -// .then(() => { -// // success -// }) -// .catch(() => { -// // error -// }); - -// const getQuery = new Parse.Query('Test'); -// try { -// await getQuery.get('objectId'); -// } catch (error) { -// // noop -// } - -// await getQuery.map((score, index) => score.increment('score', index)); -// await getQuery.reduce((accum, score, index) => (accum += score.get('score')), 0); -// await getQuery.reduce((accum, score, index) => (accum += score.get('score')), 0, { batchSize: 200 }); -// await getQuery.filter(scores => scores.get('score') > 0); -// await getQuery.filter(scores => scores.get('score') > 0, { batchSize: 10 }); -// } - -// async function test_live_query() { -// const subscription = await new Parse.Query('Test').subscribe(); -// subscription.on('close', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('create', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('delete', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('enter', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('leave', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('open', object => { -// // $ExpectType ParseObject -// object; -// }); -// subscription.on('update', object => { -// // $ExpectType ParseObject -// object; -// }); -// } - -// function test_anonymous_utils() { -// // $ExpectType boolean -// Parse.AnonymousUtils.isLinked(new Parse.User()); -// // $ExpectType Promise -// Parse.AnonymousUtils.link(new Parse.User(), { useMasterKey: true, sessionToken: '' }); -// // $ExpectType Promise -// Parse.AnonymousUtils.logIn({ useMasterKey: true, sessionToken: '' }); -// } - -// function return_a_query(): Parse.Query { -// return new Parse.Query(Game); -// } - -// function test_each() { -// new Parse.Query(Game).each(game => { -// // $ExpectType Game -// game; -// }); -// } - -// function test_file() { -// const base64 = 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE='; -// let file = new Parse.File('myfile.txt', { base64 }); - -// file = new Parse.File('nana', { uri: 'http://example.com/image.jps' }); - -// const bytes = [0xbe, 0xef, 0xca, 0xfe]; -// file = new Parse.File('myfile.txt', bytes); - -// file = new Parse.File('myfile.zzz', new Blob(), 'image/png'); - -// const src = file.url(); -// const secure = file.url({ forceSecure: true }); - -// file.save().then( -// () => { -// // The file has been saved to Parse. -// }, -// error => { -// // The file either could n ot be read, or could not be saved to Parse. -// }, -// ); - -// Parse.Cloud.httpRequest({ url: file.url() }).then((response: Parse.Cloud.HttpResponse) => { -// // result -// }); - -// // TODO: Check - -// file.cancel(); -// file.destroy(); -// } - -// function test_file_tags_and_metadata() { -// const base64 = 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE='; -// const file = new Parse.File('myfile.txt', { base64 }); -// file.setTags({ ownerId: 42, status: 'okay' }); -// file.addTag('labes', ['one', 'two', 'three']); -// file.setMetadata({ contentType: 'plain/text', contentLength: 579 }); -// file.addMetadata('author', 'John Doe'); - -// const tags = file.tags(); -// const ownerId = tags['ownerId']; - -// const metadata = file.metadata(); -// const contentType = metadata['contentType']; -// } - -// function test_analytics() { -// const dimensions = { -// // Define ranges to bucket data points into meaningful segments -// priceRange: '1000-1500', -// // Did the user filter the query? -// source: 'craigslist', -// // Do searches happen more often on weekdays or weekends? -// dayType: 'weekday', -// }; -// // Send the dimensions to Parse along with the 'search' event -// Parse.Analytics.track('search', dimensions); - -// const codeString = '404'; -// Parse.Analytics.track('error', { code: codeString }); -// } - -// function test_relation() { -// const game1 = new Game(); -// const game2 = new Game(); - -// new Parse.User() -// .relation('games') -// .query() -// .find() -// .then((g: Game[]) => {}); -// new Parse.User().relation('games').add(game1); -// new Parse.User().relation('games').add([game1, game2]); - -// new Parse.User().relation('games').remove(game1); -// new Parse.User().relation('games').remove([game1, game2]); -// } - -// function test_user() { -// const user = new Parse.User(); -// user.set('username', 'my name'); -// user.set('password', 'my pass'); -// user.set('email', 'email@example.com'); -// user.signUp(null, { useMasterKey: true }); - -// const anotherUser: Parse.User = Parse.User.fromJSON({}); -// anotherUser.set('email', 'email@example.com'); -// } - -// async function test_user_currentAsync() { -// const asyncUser = await Parse.User.currentAsync(); -// if (asyncUser) { -// asyncUser.set('email', 'email@example.com'); -// } else if (asyncUser === null) { -// Parse.User.logIn('email@example.com', 'my pass'); -// } -// } - -// function test_user_acl_roles() { -// const user = new Parse.User(); -// user.set('username', 'my name'); -// user.set('password', 'my pass'); -// user.set('email', 'email@example.com'); - -// // other fields can be set just like with Parse.Object -// user.set('phone', '415-392-0202'); - -// const currentUser = Parse.User.current(); -// if (currentUser) { -// // do stuff with the user -// } else { -// // show the signup or login page -// } - -// Parse.User.become('session-token-here').then( -// user => { -// // The current user is now set to user. -// }, -// error => { -// // The token could not be validated. -// }, -// ); - -// Parse.User.hydrate({}).then( -// user => { -// // The current user is now set to user. -// }, -// error => { -// // The token could not be validated. -// }, -// ); - -// const game = new Game(); -// game.set('gameScore', new GameScore()); -// game.setACL(new Parse.ACL(Parse.User.current())); -// game.save().then((game: Game) => {}); -// game.save(null, { useMasterKey: true }); -// game.save({ score: '10' }, { useMasterKey: true }).then( -// game => { -// // Update game then revert it to the last saved state. -// game.set('score', '20'); -// game.revert('score'); -// game.revert('score', 'ACL'); -// game.revert(); -// }, -// error => { -// // The save failed -// }, -// ); - -// const groupACL = new Parse.ACL(); - -// const userList: Parse.User[] = [Parse.User.current()!]; -// // userList is an array with the users we are sending this message to. -// for (const userListItem of userList) { -// groupACL.setReadAccess(userListItem, true); -// groupACL.setWriteAccess(userListItem, true); -// } - -// groupACL.setPublicReadAccess(true); - -// game.setACL(groupACL); - -// Parse.User.requestPasswordReset('email@example.com').then( -// data => { -// // The current user is now set to user. -// }, -// error => { -// // The token could not be validated. -// }, -// ); - -// Parse.User.requestEmailVerification('email@example.com').then( -// data => { -// // The current user is now set to user. -// }, -// error => { -// // The token could not be validated. -// }, -// ); - -// // By specifying no write privileges for the ACL, we can ensure the role cannot be altered. -// const role = new Parse.Role('Administrator', groupACL); -// role.getUsers().add(userList[0]); -// role.getRoles().add(role); -// role.save(); - -// Parse.User.logOut().then(data => { -// // logged out -// }); -// } - -// function test_facebook_util() { -// Parse.FacebookUtils.init({ -// appId: 'YOUR_APP_ID', // Facebook App ID -// channelUrl: '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File -// cookie: true, // enable cookies to allow Parse to access the session -// xfbml: true, // parse XFBML -// }); - -// Parse.FacebookUtils.logIn(null, { -// success: (user: Parse.User) => { -// if (!user.existed()) { -// alert('User signed up and logged in through Facebook!'); -// } else { -// alert('User logged in through Facebook!'); -// } -// }, -// error: (user: Parse.User, error: any) => { -// alert('User cancelled the Facebook login or did not fully authorize.'); -// }, -// }); - -// const user = Parse.User.current()!; - -// if (!Parse.FacebookUtils.isLinked(user)) { -// Parse.FacebookUtils.link(user, null, { -// success: (user: any) => { -// alert('Woohoo, user logged in with Facebook!'); -// }, -// error: (user: any, error: any) => { -// alert('User cancelled the Facebook login or did not fully authorize.'); -// }, -// }); -// } - -// Parse.FacebookUtils.unlink(user, { -// success: (user: Parse.User) => { -// alert('The user is no longer associated with their Facebook account.'); -// }, -// }); -// } - -// async function test_cloud_functions() { -// Parse.Cloud.run( -// 'hello', -// {}, -// { -// success: (result: any) => { -// // result -// }, -// error: (error: any) => {}, -// }, -// ); - -// // $ExpectType any -// await Parse.Cloud.run('SomeFunction'); - -// // $ExpectType any -// await Parse.Cloud.run('SomeFunction', { something: 'whatever' }); - -// // $ExpectType any -// await Parse.Cloud.run('SomeFunction', null, { useMasterKey: true }); - -// // ExpectType boolean -// await Parse.Cloud.run<() => boolean>('SomeFunction'); - -// // $ExpectType boolean -// await Parse.Cloud.run<() => boolean>('SomeFunction', null); - -// // $ExpectType boolean -// await Parse.Cloud.run<() => boolean>('SomeFunction', null, { useMasterKey: true }); - -// // $ExpectType number -// await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { paramA: 'hello' }); - -// // @ts-expect-error -// await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction'); - -// // @ts-expect-error -// await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { paramZ: 'hello' }); - -// // @ts-expect-error -// await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', null, { useMasterKey: true }); - -// // @ts-expect-error -// await Parse.Cloud.run<(params: string) => any>('SomeFunction', 'hello'); - -// Parse.Cloud.afterDelete('MyCustomClass', (request: Parse.Cloud.AfterDeleteRequest) => { -// // result -// }); - -// Parse.Cloud.afterSave('MyCustomClass', (request: Parse.Cloud.AfterSaveRequest) => { -// if (!request.context) { -// throw new Error('Request context should be defined'); -// } -// // result -// }); - -// Parse.Cloud.beforeDelete('MyCustomClass', (request: Parse.Cloud.BeforeDeleteRequest) => { -// // result -// }); - -// Parse.Cloud.beforeDelete('MyCustomClass', async (request: Parse.Cloud.BeforeDeleteRequest) => { -// // result -// }); - -// interface BeforeSaveObject { -// immutable: boolean; -// } - -// Parse.Cloud.beforeSave('MyCustomClass', async request => { -// if (request.object.isNew()) { -// if (!request.object.has('immutable')) throw new Error('Field immutable is required'); -// } else { -// const original = request.original; -// if (original == null) { -// // When the object is not new, request.original must be defined -// throw new Error('Original must me defined for an existing object'); -// } - -// if (original.get('immutable') !== request.object.get('immutable')) { -// throw new Error('This field cannot be changed'); -// } -// } -// if (!request.context) { -// throw new Error('Request context should be defined'); -// } -// }); - -// Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { -// const query = request.query; // the Parse.Query -// const user = request.user; // the user -// const isMaster = request.master; // if the query is run with masterKey -// const isCount = request.count; // if the query is a count operation (available on parse-server 2.4.0 or up) -// const isGet = request.isGet; // if the query is a get operation - -// // All possible read preferences -// request.readPreference = Parse.Cloud.ReadPreferenceOption.Primary; -// request.readPreference = Parse.Cloud.ReadPreferenceOption.PrimaryPreferred; -// request.readPreference = Parse.Cloud.ReadPreferenceOption.Secondary; -// request.readPreference = Parse.Cloud.ReadPreferenceOption.SecondaryPreferred; -// request.readPreference = Parse.Cloud.ReadPreferenceOption.Nearest; -// }); - -// Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { -// const query = request.query; // the Parse.Query - -// return new Parse.Query('QueryMe!'); -// }); - -// Parse.Cloud.beforeFind('MyCustomClass', async (request: Parse.Cloud.BeforeFindRequest) => { -// const query = request.query; // the Parse.Query - -// return new Parse.Query('QueryMe, IN THE FUTURE!'); -// }); - -// Parse.Cloud.afterFind('MyCustomClass', async (request: Parse.Cloud.AfterFindRequest) => { -// return new Parse.Object('MyCustomClass'); -// }); - -// Parse.Cloud.beforeLogin((request: Parse.Cloud.TriggerRequest) => { -// return Promise.resolve(); -// }); - -// Parse.Cloud.afterLogin((request: Parse.Cloud.TriggerRequest) => { -// return Promise.resolve(); -// }); - -// Parse.Cloud.afterLogout((request: Parse.Cloud.TriggerRequest) => { -// return Promise.resolve(); -// }); - -// Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => { -// return Promise.resolve(new Parse.File('myFile.txt', { base64: '' })); -// }); - -// Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => {}); - -// Parse.Cloud.beforeDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); - -// Parse.Cloud.afterDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); - -// Parse.Cloud.define('AFunc', (request: Parse.Cloud.FunctionRequest) => { -// return 'Some result'; -// }); - -// Parse.Cloud.define( -// 'AFunc', -// (request: Parse.Cloud.FunctionRequest) => { -// return 'Some result'; -// }, -// { -// requireUser: true, -// requireMaster: true, -// validateMasterKey: true, -// skipWithMasterKey: true, -// requireAnyUserRoles: ['a'], -// requireAllUserRoles: ['a'], -// fields: { -// name: { -// type: String, -// constant: true, -// default: true, -// options: [], -// error: 'invalid field.', -// }, -// }, -// requireUserKeys: { -// name: { -// type: String, -// constant: true, -// default: true, -// options: [], -// error: 'invalid field.', -// }, -// }, -// }, -// ); - -// Parse.Cloud.define('AFunc', request => { -// // $ExpectType Params -// request.params; - -// // $ExpectType any -// request.params.anything; -// }); - -// Parse.Cloud.define<() => void>('AFunc', request => { -// // $ExpectType {} -// request.params; -// }); - -// Parse.Cloud.define<(params: { something: string }) => number>('AFunc', request => { -// // $ExpectType { something: string; } -// request.params; - -// // @ts-expect-error -// request.params.somethingElse; - -// return 123; -// }); - -// // @ts-expect-error -// Parse.Cloud.define('AFunc'); - -// // @ts-expect-error -// Parse.Cloud.define<() => string>('AFunc', () => 123); - -// // @ts-expect-error -// Parse.Cloud.define<(params: string) => number>('AFunc', () => 123); - -// Parse.Cloud.job('AJob', (request: Parse.Cloud.JobRequest) => { -// request.message('Message to associate with this job run'); -// }); - -// Parse.Cloud.startJob('AJob', {}).then(v => v); - -// Parse.Cloud.getJobStatus('AJob').then(v => v); - -// Parse.Cloud.getJobsData().then(v => v); -// } - -// class PlaceObject extends Parse.Object {} - -// function test_geo_points() { -// let point = new Parse.GeoPoint(); -// // @ts-expect-error -// point = new Parse.GeoPoint('40.0'); -// // @ts-expect-error -// point = new Parse.GeoPoint(40.0); -// // @ts-expect-error -// point = new Parse.GeoPoint([40.0, -30.0, 20.0]); -// point = new Parse.GeoPoint([40.0, -30.0]); -// point = new Parse.GeoPoint(40.0, -30.0); -// point = new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 }); - -// const userObject = Parse.User.current>()!; - -// // User's location -// const userGeoPoint = userObject.get('location'); - -// // Create a query for places -// const query = new Parse.Query(Parse.User); -// // Interested in locations near user. -// query.near('location', userGeoPoint); -// // Limit what could be a lot of points. -// query.limit(10); - -// const southwestOfSF = new Parse.GeoPoint(37.708813, -122.526398); -// const northeastOfSF = new Parse.GeoPoint(37.822802, -122.373962); - -// const query2 = new Parse.Query(PlaceObject); -// query2.withinGeoBox('location', southwestOfSF, northeastOfSF); - -// const query3 = new Parse.Query('PlaceObject').find().then((o: Parse.Object[]) => {}); -// } - -// function test_push() { -// Parse.Push.send( -// { -// channels: ['Gia nts', 'Mets'], -// data: { -// alert: 'The Giants won against the Mets 2-3.', -// }, -// }, -// { -// success: () => { -// // Push was successful -// }, -// error: (error: any) => { -// // Handle error -// }, -// }, -// ); - -// const query = new Parse.Query(Parse.Installation); -// query.equalTo('injuryReports', true); - -// Parse.Push.send( -// { -// where: query, // Set our Installation query -// data: { -// alert: 'Willie Hayes injured by own pop fly.', -// }, -// }, -// { -// success() { -// // Push was successful -// }, -// error(error: any) { -// // Handle error -// }, -// }, -// ); -// } - -// function test_batch_operations() { -// const game1 = new Game(); -// const game2 = new Game(); -// const games = [game1, game2]; - -// // Master key -// Parse.Object.saveAll(games, { useMasterKey: true }); -// Parse.Object.destroyAll(games, { useMasterKey: true }); -// Parse.Object.fetchAll(games, { useMasterKey: true }); -// Parse.Object.fetchAllIfNeeded(games, { useMasterKey: true }); - -// // Session token -// Parse.Object.saveAll(games, { sessionToken: '' }); -// Parse.Object.destroyAll(games, { sessionToken: '' }); -// Parse.Object.fetchAll(games, { sessionToken: '' }); -// Parse.Object.fetchAllIfNeeded(games, { sessionToken: '' }); -// } - -// async function test_query_subscribe() { -// // create new query from Game object type -// const query = new Parse.Query(Game); - -// // create subscription to Game object -// // Without a token -// // $ExpectType LiveQuerySubscription -// let subscription = await query.subscribe(); - -// // With a session token -// // $ExpectType LiveQuerySubscription -// subscription = await query.subscribe(new Parse.User().getSessionToken()); - -// // listen for new Game objects created on Parse server -// subscription.on('create', (game: any) => { -// console.log(game); -// }); - -// // unsubscribe -// subscription.unsubscribe(); -// } - -// function test_serverURL() { -// Parse.serverURL = 'http://localhost:1337/parse'; -// } -// function test_polygon() { -// const point = new Parse.GeoPoint(1, 2); -// const polygon1 = new Parse.Polygon([ -// [0, 0], -// [1, 0], -// [1, 1], -// [0, 1], -// ]); -// const polygon2 = new Parse.Polygon([point, point, point]); -// polygon1.equals(polygon2); -// polygon1.containsPoint(point); - -// const query = new Parse.Query('TestObject'); -// query.polygonContains('key', point); -// query.withinPolygon('key', [ -// [0, 0], -// [1, 0], -// [1, 1], -// [0, 1], -// ]); -// } - -// async function test_local_datastore() { -// Parse.enableLocalDatastore(); -// const name = 'test_pin'; -// const obj = new Parse.Object('TestObject'); -// await obj.pin(); -// await obj.unPin(); -// await obj.isPinned(); -// await obj.pinWithName(name); -// await obj.unPinWithName(name); -// await obj.fetchFromLocalDatastore(); - -// await Parse.Object.pinAll([obj]); -// await Parse.Object.unPinAll([obj]); -// await Parse.Object.pinAllWithName(name, [obj]); -// await Parse.Object.unPinAllWithName(name, [obj]); -// await Parse.Object.unPinAllObjects(); -// await Parse.Object.unPinAllObjectsWithName(name); - -// const flag = Parse.isLocalDatastoreEnabled(); -// const LDS = await Parse.dumpLocalDatastore(); - -// const query = new Parse.Query('TestObject'); -// query.fromPin(); -// query.fromPinWithName(name); -// query.fromLocalDatastore(); - -// Parse.setLocalDatastoreController({}); -// } - -// async function test_from_network() { -// const obj = new Parse.Object('TestObject'); -// await obj.save(); - -// const query = new Parse.Query('TestObject'); -// query.fromNetwork(); -// } - -// async function test_cancel_query() { -// const obj = new Parse.Object('TestObject'); -// await obj.save(); - -// const query = new Parse.Query('TestObject'); -// query.fromNetwork().find(); -// query.cancel(); -// } - -// type FieldType = -// | string -// | number -// | boolean -// | Date -// | Parse.File -// | Parse.GeoPoint -// | any[] -// | object -// | Parse.Pointer -// | Parse.Polygon -// | Parse.Relation; -// async function test_schema( -// anyField: FieldType, -// notString: Exclude, -// notNumber: Exclude, -// notboolean: Exclude, -// notDate: Exclude, -// notFile: Exclude, -// notGeopoint: Exclude, -// notArray: Exclude, -// notObject: Exclude, -// notPointer: Exclude, -// notPolygon: Exclude, -// ) { -// // $ExpectType RestSchema[] -// await Parse.Schema.all(); - -// const schema = new Parse.Schema('TestSchema'); - -// schema.addArray('arrayField'); -// schema.addArray('arrayField', { defaultValue: [1, 2, 3, 4] }); -// // @ts-expect-error -// schema.addArray('arrayField', { defaultValue: notArray }); - -// /** -// * @todo Enable type check for default value -// */ -// schema.addField('defaultFieldString'); -// schema.addField('defaultFieldString', 'String', { defaultValue: anyField }); -// schema.addField('defaultFieldString', 'Number'); -// schema.addField('defaultFieldString', 'Relation'); -// // @ts-expect-error -// schema.addField('defaultFieldString', 'String', 'Invalid Options'); - -// schema.addString('field'); -// schema.addString('field', { defaultValue: 'some string', required: true }); -// // @ts-expect-error -// schema.addString('field', { defaultValue: notString }); - -// schema.addNumber('field'); -// schema.addNumber('field', { defaultValue: 0, required: true }); -// // @ts-expect-error -// schema.addNumber('field', { defaultValue: notNumber }); - -// schema.addBoolean('field'); -// schema.addBoolean('field', { defaultValue: true, required: true }); -// // @ts-expect-error -// schema.addBoolean('field', { defaultValue: notboolean }); - -// schema.addDate('field'); -// schema.addDate('field', { defaultValue: new Date(), required: true }); -// // @ts-expect-error -// schema.addDate('field', { defaultValue: notDate }); - -// schema.addFile('field'); -// schema.addFile('field', { defaultValue: new Parse.File('myfile', []), required: true }); -// // @ts-expect-error -// schema.addFile('field', { defaultValue: notFile }); - -// schema.addGeoPoint('field'); -// schema.addGeoPoint('field', { defaultValue: new Parse.GeoPoint(), required: true }); -// // @ts-expect-error -// schema.addGeoPoint('field', { defaultValue: notGeopoint }); - -// schema.addPolygon('field'); -// schema.addPolygon('field', { defaultValue: new Parse.Polygon([]), required: true }); -// // @ts-expect-error -// schema.addPolygon('field', { defaultValue: notPolygon }); - -// schema.addObject('field'); -// schema.addObject('field', { defaultValue: {}, required: true }); -// schema.addObject('field', { defaultValue: { abc: 'def' } }); -// // @ts-expect-error -// schema.addObject('field', { defaultValue: notObject }); - -// schema.addPointer('field', 'SomeClass'); -// // @ts-expect-error -// schema.addPointer('field'); -// /** -// * @todo Infer defaultValue type from targetClass -// */ -// schema.addPointer('field', '_User', { defaultValue: new Parse.User().toPointer(), required: true }); -// // @ts-expect-error -// schema.addPointer('field', { defaultValue: notPointer }); - -// schema.addRelation('field', 'SomeClass'); -// // @ts-expect-error -// schema.addRelation('field'); -// // @ts-expect-error -// schema.addRelation('field', 'SomeClass', 'anything'); - -// schema.addIndex('testIndex', { stringField: 'text' }); -// schema.addIndex('testIndex', { stringField: 1 }); -// schema.addIndex('testIndex', { stringField: -1 }); -// // @ts-expect-error -// schema.addIndex('testIndex', { stringField: true }); - -// schema.deleteField('defaultFieldString'); -// schema.deleteIndex('testIndex'); -// schema.delete().then(results => {}); -// // $ExpectType RestSchema -// await schema.get(); -// schema.purge().then(results => {}); -// schema.save().then(results => {}); -// schema.update().then(results => {}); - -// function testGenericType() { -// interface iTestAttributes { -// arrField: any[]; -// boolField: boolean; -// stringField: string; -// numField: number; -// dateField: Date; -// fileField: Parse.File; -// geoPointField: Parse.GeoPoint; -// polygonField: Parse.Polygon; -// objectField: object; -// relationField: Parse.Relation; -// pointerField: Parse.Pointer | Parse.Object; -// } -// class TestObject extends Parse.Object {} - -// const schema = new Parse.Schema('TestObject'); -// schema.addArray('arrField'); -// schema.addBoolean('boolField'); -// schema.addDate('dateField'); -// schema.addFile('fileField'); -// schema.addGeoPoint('geoPointField'); -// schema.addNumber('numField'); -// schema.addObject('objectField'); -// schema.addPointer('pointerField', 'FooClass'); -// schema.addPolygon('polygonField'); -// schema.addRelation('relationField', 'FooClass'); -// schema.addString('stringField'); - -// // @ts-expect-error -// schema.addArray('wrong'); -// // @ts-expect-error -// schema.addBoolean('wrong'); -// // @ts-expect-error -// schema.addDate('wrong'); -// // @ts-expect-error -// schema.addFile('wrong'); -// // @ts-expect-error -// schema.addGeoPoint('wrong'); -// // @ts-expect-error -// schema.addNumber('wrong'); -// // @ts-expect-error -// schema.addObject('wrong'); -// // @ts-expect-error -// schema.addPointer('wrong', 'FooClass'); -// // @ts-expect-error -// schema.addPolygon('wrong'); -// // @ts-expect-error -// schema.addRelation('wrong', 'FooClass'); -// // @ts-expect-error -// schema.addString('wrong'); -// } -// } - -// function testObject() { -// function testConstructor() { -// // $ExpectType Object -// new Parse.Object(); - -// // $ExpectType Object -// new Parse.Object('TestObject'); - -// // $ExpectType Object<{ example: number; }> -// new Parse.Object('TestObject', { example: 100 }); - -// // $ExpectType Object<{ example: boolean; }> -// new Parse.Object<{ example: boolean }>('TestObject', { example: true }); - -// // $ExpectType Object<{ example: string; }> -// new Parse.Object('TestObject', { example: 'hello' }, { ignoreValidation: true }); - -// // @ts-expect-error -// new Parse.Object<{ example: string }>('TestObject'); - -// // @ts-expect-error -// new Parse.Object<{ example: boolean }>('TestObject', { example: 'hello' }); -// } - -// function testStaticMethods() { -// async function testSaveAll(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType Object[] -// await Parse.Object.saveAll([objUntyped]); - -// // $ExpectType Object<{ example: string; }>[] -// await Parse.Object.saveAll([objTyped]); - -// // $ExpectType [Object, Object<{ example: string; }>] -// await Parse.Object.saveAll<[typeof objUntyped, typeof objTyped]>([objUntyped, objTyped]); - -// // @ts-expect-error -// await Parse.Object.saveAll([123]); -// } -// } - -// function testAttributes(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType any -// objUntyped.attributes.whatever; - -// // $ExpectType string -// objTyped.attributes.example; - -// // @ts-expect-error -// objTyped.attributes.other; -// } - -// function testAdd(objUntyped: Parse.Object, objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>) { -// // $ExpectType false | Object -// objUntyped.add('whatever', 'hello'); - -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.add('stringList', 'hello'); - -// // @ts-expect-error -// objTyped.add('stringList', 100); - -// // @ts-expect-error -// objTyped.add('thing', true); - -// // @ts-expect-error -// objTyped.add('whatever', 'hello'); -// } - -// function testAddAll(objUntyped: Parse.Object, objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>) { -// // $ExpectType false | Object -// objUntyped.addAll('whatever', ['hello', 100]); - -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.addAll('stringList', ['hello']); - -// // @ts-expect-error -// objTyped.addAll('stringList', [100]); +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-unused-expressions, @typescript-eslint/no-empty-object-type, no-empty */ -// // @ts-expect-error -// objTyped.addAll('thing', [true]); +// Run the following command to get number of failed tests +// $ npm run test:types 2>&1 | tee temp.txt; grep 'ERROR:' temp.txt -c; rm temp.txt; -// // @ts-expect-error -// objTyped.addAll('whatever', ['hello']); -// } - -// function testAddAllUnique( -// objUntyped: Parse.Object, -// objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>, -// ) { -// // $ExpectType false | Object -// objUntyped.addAllUnique('whatever', ['hello', 100]); - -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.addAllUnique('stringList', ['hello']); +import Parse from 'parse'; +import ParseNode from 'parse/node'; +import ParseRN from 'parse/react-native'; + +class GameScore extends Parse.Object { + constructor(options?: any) { + super('GameScore', options); + } +} + +class Game extends Parse.Object { + constructor(options?: any) { + super('Game', options); + } +} + +function test_config() { + Parse.Config.save({ foo: 'bar' }, { foo: true }); + Parse.Config.get({ useMasterKey: true }); +} + +function test_object() { + const game = new Game(); + game + .save(null, { + useMasterKey: true, + sessionToken: 'sometoken', + cascadeSave: false, + }) + .then(result => result); + + if (!game.isNew()) { + } + + if (game.toPointer().className !== 'Game') { + } + + game.fetch({}); + + // Create a new instance of that class. + const gameScore = new GameScore(); + + gameScore.set('score', 1337); + gameScore.set('playerName', 'Sean Plott'); + gameScore.set('cheatMode', false); + + // Setting attrs using object + gameScore.set({ + level: '10', + difficult: 15, + }); + + const score = gameScore.get('score'); + const playerName = gameScore.get('playerName'); + const cheatMode = gameScore.get('cheatMode'); + + gameScore.increment('score'); + gameScore.addUnique('skills', 'flying'); + gameScore.addUnique('skills', 'kungfu'); + gameScore.addAll('skills', ['kungfu']); + gameScore.addAllUnique('skills', ['kungfu']); + gameScore.remove('skills', 'flying'); + gameScore.removeAll('skills', ['kungFu']); + game.set('gameScore', gameScore); + + const gameCopy = Game.fromJSON(JSON.parse(JSON.stringify(game)), true); + + const object = new Parse.Object('TestObject'); + object.equals(gameScore); + object.fetchWithInclude(['key1', 'key2']); +} + +function test_errors() { + try { + throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'sdfds'); + } catch (error) { + if (error.code !== 1) { + } + } +} + +function test_query() { + const gameScore = new GameScore(); + + const query = new Parse.Query(GameScore); + query.equalTo('playerName', 'Dan Stemkoski'); + query.notEqualTo('playerName', 'Michael Yabuti'); + query.fullText('playerName', 'dan', { + language: 'en', + caseSensitive: false, + diacriticSensitive: true, + }); + query.greaterThan('playerAge', 18); + query.eachBatch(objs => Promise.resolve(), { batchSize: 10 }); + query.each(score => Promise.resolve()); + query.hint('_id_'); + query.explain(true); + query.limit(10); + query.skip(10); + + // Sorts the results in ascending order by the score field + query.ascending('score'); + + // Sorts the results in descending order by the score field + query.descending('score'); + + // Restricts to wins < 50 + query.lessThan('wins', 50); + + // Restricts to wins <= 50 + query.lessThanOrEqualTo('wins', 50); + + // Restricts to wins > 50 + query.greaterThan('wins', 50); + + // Restricts to wins >= 50 + query.greaterThanOrEqualTo('wins', 50); + + query.containedBy('place', ['1', '2']); + // Finds scores from any of Jonathan, Dario, or Shawn + query.containedIn('playerName', ['Jonathan Walsh', 'Dario Wunsch', 'Shawn Simon']); + + // Finds scores from anyone who is neither Jonathan, Dario, nor Shawn + query.notContainedIn('playerName', ['Jonathan Walsh', 'Dario Wunsch', 'Shawn Simon']); + + // Finds objects that have the score set + query.exists('score'); + + // Finds objects that don't have the score set + query.doesNotExist('score'); + query.matchesKeyInQuery('hometown', 'city', query); + query.doesNotMatchKeyInQuery('hometown', 'city', query); + query.select('score', 'playerName'); + + // Find objects where the array in arrayKey contains 2. + query.equalTo('arrayKey', 2); + + // Find objects where the array in arrayKey contains all of the elements 2, 3, and 4. + query.containsAll('arrayKey', [2, 3, 4]); + query.containsAllStartingWith('arrayKey', ['2', '3', '4']); + + query.startsWith('name', "Big Daddy's"); + query.equalTo('score', gameScore); + query.exists('score'); + query.include('score'); + query.include(['score.team']); + query.includeAll(); + query.sortByTextScore(); + // Find objects that match the aggregation pipeline + query.aggregate({ + group: { + objectId: '$name', + }, + }); + + query.aggregate({ + count: 'total', + }); + + query.aggregate({ + lookup: { + from: 'Collection', + foreignField: 'id', + localField: 'id', + as: 'result', + }, + }); + query.aggregate({ + lookup: { + from: 'Target', + let: { foo: 'bar', baz: 123 }, + pipeline: [], + as: 'result', + }, + }); + + query.aggregate({ + graphLookup: { + from: 'Target', + connectFromField: 'objectId', + connectToField: 'newId', + as: 'result', + }, + }); + + query.aggregate({ + facet: { + foo: [ + { + count: 'total', + }, + ], + bar: [ + { + group: { + objectId: '$name', + }, + }, + ], + }, + }); + + query.aggregate({ + unwind: '$field', + }); + + query.aggregate({ + unwind: { + path: '$field', + includeArrayIndex: 'newIndex', + preserveNullAndEmptyArrays: true, + }, + }); + + // Find objects with distinct key + query.distinct('name'); + + const testQuery = Parse.Query.or(query, query); +} + +function test_query_exclude() { + const gameScore = new GameScore(); + + const query = new Parse.Query(GameScore); + + // Show all keys, except the specified key. + query.exclude('place'); + + const testQuery = Parse.Query.or(query, query); +} + +async function test_query_promise() { + // Test promise with a query + const findQuery = new Parse.Query('Test'); + findQuery + .find() + .then(() => { + // success + }) + .catch(() => { + // error + }); + + const getQuery = new Parse.Query('Test'); + try { + await getQuery.get('objectId'); + } catch (error) { + // noop + } + + await getQuery.map((score, index) => score.increment('score', index)); + await getQuery.reduce((accum, score, index) => (accum += score.get('score')), 0); + await getQuery.reduce((accum, score, index) => (accum += score.get('score')), 0, { + batchSize: 200, + }); + await getQuery.filter(scores => scores.get('score') > 0); + await getQuery.filter(scores => scores.get('score') > 0, { batchSize: 10 }); +} + +async function test_live_query() { + const subscription = await new Parse.Query('Test').subscribe(); + subscription.on('close', object => { + // $ExpectType Object + object; + }); + subscription.on('create', object => { + // $ExpectType Object + object; + }); + subscription.on('delete', object => { + // $ExpectType Object + object; + }); + subscription.on('enter', object => { + // $ExpectType Object + object; + }); + subscription.on('leave', object => { + // $ExpectType Object + object; + }); + subscription.on('open', object => { + // $ExpectType Object + object; + }); + subscription.on('update', object => { + // $ExpectType Object + object; + }); +} + +function test_anonymous_utils() { + // $ExpectType boolean + Parse.AnonymousUtils.isLinked(new Parse.User()); + // $ExpectType Promise> + Parse.AnonymousUtils.link(new Parse.User(), { useMasterKey: true, sessionToken: '' }); + // $ExpectType Promise> + Parse.AnonymousUtils.logIn({ useMasterKey: true, sessionToken: '' }); +} + +function return_a_query(): Parse.Query { + return new Parse.Query(Game); +} + +function test_each() { + new Parse.Query(Game).each(game => { + // $ExpectType Game + game; + }); +} + +function test_file() { + const base64 = 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE='; + let file = new Parse.File('myfile.txt', { base64 }); + + file = new Parse.File('nana', { uri: 'http://example.com/image.jps' }); + + const bytes = [0xbe, 0xef, 0xca, 0xfe]; + file = new Parse.File('myfile.txt', bytes); + + file = new Parse.File('myfile.zzz', new Blob(), 'image/png'); + + const src = file.url(); + const secure = file.url({ forceSecure: true }); + + file.save(); + file.cancel(); + file.destroy(); +} + +function test_file_tags_and_metadata() { + const base64 = 'V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE='; + const file = new Parse.File('myfile.txt', { base64 }); + file.setTags({ ownerId: 42, status: 'okay' }); + file.addTag('labes', 'one'); + file.setMetadata({ contentType: 'plain/text', contentLength: 579 }); + file.addMetadata('author', 'John Doe'); + + const tags = file.tags(); + const ownerId = tags['ownerId']; + + const metadata = file.metadata(); + const contentType = metadata['contentType']; +} + +function test_analytics() { + const dimensions = { + // Define ranges to bucket data points into meaningful segments + priceRange: '1000-1500', + // Did the user filter the query? + source: 'craigslist', + // Do searches happen more often on weekdays or weekends? + dayType: 'weekday', + }; + // Send the dimensions to Parse along with the 'search' event + Parse.Analytics.track('search', dimensions); + + const codeString = '404'; + Parse.Analytics.track('error', { code: codeString }); +} + +function test_relation() { + const game1 = new Game(); + const game2 = new Game(); + + new Parse.User() + .relation('games') + .query() + .find() + .then((g: Game[]) => {}); + new Parse.User().relation('games').add(game1); + new Parse.User().relation('games').add([game1, game2]); + + new Parse.User().relation('games').remove(game1); + new Parse.User().relation('games').remove([game1, game2]); +} + +function test_user() { + const user = new Parse.User(); + user.set('username', 'my name'); + user.set('password', 'my pass'); + user.set('email', 'email@example.com'); + user.signUp(null, { useMasterKey: true }); + + const anotherUser: Parse.User = Parse.User.fromJSON({}); + anotherUser.set('email', 'email@example.com'); +} + +async function test_user_currentAsync() { + const asyncUser = await Parse.User.currentAsync(); + if (asyncUser) { + asyncUser.set('email', 'email@example.com'); + } else if (asyncUser === null) { + Parse.User.logIn('email@example.com', 'my pass'); + } +} + +function test_user_acl_roles() { + const user = new Parse.User(); + user.set('username', 'my name'); + user.set('password', 'my pass'); + user.set('email', 'email@example.com'); + + // other fields can be set just like with Parse.Object + user.set('phone', '415-392-0202'); + + const currentUser = Parse.User.current(); + if (currentUser) { + // do stuff with the user + } else { + // show the signup or login page + } + + Parse.User.become('session-token-here').then( + user => { + // The current user is now set to user. + }, + error => { + // The token could not be validated. + } + ); + + Parse.User.hydrate({}).then( + user => { + // The current user is now set to user. + }, + error => { + // The token could not be validated. + } + ); + + const game = new Game(); + game.set('gameScore', new GameScore()); + game.setACL(new Parse.ACL(Parse.User.current())); + game.save().then((game: Game) => {}); + game.save(null, { useMasterKey: true }); + game.save({ score: '10' }, { useMasterKey: true }).then( + game => { + // Update game then revert it to the last saved state. + game.set('score', '20'); + game.revert('score'); + game.revert('score', 'ACL'); + game.revert(); + }, + error => { + // The save failed + } + ); + + const groupACL = new Parse.ACL(); + + const userList: Parse.User[] = [Parse.User.current()!]; + // userList is an array with the users we are sending this message to. + for (const userListItem of userList) { + groupACL.setReadAccess(userListItem, true); + groupACL.setWriteAccess(userListItem, true); + } + + groupACL.setPublicReadAccess(true); + + game.setACL(groupACL); + + Parse.User.requestPasswordReset('email@example.com').then( + data => { + // The current user is now set to user. + }, + error => { + // The token could not be validated. + } + ); + + Parse.User.requestEmailVerification('email@example.com').then( + data => { + // The current user is now set to user. + }, + error => { + // The token could not be validated. + } + ); + + // By specifying no write privileges for the ACL, we can ensure the role cannot be altered. + const role = new Parse.Role('Administrator', groupACL); + role.getUsers().add(userList[0]); + role.getRoles().add(role); + role.save(); + + Parse.User.logOut().then(data => { + // logged out + }); +} + +function test_facebook_util() { + Parse.FacebookUtils.init({ + appId: 'YOUR_APP_ID', // Facebook App ID + channelUrl: '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File + cookie: true, // enable cookies to allow Parse to access the session + xfbml: true, // parse XFBML + }); + + Parse.FacebookUtils.logIn(null, { + success: (user: Parse.User) => { + if (!user.existed()) { + alert('User signed up and logged in through Facebook!'); + } else { + alert('User logged in through Facebook!'); + } + }, + error: (user: Parse.User, error: any) => { + alert('User cancelled the Facebook login or did not fully authorize.'); + }, + }); + + const user = Parse.User.current()!; + + if (!Parse.FacebookUtils.isLinked(user)) { + Parse.FacebookUtils.link(user, null, { + success: (user: any) => { + alert('Woohoo, user logged in with Facebook!'); + }, + error: (user: any, error: any) => { + alert('User cancelled the Facebook login or did not fully authorize.'); + }, + }); + } + + Parse.FacebookUtils.unlink(user, { + success: (user: Parse.User) => { + alert('The user is no longer associated with their Facebook account.'); + }, + }); +} + +async function test_cloud_functions() { + Parse.Cloud.run( + 'hello', + {}, + { + success: (result: any) => { + // result + }, + error: (error: any) => {}, + } + ); + + // $ExpectType any + await Parse.Cloud.run('SomeFunction'); + + // $ExpectType any + await Parse.Cloud.run('SomeFunction', { something: 'whatever' }); + + // $ExpectType any + await Parse.Cloud.run('SomeFunction', null, { useMasterKey: true }); + + // ExpectType boolean + await Parse.Cloud.run<() => boolean>('SomeFunction'); + + // $ExpectType boolean + await Parse.Cloud.run<() => boolean>('SomeFunction', null); + + // $ExpectType boolean + await Parse.Cloud.run<() => boolean>('SomeFunction', null, { useMasterKey: true }); + + // $ExpectType number + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { + paramA: 'hello', + }); + + // @ts-expect-error + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction'); + + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', { + // @ts-expect-error + paramZ: 'hello', + }); + + // @ts-expect-error + await Parse.Cloud.run<(params: { paramA: string }) => number>('SomeFunction', null, { + useMasterKey: true, + }); + + // @ts-expect-error + await Parse.Cloud.run<(params: string) => any>('SomeFunction', 'hello'); + + Parse.Cloud.afterDelete('MyCustomClass', (request: Parse.Cloud.AfterDeleteRequest) => { + // result + }); + + Parse.Cloud.afterSave('MyCustomClass', (request: Parse.Cloud.AfterSaveRequest) => { + if (!request.context) { + throw new Error('Request context should be defined'); + } + // result + }); + + Parse.Cloud.beforeDelete('MyCustomClass', (request: Parse.Cloud.BeforeDeleteRequest) => { + // result + }); + + Parse.Cloud.beforeDelete('MyCustomClass', async (request: Parse.Cloud.BeforeDeleteRequest) => { + // result + }); + + interface BeforeSaveObject { + immutable: boolean; + } + + Parse.Cloud.beforeSave('MyCustomClass', async request => { + if (request.object.isNew()) { + if (!request.object.has('immutable')) throw new Error('Field immutable is required'); + } else { + const original = request.original; + if (original == null) { + // When the object is not new, request.original must be defined + throw new Error('Original must me defined for an existing object'); + } + + if (original.get('immutable') !== request.object.get('immutable')) { + throw new Error('This field cannot be changed'); + } + } + if (!request.context) { + throw new Error('Request context should be defined'); + } + }); + + Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { + const query = request.query; // the Parse.Query + const user = request.user; // the user + const isMaster = request.master; // if the query is run with masterKey + const isCount = request.count; // if the query is a count operation (available on parse-server 2.4.0 or up) + const isGet = request.isGet; // if the query is a get operation + + // All possible read preferences + request.readPreference = Parse.Cloud.ReadPreferenceOption.Primary; + request.readPreference = Parse.Cloud.ReadPreferenceOption.PrimaryPreferred; + request.readPreference = Parse.Cloud.ReadPreferenceOption.Secondary; + request.readPreference = Parse.Cloud.ReadPreferenceOption.SecondaryPreferred; + request.readPreference = Parse.Cloud.ReadPreferenceOption.Nearest; + }); + + Parse.Cloud.beforeFind('MyCustomClass', (request: Parse.Cloud.BeforeFindRequest) => { + const query = request.query; // the Parse.Query + + return new Parse.Query('QueryMe!'); + }); + + Parse.Cloud.beforeFind('MyCustomClass', async (request: Parse.Cloud.BeforeFindRequest) => { + const query = request.query; // the Parse.Query + + return new Parse.Query('QueryMe, IN THE FUTURE!'); + }); + + Parse.Cloud.afterFind('MyCustomClass', async (request: Parse.Cloud.AfterFindRequest) => { + return new Parse.Object('MyCustomClass'); + }); + + Parse.Cloud.beforeLogin((request: Parse.Cloud.TriggerRequest) => { + return Promise.resolve(); + }); + + Parse.Cloud.afterLogin((request: Parse.Cloud.TriggerRequest) => { + return Promise.resolve(); + }); + + Parse.Cloud.afterLogout((request: Parse.Cloud.TriggerRequest) => { + return Promise.resolve(); + }); + + Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => { + return Promise.resolve(new Parse.File('myFile.txt', { base64: '' })); + }); + + Parse.Cloud.beforeSaveFile((request: Parse.Cloud.FileTriggerRequest) => {}); + + Parse.Cloud.beforeDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); + + Parse.Cloud.afterDeleteFile((request: Parse.Cloud.FileTriggerRequest) => {}); + + Parse.Cloud.define('AFunc', (request: Parse.Cloud.FunctionRequest) => { + return 'Some result'; + }); + + Parse.Cloud.define( + 'AFunc', + (request: Parse.Cloud.FunctionRequest) => { + return 'Some result'; + }, + { + requireUser: true, + requireMaster: true, + validateMasterKey: true, + skipWithMasterKey: true, + requireAnyUserRoles: ['a'], + requireAllUserRoles: ['a'], + fields: { + name: { + type: String, + constant: true, + default: true, + options: [], + error: 'invalid field.', + }, + }, + requireUserKeys: { + name: { + type: String, + constant: true, + default: true, + options: [], + error: 'invalid field.', + }, + }, + } + ); + + Parse.Cloud.define('AFunc', request => { + // $ExpectType Params + request.params; + + // $ExpectType any + request.params.anything; + }); + + Parse.Cloud.define<() => void>('AFunc', request => { + // $ExpectType {} + request.params; + }); + + Parse.Cloud.define<(params: { something: string }) => number>('AFunc', request => { + // $ExpectType { something: string; } + request.params; + + // @ts-expect-error + request.params.somethingElse; + + return 123; + }); + + // @ts-expect-error + Parse.Cloud.define('AFunc'); + + // @ts-expect-error + Parse.Cloud.define<() => string>('AFunc', () => 123); + + // @ts-expect-error + Parse.Cloud.define<(params: string) => number>('AFunc', () => 123); + + Parse.Cloud.job('AJob', (request: Parse.Cloud.JobRequest) => { + request.message('Message to associate with this job run'); + }); + + Parse.Cloud.startJob('AJob', {}).then(v => v); + + Parse.Cloud.getJobStatus('AJob').then(v => v); + + Parse.Cloud.getJobsData().then(v => v); +} + +class PlaceObject extends Parse.Object {} + +function test_geo_points() { + let point = new Parse.GeoPoint(); + // @ts-expect-error + point = new Parse.GeoPoint('40.0'); + // @ts-expect-error + point = new Parse.GeoPoint(40.0); + // @ts-expect-error + point = new Parse.GeoPoint([40.0, -30.0, 20.0]); + point = new Parse.GeoPoint([40.0, -30.0]); + point = new Parse.GeoPoint(40.0, -30.0); + point = new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 }); + + const userObject = Parse.User.current>()!; + + // User's location + const userGeoPoint = userObject.get('location'); + + // Create a query for places + const query = new Parse.Query(Parse.User); + // Interested in locations near user. + query.near('location', userGeoPoint); + // Limit what could be a lot of points. + query.limit(10); + + const southwestOfSF = new Parse.GeoPoint(37.708813, -122.526398); + const northeastOfSF = new Parse.GeoPoint(37.822802, -122.373962); + + const query2 = new Parse.Query(PlaceObject); + query2.withinGeoBox('location', southwestOfSF, northeastOfSF); + + const query3 = new Parse.Query('PlaceObject').find().then((o: Parse.Object[]) => {}); +} + +function test_push() { + Parse.Push.send( + { + channels: ['Gia nts', 'Mets'], + data: { + alert: 'The Giants won against the Mets 2-3.', + }, + }, + { + success: () => { + // Push was successful + }, + error: (error: any) => { + // Handle error + }, + } + ); + + const query = new Parse.Query(Parse.Installation); + query.equalTo('injuryReports', true); + + Parse.Push.send( + { + where: query, // Set our Installation query + data: { + alert: 'Willie Hayes injured by own pop fly.', + }, + }, + { + success() { + // Push was successful + }, + error(error: any) { + // Handle error + }, + } + ); +} + +function test_batch_operations() { + const game1 = new Game(); + const game2 = new Game(); + const games = [game1, game2]; + + // Master key + Parse.Object.saveAll(games, { useMasterKey: true }); + Parse.Object.destroyAll(games, { useMasterKey: true }); + Parse.Object.fetchAll(games, { useMasterKey: true }); + Parse.Object.fetchAllIfNeeded(games, { useMasterKey: true }); + + // Session token + Parse.Object.saveAll(games, { sessionToken: '' }); + Parse.Object.destroyAll(games, { sessionToken: '' }); + Parse.Object.fetchAll(games, { sessionToken: '' }); + Parse.Object.fetchAllIfNeeded(games, { sessionToken: '' }); +} + +async function test_query_subscribe() { + // create new query from Game object type + const query = new Parse.Query(Game); + + // create subscription to Game object + // Without a token + // $ExpectType LiveQuerySubscription + let subscription = await query.subscribe(); + + // With a session token + // $ExpectType LiveQuerySubscription + subscription = await query.subscribe(new Parse.User().getSessionToken()); + + // listen for new Game objects created on Parse server + subscription.on('create', (game: any) => { + console.log(game); + }); + + // unsubscribe + subscription.unsubscribe(); +} + +function test_serverURL() { + Parse.serverURL = 'http://localhost:1337/parse'; +} +function test_polygon() { + const point = new Parse.GeoPoint(1, 2); + const polygon1 = new Parse.Polygon([ + [0, 0], + [1, 0], + [1, 1], + [0, 1], + ]); + const polygon2 = new Parse.Polygon([point, point, point]); + polygon1.equals(polygon2); + polygon1.containsPoint(point); + + const query = new Parse.Query('TestObject'); + query.polygonContains('key', point); + query.withinPolygon('key', [ + [0, 0], + [1, 0], + [1, 1], + [0, 1], + ]); +} + +async function test_local_datastore() { + Parse.enableLocalDatastore(); + const name = 'test_pin'; + const obj = new Parse.Object('TestObject'); + await obj.pin(); + await obj.unPin(); + await obj.isPinned(); + await obj.pinWithName(name); + await obj.unPinWithName(name); + await obj.fetchFromLocalDatastore(); + + await Parse.Object.pinAll([obj]); + await Parse.Object.unPinAll([obj]); + await Parse.Object.pinAllWithName(name, [obj]); + await Parse.Object.unPinAllWithName(name, [obj]); + await Parse.Object.unPinAllObjects(); + await Parse.Object.unPinAllObjectsWithName(name); + + const flag = Parse.isLocalDatastoreEnabled(); + const LDS = await Parse.dumpLocalDatastore(); + + const query = new Parse.Query('TestObject'); + query.fromPin(); + query.fromPinWithName(name); + query.fromLocalDatastore(); + + Parse.setLocalDatastoreController({}); +} + +async function test_from_network() { + const obj = new Parse.Object('TestObject'); + await obj.save(); + + const query = new Parse.Query('TestObject'); + query.fromNetwork(); +} + +async function test_cancel_query() { + const obj = new Parse.Object('TestObject'); + await obj.save(); + + const query = new Parse.Query('TestObject'); + query.fromNetwork().find(); + query.cancel(); +} + +type FieldType = + | string + | number + | boolean + | Date + | Parse.File + | Parse.GeoPoint + | any[] + | object + | Parse.Pointer + | Parse.Polygon + | Parse.Relation; +async function test_schema( + anyField: FieldType, + notString: Exclude, + notNumber: Exclude, + notboolean: Exclude, + notDate: Exclude, + notFile: Exclude, + notGeopoint: Exclude, + notArray: Exclude, + notObject: Exclude, + notPointer: Exclude, + notPolygon: Exclude +) { + // $ExpectType RestSchema[] + await Parse.Schema.all(); + + const schema = new Parse.Schema('TestSchema'); + + schema.addArray('arrayField'); + schema.addArray('arrayField', { defaultValue: [1, 2, 3, 4] }); + // @ts-expect-error + schema.addArray('arrayField', { defaultValue: notArray }); + + /** + * @todo Enable type check for default value + */ + schema.addField('defaultFieldString'); + schema.addField('defaultFieldString', 'String', { defaultValue: anyField }); + schema.addField('defaultFieldString', 'Number'); + schema.addField('defaultFieldString', 'Relation'); + // @ts-expect-error + schema.addField('defaultFieldString', 'String', 'Invalid Options'); + + schema.addString('field'); + schema.addString('field', { defaultValue: 'some string', required: true }); + // @ts-expect-error + schema.addString('field', { defaultValue: notString }); + + schema.addNumber('field'); + schema.addNumber('field', { defaultValue: 0, required: true }); + // @ts-expect-error + schema.addNumber('field', { defaultValue: notNumber }); + + schema.addBoolean('field'); + schema.addBoolean('field', { defaultValue: true, required: true }); + // @ts-expect-error + schema.addBoolean('field', { defaultValue: notboolean }); + + schema.addDate('field'); + schema.addDate('field', { defaultValue: new Date(), required: true }); + // @ts-expect-error + schema.addDate('field', { defaultValue: notDate }); + + schema.addFile('field'); + schema.addFile('field', { defaultValue: new Parse.File('myfile', []), required: true }); + // @ts-expect-error + schema.addFile('field', { defaultValue: notFile }); + + schema.addGeoPoint('field'); + schema.addGeoPoint('field', { defaultValue: new Parse.GeoPoint(), required: true }); + // @ts-expect-error + schema.addGeoPoint('field', { defaultValue: notGeopoint }); + + schema.addPolygon('field'); + schema.addPolygon('field', { defaultValue: new Parse.Polygon([]), required: true }); + // @ts-expect-error + schema.addPolygon('field', { defaultValue: notPolygon }); + + schema.addObject('field'); + schema.addObject('field', { defaultValue: {}, required: true }); + schema.addObject('field', { defaultValue: { abc: 'def' } }); + // @ts-expect-error + schema.addObject('field', { defaultValue: notObject }); + + schema.addPointer('field', 'SomeClass'); + // @ts-expect-error + schema.addPointer('field'); + /** + * @todo Infer defaultValue type from targetClass + */ + schema.addPointer('field', '_User', { + defaultValue: new Parse.User().toPointer(), + required: true, + }); + // @ts-expect-error + schema.addPointer('field', { defaultValue: notPointer }); + + schema.addRelation('field', 'SomeClass'); + // @ts-expect-error + schema.addRelation('field'); + // @ts-expect-error + schema.addRelation('field', 'SomeClass', 'anything'); + + schema.addIndex('testIndex', { stringField: 'text' }); + schema.addIndex('testIndex', { stringField: 1 }); + schema.addIndex('testIndex', { stringField: -1 }); + // @ts-expect-error + schema.addIndex('testIndex', { stringField: true }); + + schema.deleteField('defaultFieldString'); + schema.deleteIndex('testIndex'); + schema.delete().then(results => {}); + // $ExpectType RestSchema + await schema.get(); + schema.purge().then(results => {}); + schema.save().then(results => {}); + schema.update().then(results => {}); + + function testGenericType() { + interface iTestAttributes { + arrField: any[]; + boolField: boolean; + stringField: string; + numField: number; + dateField: Date; + fileField: Parse.File; + geoPointField: Parse.GeoPoint; + polygonField: Parse.Polygon; + objectField: object; + relationField: Parse.Relation; + pointerField: Parse.Pointer | Parse.Object; + } + class TestObject extends Parse.Object {} + + const schema = new Parse.Schema('TestObject'); + schema.addArray('arrField'); + schema.addBoolean('boolField'); + schema.addDate('dateField'); + schema.addFile('fileField'); + schema.addGeoPoint('geoPointField'); + schema.addNumber('numField'); + schema.addObject('objectField'); + schema.addPointer('pointerField', 'FooClass'); + schema.addPolygon('polygonField'); + schema.addRelation('relationField', 'FooClass'); + schema.addString('stringField'); + + // @ts-expect-error + schema.addArray('wrong'); + // @ts-expect-error + schema.addBoolean('wrong'); + // @ts-expect-error + schema.addDate('wrong'); + // @ts-expect-error + schema.addFile('wrong'); + // @ts-expect-error + schema.addGeoPoint('wrong'); + // @ts-expect-error + schema.addNumber('wrong'); + // @ts-expect-error + schema.addObject('wrong'); + // @ts-expect-error + schema.addPointer('wrong', 'FooClass'); + // @ts-expect-error + schema.addPolygon('wrong'); + // @ts-expect-error + schema.addRelation('wrong', 'FooClass'); + // @ts-expect-error + schema.addString('wrong'); + } +} + +function testObject() { + function testConstructor() { + // $ExpectType Object + new Parse.Object(); + + // $ExpectType Object + new Parse.Object('TestObject'); + + // $ExpectType Object<{ example: number; }> + new Parse.Object('TestObject', { example: 100 }); + + // $ExpectType Object<{ example: boolean; }> + new Parse.Object<{ example: boolean }>('TestObject', { example: true }); + + // $ExpectType Object<{ example: string; }> + new Parse.Object('TestObject', { example: 'hello' }, { ignoreValidation: true }); + + // @ts-expect-error + new Parse.Object<{ example: string }>('TestObject'); + + // @ts-expect-error + new Parse.Object<{ example: boolean }>('TestObject', { example: 'hello' }); + } + + function testStaticMethods() { + async function testSaveAll( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ example: string }> + ) { + // $ExpectType Object[] + await Parse.Object.saveAll([objUntyped]); + + // $ExpectType Object<{ example: string; }>[] + await Parse.Object.saveAll([objTyped]); + + // $ExpectType [Object, Object<{ example: string; }>] + await Parse.Object.saveAll<[typeof objUntyped, typeof objTyped]>([objUntyped, objTyped]); + + // @ts-expect-error + await Parse.Object.saveAll([123]); + } + } + + function testAttributes(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { + // $ExpectType any + objUntyped.attributes.whatever; + + // $ExpectType string + objTyped.attributes.example; + + // @ts-expect-error + objTyped.attributes.other; + } + + function testAdd( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.add('whatever', 'hello'); + + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.add('stringList', 'hello'); + + // @ts-expect-error + objTyped.add('stringList', 100); + + // @ts-expect-error + objTyped.add('thing', true); + + // @ts-expect-error + objTyped.add('whatever', 'hello'); + } + + function testAddAll( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.addAll('whatever', ['hello', 100]); + + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.addAll('stringList', ['hello']); + + // @ts-expect-error + objTyped.addAll('stringList', [100]); + + // @ts-expect-error + objTyped.addAll('thing', [true]); -// // @ts-expect-error -// objTyped.addAllUnique('stringList', [100]); + // @ts-expect-error + objTyped.addAll('whatever', ['hello']); + } -// // @ts-expect-error -// objTyped.addAllUnique('thing', [true]); + function testAddAllUnique( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.addAllUnique('whatever', ['hello', 100]); -// // @ts-expect-error -// objTyped.addAllUnique('whatever', ['hello']); -// } + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.addAllUnique('stringList', ['hello']); -// function testAddUnique(objUntyped: Parse.Object, objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>) { -// // $ExpectType false | Object -// objUntyped.addUnique('whatever', 'hello'); + // @ts-expect-error + objTyped.addAllUnique('stringList', [100]); -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.addUnique('stringList', 'hello'); + // @ts-expect-error + objTyped.addAllUnique('thing', [true]); -// // @ts-expect-error -// objTyped.addUnique('stringList', 100); + // @ts-expect-error + objTyped.addAllUnique('whatever', ['hello']); + } -// // @ts-expect-error -// objTyped.addUnique('thing', true); + function testAddUnique( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.addUnique('whatever', 'hello'); -// // @ts-expect-error -// objTyped.addUnique('whatever', 'hello'); -// } + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.addUnique('stringList', 'hello'); -// function testDirty(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType boolean -// objUntyped.dirty(); + // @ts-expect-error + objTyped.addUnique('stringList', 100); -// // $ExpectType boolean -// objUntyped.dirty('whatever'); + // @ts-expect-error + objTyped.addUnique('thing', true); -// // $ExpectType boolean -// objTyped.dirty(); + // @ts-expect-error + objTyped.addUnique('whatever', 'hello'); + } -// // $ExpectType boolean -// objTyped.dirty('example'); + function testDirty(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { + // $ExpectType boolean + objUntyped.dirty(); -// // @ts-expect-error -// objTyped.dirty('other'); -// } + // $ExpectType boolean + objUntyped.dirty('whatever'); -// function testEquals(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType boolean -// objUntyped.equals(objTyped); + // $ExpectType boolean + objTyped.dirty(); -// // $ExpectType boolean -// objTyped.equals(objUntyped); + // $ExpectType boolean + objTyped.dirty('example'); -// // @ts-expect-error -// objUntyped.equals('blah'); -// } + // @ts-expect-error + objTyped.dirty('other'); + } -// function testEscape(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType string -// objUntyped.escape('whatever'); + function testEquals(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { + // $ExpectType boolean + objUntyped.equals(objTyped); -// // $ExpectType string -// objTyped.escape('example'); + // $ExpectType boolean + objTyped.equals(objUntyped); -// // @ts-expect-error -// objTyped.escape('other'); -// } + // @ts-expect-error + objUntyped.equals('blah'); + } -// function testFetchWithInclude(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType Promise> -// objUntyped.fetchWithInclude('whatever'); + function testEscape(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { + // $ExpectType string + objUntyped.escape('whatever'); -// // $ExpectType Promise> -// objUntyped.fetchWithInclude(['whatever']); + // $ExpectType string + objTyped.escape('example'); -// // $ExpectType Promise> -// objUntyped.fetchWithInclude([['whatever']]); + // @ts-expect-error + objTyped.escape('other'); + } -// // @ts-expect-error -// objUntyped.fetchWithInclude([[['whatever']]]); + function testFetchWithInclude( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ example: string }> + ) { + // $ExpectType Promise> + objUntyped.fetchWithInclude('whatever'); -// // $ExpectType Promise> -// objTyped.fetchWithInclude('example'); + // $ExpectType Promise> + objUntyped.fetchWithInclude(['whatever']); -// // $ExpectType Promise> -// objTyped.fetchWithInclude(['example']); + // $ExpectType Promise> + objUntyped.fetchWithInclude([['whatever']]); -// // $ExpectType Promise> -// objTyped.fetchWithInclude([['example']]); + // @ts-expect-error + objUntyped.fetchWithInclude([[['whatever']]]); -// // @ts-expect-error -// objTyped.fetchWithInclude([[['example']]]); + // $ExpectType Promise> + objTyped.fetchWithInclude('example'); -// // $ExpectType Promise[]> -// Parse.Object.fetchAllIfNeededWithInclude([objTyped], 'example'); + // $ExpectType Promise> + objTyped.fetchWithInclude(['example']); -// // @ts-expect-error -// Parse.Object.fetchAllIfNeededWithInclude([objTyped], 'notAnAttribute'); + // $ExpectType Promise> + objTyped.fetchWithInclude([['example']]); -// // $ExpectType Promise[]> -// Parse.Object.fetchAllWithInclude([objTyped], 'example'); + // @ts-expect-error + objTyped.fetchWithInclude([[['example']]]); -// // @ts-expect-error -// Parse.Object.fetchAllWithInclude([objTyped], 'notAnAttribute'); -// } + // $ExpectType Promise[]> + Parse.Object.fetchAllIfNeededWithInclude([objTyped], 'example'); -// function testGet(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType any -// objUntyped.get('whatever'); + // @ts-expect-error + Parse.Object.fetchAllIfNeededWithInclude([objTyped], 'notAnAttribute'); -// // $ExpectType number -// objTyped.get('example'); + // $ExpectType Promise[]> + Parse.Object.fetchAllWithInclude([objTyped], 'example'); -// // @ts-expect-error -// objTyped.get('other'); -// } + // @ts-expect-error + Parse.Object.fetchAllWithInclude([objTyped], 'notAnAttribute'); + } -// function testHas(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType boolean -// objUntyped.has('whatever'); + function testGet(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType any + objUntyped.get('whatever'); -// // $ExpectType boolean -// objTyped.has('example'); + // $ExpectType number + objTyped.get('example'); -// // @ts-expect-error -// objTyped.has('other'); -// } + // @ts-expect-error + objTyped.get('other'); + } -// function testIncrement(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType false | Object -// objUntyped.increment('whatever'); + function testHas(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType boolean + objUntyped.has('whatever'); -// // $ExpectType false | Object -// objUntyped.increment('whatever', 10); + // $ExpectType boolean + objTyped.has('example'); -// // $ExpectType false | Object<{ example: number; }> -// objTyped.increment('example'); + // @ts-expect-error + objTyped.has('other'); + } -// // $ExpectType false | Object<{ example: number; }> -// objTyped.increment('example', 20); + function testIncrement(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType false | Object + objUntyped.increment('whatever'); -// // @ts-expect-error -// objTyped.increment('example', true); + // $ExpectType false | Object + objUntyped.increment('whatever', 10); -// // @ts-expect-error -// objTyped.increment('other'); -// } + // $ExpectType false | Object<{ example: number; }> + objTyped.increment('example'); -// function testDecrement(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType false | Object -// objUntyped.decrement('whatever'); + // $ExpectType false | Object<{ example: number; }> + objTyped.increment('example', 20); -// // $ExpectType false | Object -// objUntyped.decrement('whatever', 10); + // @ts-expect-error + objTyped.increment('example', true); -// // $ExpectType false | Object<{ example: number; }> -// objTyped.decrement('example'); + // @ts-expect-error + objTyped.increment('other'); + } -// // $ExpectType false | Object<{ example: number; }> -// objTyped.decrement('example', 20); + function testDecrement(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType false | Object + objUntyped.decrement('whatever'); -// // @ts-expect-error -// objTyped.decrement('example', true); + // $ExpectType false | Object + objUntyped.decrement('whatever', 10); -// // @ts-expect-error -// objTyped.decrement('other'); -// } + // $ExpectType false | Object<{ example: number; }> + objTyped.decrement('example'); -// function testNewInstance(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType Object -// objUntyped.newInstance(); + // $ExpectType false | Object<{ example: number; }> + objTyped.decrement('example', 20); -// // $ExpectType Object<{ example: number; }> -// objTyped.newInstance(); -// } + // @ts-expect-error + objTyped.decrement('example', true); -// function testOp(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { -// // $ExpectType any -// objUntyped.op('whatever'); + // @ts-expect-error + objTyped.decrement('other'); + } -// // $ExpectType any -// objTyped.op('example'); + function testNewInstance(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType Object + objUntyped.newInstance(); -// // @ts-expect-error -// objTyped.op('other'); -// } + // $ExpectType Object<{ example: number; }> + objTyped.newInstance(); + } -// function testRelation(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number; rel: Parse.Relation }>) { -// // $ExpectType Relation, Object> -// objUntyped.relation('whatever'); + function testOp(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: number }>) { + // $ExpectType any + objUntyped.op('whatever'); -// // $ExpectType Relation, Object>; }>, Object> -// objTyped.relation('rel'); + // $ExpectType any + objTyped.op('example'); -// // @ts-expect-error -// objTyped.relation('example'); + // @ts-expect-error + objTyped.op('other'); + } -// // @ts-expect-error -// objTyped.relation('other'); -// } + function testRelation( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ example: number; rel: Parse.Relation }> + ) { + // $ExpectType Relation, Object> + objUntyped.relation('whatever'); -// function testRemove(objUntyped: Parse.Object, objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>) { -// // $ExpectType false | Object -// objUntyped.remove('whatever', 'hello'); + // $ExpectType Relation, Object>; }>, Object> + objTyped.relation('rel'); -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.remove('stringList', 'hello'); + // @ts-expect-error + objTyped.relation('example'); -// // @ts-expect-error -// objTyped.remove('stringList', 100); + // @ts-expect-error + objTyped.relation('other'); + } -// // @ts-expect-error -// objTyped.remove('thing', true); + function testRemove( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.remove('whatever', 'hello'); -// // @ts-expect-error -// objTyped.remove('whatever', 'hello'); -// } + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.remove('stringList', 'hello'); -// function testRemoveAll(objUntyped: Parse.Object, objTyped: Parse.Object<{ stringList: string[]; thing: boolean }>) { -// // $ExpectType false | Object -// objUntyped.removeAll('whatever', ['hello', 100]); + // @ts-expect-error + objTyped.remove('stringList', 100); -// // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> -// objTyped.removeAll('stringList', ['hello']); + // @ts-expect-error + objTyped.remove('thing', true); -// // @ts-expect-error -// objTyped.removeAll('stringList', [100]); + // @ts-expect-error + objTyped.remove('whatever', 'hello'); + } -// // @ts-expect-error -// objTyped.removeAll('thing', [true]); + function testRemoveAll( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ stringList: string[]; thing: boolean }> + ) { + // $ExpectType false | Object + objUntyped.removeAll('whatever', ['hello', 100]); -// // @ts-expect-error -// objTyped.removeAll('whatever', ['hello']); -// } + // $ExpectType false | Object<{ stringList: string[]; thing: boolean; }> + objTyped.removeAll('stringList', ['hello']); -// function testRevert(objUntyped: Parse.Object, objTyped: Parse.Object<{ thingOne: number; thingTwo: boolean }>) { -// // $ExpectType void -// objUntyped.revert(); + // @ts-expect-error + objTyped.removeAll('stringList', [100]); -// // $ExpectType void -// objUntyped.revert('whatever', 'more whatever'); + // @ts-expect-error + objTyped.removeAll('thing', [true]); -// // $ExpectType void -// objTyped.revert(); + // @ts-expect-error + objTyped.removeAll('whatever', ['hello']); + } -// // $ExpectType void -// objTyped.revert('thingOne', 'thingTwo'); + function testRevert( + objUntyped: Parse.Object, + objTyped: Parse.Object<{ thingOne: number; thingTwo: boolean }> + ) { + // $ExpectType void + objUntyped.revert(); -// // @ts-expect-error -// objTyped.revert('other'); -// } -// interface ObjectAttributes { -// example: boolean; -// someString: string; -// } -// interface OptionalObjectAttributes { -// example?: boolean | undefined; -// another?: string | undefined; -// } + // $ExpectType void + objUntyped.revert('whatever', 'more whatever'); -// async function testSave( -// objUntyped: Parse.Object, -// objTyped: Parse.Object, -// objTypedOptional: Parse.Object, -// ) { -// // $ExpectType Object -// await objUntyped.save({ whatever: 100 }); + // $ExpectType void + objTyped.revert(); -// // $ExpectType Object -// await objUntyped.save('whatever', 100); + // $ExpectType void + objTyped.revert('thingOne', 'thingTwo'); -// // $ExpectType Object -// await objTyped.save({ example: true }); + // @ts-expect-error + objTyped.revert('other'); + } + interface ObjectAttributes { + example: boolean; + someString: string; + } + interface OptionalObjectAttributes { + example?: boolean | undefined; + another?: string | undefined; + } -// // $ExpectType Object -// await objTyped.save({ example: true, someString: 'hello' }); + async function testSave( + objUntyped: Parse.Object, + objTyped: Parse.Object, + objTypedOptional: Parse.Object + ) { + // $ExpectType Object + await objUntyped.save({ whatever: 100 }); -// // @ts-expect-error -// await objTyped.save({ example: 'hello', someString: true }); + // $ExpectType Object + await objUntyped.save('whatever', 100); -// // $ExpectType Object -// await objTyped.save('example', true); + // $ExpectType Object + await objTyped.save({ example: true }); -// // @ts-expect-error -// await objTyped.save({ example: 'hello' }); + // $ExpectType Object + await objTyped.save({ example: true, someString: 'hello' }); -// // @ts-expect-error -// await objTyped.save({ wrongProp: 5 }); + // @ts-expect-error + await objTyped.save({ example: 'hello', someString: true }); -// // @ts-expect-error -// await objTyped.save('example', 10); + // $ExpectType Object + await objTyped.save('example', true); -// // @ts-expect-error -// await objTyped.save('wrongProp', true); + // @ts-expect-error + await objTyped.save({ example: 'hello' }); -// // @ts-expect-error -// await objTyped.save({ example: undefined }); + // @ts-expect-error + await objTyped.save({ wrongProp: 5 }); -// // @ts-expect-error -// await objTyped.save('example', undefined); + // @ts-expect-error + await objTyped.save('example', 10); -// // $ExpectType Object -// await objTyped.save({}); + // @ts-expect-error + await objTyped.save('wrongProp', true); -// // $ExpectType Object -// await objTypedOptional.save({ example: undefined }); + // @ts-expect-error + await objTyped.save({ example: undefined }); -// // $ExpectType Object -// await objTypedOptional.save('example', undefined); - -// // $ExpectType Object -// await objTypedOptional.save({}); - -// // $ExpectType Object -// await objTypedOptional.saveEventually({}); - -// // $ExpectType Object -// await objTypedOptional.destroyEventually({}); -// } - -// function testSet( -// objUntyped: Parse.Object, -// objTyped: Parse.Object, -// objTypedOptional: Parse.Object, -// ) { -// // $ExpectType false | Object -// objUntyped.set('propA', 'some value'); - -// // $ExpectType false | Object -// objUntyped.set({ propA: undefined }); - -// // $ExpectType false | Object -// objTyped.set({ example: false }); - -// // $ExpectType false | Object -// objTyped.set({ example: true, someString: 'abc' }); - -// // @ts-expect-error -// objTyped.set({ example: 123, someString: 'abc' }); - -// // $ExpectType false | Object -// objTyped.set('example', true); - -// // @ts-expect-error -// objTyped.set({ example: 100 }); - -// // @ts-expect-error -// objTyped.set({ other: 'something' }); - -// // @ts-expect-error -// objTyped.set('example', 100); - -// // @ts-expect-error -// objTyped.set('other', 100); - -// // @ts-expect-error -// objTyped.set({ example: undefined }); - -// // $ExpectType false | Object -// objTyped.set({}); - -// // @ts-expect-error -// objTyped.set('example', undefined); - -// // $ExpectType false | Object -// objTypedOptional.set({ example: undefined }); - -// // $ExpectType false | Object -// objTypedOptional.set('example', undefined); - -// // $ExpectType false | Object -// objTypedOptional.set({}); -// } - -// interface AttributesAllTypes { -// someString: string; -// someNumber: number; -// someBoolean: boolean; -// someDate: Date; -// someJSONObject: AttributesAllTypes; -// someJSONArray: AttributesAllTypes[]; -// someRegExp: RegExp; -// someUndefined: undefined; -// someNull: null; -// someParseObjectUntyped: Parse.Object; -// someParseObjectTyped: Parse.Object; -// someParseACL: Parse.ACL; -// someParseGeoPoint: Parse.GeoPoint; -// someParsePolygon: Parse.Polygon; -// someParseRelation: Parse.Relation; -// someParseFile: Parse.File; -// } - -// function testToJSON(objUntyped: Parse.Object, objTyped: Parse.Object) { -// // $ExpectType ToJSON & JSONBaseAttributes -// const JSONUntyped = objUntyped.toJSON(); -// // $ExpectType string -// JSONUntyped.objectId; -// // $ExpectType string -// JSONUntyped.createdAt; -// // $ExpectType string -// JSONUntyped.updatedAt; -// // $ExpectType any -// JSONUntyped.anything; - -// // $ExpectType ToJSON & JSONBaseAttributes -// const JSONTyped = objTyped.toJSON(); -// // $ExpectType string -// JSONTyped.objectId; -// // $ExpectType string -// JSONTyped.createdAt; -// // $ExpectType string -// JSONTyped.updatedAt; -// // $ExpectType string -// JSONTyped.someString; -// // $ExpectType number -// JSONTyped.someNumber; -// // $ExpectType boolean -// JSONTyped.someBoolean; -// // $ExpectType { __type: "Date"; iso: string; } -// JSONTyped.someDate; -// // $ExpectType ToJSON -// JSONTyped.someJSONObject; -// // $ExpectType ToJSON[] -// JSONTyped.someJSONArray; -// // $ExpectType string -// JSONTyped.someRegExp; -// // $ExpectType undefined -// JSONTyped.someUndefined; -// // $ExpectType null -// JSONTyped.someNull; -// // $ExpectType Pointer | (ToJSON & JSONBaseAttributes) -// JSONTyped.someParseObjectUntyped; -// // $ExpectType Pointer | (ToJSON & JSONBaseAttributes) -// JSONTyped.someParseObjectTyped; -// // $ExpectType any -// JSONTyped.someParseACL; -// // $ExpectType any -// JSONTyped.someParseGeoPoint; -// // $ExpectType any -// JSONTyped.someParsePolygon; -// // $ExpectType any -// JSONTyped.someParseRelation; -// // $ExpectType { __type: string; name: string; url: string; } -// JSONTyped.someParseFile; -// } - -// function testUnset(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { -// // $ExpectType false | Object -// objUntyped.unset('whatever'); - -// // $ExpectType false | Object<{ example: string; }> -// objTyped.unset('example'); - -// // @ts-expect-error -// objTyped.unset('other'); -// } - -// function testValidate(obj: Parse.Object<{}>) { -// // Note: The attributes being validated don't necessarily have to match the current object's attributes - -// // $ExpectType false | Error -// obj.validate({ someAttrToValidate: 'hello' }); -// } - -// function testNullableArrays( -// objTyped: Parse.Object<{ stringList?: string[] | null }> -// ) { -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.add('stringList', 'foo'); - -// // @ts-expect-error -// objTyped.add('stringList', 4); - -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.addAll('stringList', ['foo']); - -// // @ts-expect-error -// objTyped.addAll('stringList', [4]); - -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.addAllUnique('stringList', ['foo', 'bar']); - -// // @ts-expect-error -// objTyped.addAllUnique('stringList', [4]); - -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.addUnique('stringList', 'foo'); - -// // @ts-expect-error -// objTyped.addUnique('stringList', 4); - -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.remove('stringList', 'bar'); - -// // @ts-expect-error -// objTyped.remove('stringList', 4); - -// // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> -// objTyped.removeAll('stringList', ['bar']); - -// // @ts-expect-error -// objTyped.removeAll('stringList', [4]); -// } -// } - -// function testInstallation() { -// function testConstructor() { -// // $ExpectType Installation -// new Parse.Installation(); - -// // $ExpectType Installation<{ example: number; }> -// new Parse.Installation({ example: 100 }); - -// // @ts-expect-error -// new Parse.Installation<{ example: number }>(); - -// // @ts-expect-error -// new Parse.Installation<{ example: number }>({ example: 'hello' }); -// } -// } - -// function testQuery() { -// function testConstructor() { -// // $ExpectType Query> -// new Parse.Query('TestObject'); - -// // $ExpectType Query> -// new Parse.Query(Parse.Role); - -// // $ExpectType Query> -// new Parse.Query(Parse.User); - -// // $ExpectType Query> -// new Parse.Query>('TestObject'); - -// // $ExpectType Query> -// new Parse.Query>(Parse.Role); - -// // $ExpectType Query> -// new Parse.Query>(Parse.User); -// } - -// async function testQueryMethodTypes() { -// class AnotherSubClass extends Parse.Object<{ x: any }> { -// constructor() { -// super('Another', { x: 'example' }); -// } -// } -// class MySubClass extends Parse.Object<{ -// attribute1: string; -// attribute2: number; -// attribute3: AnotherSubClass; -// attribute4: string[]; -// }> {} -// const query = new Parse.Query(MySubClass); - -// // $ExpectType Query -// query.addAscending(['attribute1', 'attribute2', 'updatedAt']); -// // @ts-expect-error -// query.addAscending(['attribute1', 'unexistenProp']); - -// // $ExpectType Query -// query.addDescending(['attribute1', 'attribute2', 'createdAt']); -// // @ts-expect-error -// query.addDescending(['attribute1', 'unexistenProp']); - -// // $ExpectType Query -// query.ascending(['attribute1', 'attribute2', 'objectId']); -// // @ts-expect-error -// query.ascending(['attribute1', 'nonexistentProp']); - -// // $ExpectType Query -// query.containedBy('attribute1', ['a', 'b', 'c']); -// // $ExpectType Query -// query.containedBy('attribute3', ['objectId1', 'objectId2', 'objectId3']); -// // @ts-expect-error -// query.containedBy('attribute2', ['a', 'b', 'c']); -// // @ts-expect-error -// query.containedBy('attribute1', [1, 2, 3]); -// // @ts-expect-error -// query.containedBy('nonexistentProp', ['a', 'b', 'c']); - -// // $ExpectType Query -// query.containedIn('attribute1', ['a', 'b', 'c']); -// // $ExpectType Query -// query.containedIn('attribute3', ['objectId1', 'objectId2', 'objectId3']); -// // @ts-expect-error -// query.containedIn('attribute2', ['a', 'b', 'c']); -// // @ts-expect-error -// query.containedIn('attribute1', [1, 2, 3]); -// // @ts-expect-error -// query.containedIn('nonexistentProp', ['a', 'b', 'c']); - -// // $ExpectType Query -// query.contains('attribute1', 'a substring'); -// // @ts-expect-error -// query.contains('nonexistentProp', 'a substring'); - -// // $ExpectType Query -// query.containsAll('attribute1', ['a', 'b', 'c']); -// // @ts-expect-error -// query.containsAll('nonexistentProp', ['a', 'b', 'c']); - -// // $ExpectType Query -// query.containsAllStartingWith('attribute1', ['a', 'b', 'c']); -// // @ts-expect-error -// query.containsAllStartingWith('nonexistentProp', ['a', 'b', 'c']); - -// // $ExpectType Query -// query.descending(['attribute1', 'attribute2', 'objectId']); -// // @ts-expect-error -// query.descending(['attribute1', 'nonexistentProp']); - -// // $ExpectType Query -// query.doesNotExist('attribute1'); -// // @ts-expect-error -// query.doesNotExist('nonexistentProp'); - -// // $ExpectType Query -// query.doesNotMatchKeyInQuery('attribute1', 'x', new Parse.Query(AnotherSubClass)); -// // @ts-expect-error -// query.doesNotMatchKeyInQuery('unexistenProp', 'x', new Parse.Query(AnotherSubClass)); -// // @ts-expect-error -// query.doesNotMatchKeyInQuery('attribute1', 'unknownKey', new Parse.Query(AnotherSubClass)); -// // $ExpectType Query -// query.doesNotMatchKeyInQuery('objectId', 'x', new Parse.Query(AnotherSubClass)); -// // $ExpectType Query -// query.doesNotMatchKeyInQuery('updatedAt', 'x', new Parse.Query(AnotherSubClass)); - -// // $ExpectType Query -// query.doesNotMatchQuery('attribute1', new Parse.Query('Example')); -// // @ts-expect-error -// query.doesNotMatchQuery('nonexistentProp', new Parse.Query('Example')); - -// // $ExpectType Query -// query.endsWith('attribute1', 'asuffixstring'); -// // @ts-expect-error -// query.endsWith('nonexistentProp', 'asuffixstring'); - -// // $ExpectType Query -// query.equalTo('attribute2', 0); -// // $ExpectType Query -// query.equalTo('attribute3', new AnotherSubClass()); -// // $ExpectType Query -// query.equalTo('attribute3', new AnotherSubClass().toPointer()); -// // @ts-expect-error -// query.equalTo('attribute1', new AnotherSubClass().toPointer()); -// // @ts-expect-error -// query.equalTo('attribute2', 'a string value'); -// // @ts-expect-error -// query.equalTo('nonexistentProp', 'any value'); - -// // $ExpectType Query -// query.equalTo('attribute4', 'a_string_value'); // Can query contents of array -// // Can query array itself if equal too (mongodb $eq matches the array exactly or the contains an element that matches the array exactly) -// // $ExpectType Query -// query.equalTo('attribute4', ['a_string_value']); - -// // $ExpectType Query -// query.notEqualTo('attribute4', 'a_string_value'); -// // $ExpectType Query -// query.notEqualTo('attribute4', ['a_string_value']); - -// // @ts-expect-error -// query.equalTo('attribute4', 5); -// // @ts-expect-error -// query.notEqualTo('attribute4', 5); -// // @ts-expect-error -// query.equalTo('attribute4', [5]); -// // @ts-expect-error -// query.notEqualTo('attribute4', [5]); - -// // $ExpectType Query -// query.exists('attribute1'); -// // @ts-expect-error -// query.exists('nonexistentProp'); - -// // $ExpectType Query -// query.fullText('attribute1', 'full text'); -// // @ts-expect-error -// query.fullText('nonexistentProp', 'full text'); - -// // $ExpectType Query -// query.greaterThan('attribute2', 1000); -// // @ts-expect-error -// query.greaterThan('attribute2', '1000'); -// // @ts-expect-error -// query.greaterThan('nonexistentProp', 1000); - -// // $ExpectType Query -// query.greaterThanOrEqualTo('attribute2', 1000); -// // @ts-expect-error -// query.greaterThanOrEqualTo('attribute2', '1000'); -// // @ts-expect-error -// query.greaterThanOrEqualTo('nonexistentProp', 1000); - -// // $ExpectType Query -// query.include(['attribute1', 'attribute2']); -// // $ExpectType Query -// query.include('attribute3.someProp'); -// // @ts-expect-error -// query.include(['attribute1', 'nonexistentProp']); - -// // $ExpectType Query -// query.lessThan('attribute2', 1000); -// // @ts-expect-error -// query.lessThan('attribute2', '1000'); -// // @ts-expect-error -// query.lessThan('nonexistentProp', 1000); - -// // $ExpectType Query -// query.lessThanOrEqualTo('attribute2', 1000); -// // @ts-expect-error -// query.lessThanOrEqualTo('attribute2', '1000'); -// // @ts-expect-error -// query.lessThanOrEqualTo('nonexistentProp', 1000); - -// // $ExpectType Query -// query.matches('attribute1', /a regex/); -// // @ts-expect-error -// query.matches('nonexistentProp', /a regex/); - -// // $ExpectType Query -// query.matchesKeyInQuery('attribute1', 'x', new Parse.Query(AnotherSubClass)); -// // @ts-expect-error -// query.matchesKeyInQuery('nonexistentProp', 'x', new Parse.Query(AnotherSubClass)); -// // @ts-expect-error -// query.matchesKeyInQuery('attribute1', 'unknownKey', new Parse.Query(AnotherSubClass)); - -// // $ExpectType Query -// query.matchesQuery('attribute1', new Parse.Query('Example')); -// // @ts-expect-error -// query.matchesQuery('nonexistentProp', new Parse.Query('Example')); - -// // $ExpectType Query -// query.near('attribute1', new Parse.GeoPoint()); -// // @ts-expect-error -// query.near('nonexistentProp', new Parse.GeoPoint()); - -// // $ExpectType Query -// query.notContainedIn('attribute2', [1, 2, 3]); -// // @ts-expect-error -// query.notContainedIn('attribute2', ['1', '2', '3']); -// // @ts-expect-error -// query.notContainedIn('nonexistentProp', [1, 2, 3]); - -// // $ExpectType Query -// query.notEqualTo('attribute1', '1'); -// // @ts-expect-error -// query.notEqualTo('attribute1', 1); -// // @ts-expect-error -// query.notEqualTo('nonexistentProp', 1); - -// // $ExpectType Query -// query.polygonContains('attribute1', new Parse.GeoPoint()); -// // @ts-expect-error -// query.polygonContains('nonexistentProp', new Parse.GeoPoint()); - -// // $ExpectType Query -// query.select('attribute1', 'attribute2'); -// // @ts-expect-error -// query.select('attribute1', 'nonexistentProp'); - -// // $ExpectType Query -// query.startsWith('attribute1', 'prefix string'); -// // @ts-expect-error -// query.startsWith('nonexistentProp', 'prefix string'); - -// // $ExpectType Query -// query.withCount(true); - -// // $ExpectType Query -// query.withinGeoBox('attribute1', new Parse.GeoPoint(), new Parse.GeoPoint()); -// // @ts-expect-error -// query.withinGeoBox('nonexistentProp', new Parse.GeoPoint(), new Parse.GeoPoint()); - -// // $ExpectType Query -// query.withinKilometers('attribute1', new Parse.GeoPoint(), 100); -// // @ts-expect-error -// query.withinKilometers('nonexistentProp', new Parse.GeoPoint(), 100); - -// // $ExpectType Query -// query.withinMiles('attribute1', new Parse.GeoPoint(), 100); -// // @ts-expect-error -// query.withinMiles('nonexistentProp', new Parse.GeoPoint(), 100); - -// // $ExpectType Query -// query.withinPolygon('attribute1', [ -// [12.3, 45.6], -// [-78.9, 10.1], -// ]); -// // @ts-expect-error -// query.withinPolygon('nonexistentProp', [ -// [12.3, 45.6], -// [-78.9, 10.1], -// ]); - -// // $ExpectType Query -// query.withinRadians('attribute1', new Parse.GeoPoint(), 100); -// // @ts-expect-error -// query.withinRadians('nonexistentProp', new Parse.GeoPoint(), 100); -// } - -// async function testQueryMethods( -// queryUntyped: Parse.Query, -// queryTyped: Parse.Query>, -// ) { -// // $ExpectType Object -// await queryUntyped.get('objectId'); - -// // $ExpectType Object[] -// await queryUntyped.find(); - -// // $ExpectType string[] -// await queryTyped.distinct('example'); - -// // $ExpectType Object | undefined -// await queryUntyped.first(); - -// // $ExpectType Object<{ example: string; }> -// await queryTyped.get('objectId'); - -// // $ExpectType Object<{ example: string; }>[] -// await queryTyped.find(); - -// // $ExpectType Object<{ example: string; }> | undefined -// await queryTyped.first(); -// } -// } - -// function testRole() { -// function testConstructor(acl: Parse.ACL) { -// // $ExpectType Role> -// new Parse.Role<{ example: string }>('TestRole', acl); -// } - -// function testAttributes(roleUntyped: Parse.Role, roleTyped: Parse.Role<{ example: number }>) { -// // $ExpectType Attributes -// roleUntyped.attributes; - -// // $ExpectType { example: number; } -// roleTyped.attributes; -// } -// } - -// $ExpectType ParseSession + // @ts-expect-error + await objTyped.save('example', undefined); + + // $ExpectType Object + await objTyped.save({}); + + // $ExpectType Object + await objTypedOptional.save({ example: undefined }); + + // $ExpectType Object + await objTypedOptional.save('example', undefined); + + // $ExpectType Object + await objTypedOptional.save({}); + + // $ExpectType Object + await objTypedOptional.saveEventually({}); + + // $ExpectType Object + await objTypedOptional.destroyEventually({}); + } + + function testSet( + objUntyped: Parse.Object, + objTyped: Parse.Object, + objTypedOptional: Parse.Object + ) { + // $ExpectType false | Object + objUntyped.set('propA', 'some value'); + + // $ExpectType false | Object + objUntyped.set({ propA: undefined }); + + // $ExpectType false | Object + objTyped.set({ example: false }); + + // $ExpectType false | Object + objTyped.set({ example: true, someString: 'abc' }); + + // @ts-expect-error + objTyped.set({ example: 123, someString: 'abc' }); + + // $ExpectType false | Object + objTyped.set('example', true); + + // @ts-expect-error + objTyped.set({ example: 100 }); + + // @ts-expect-error + objTyped.set({ other: 'something' }); + + // @ts-expect-error + objTyped.set('example', 100); + + // @ts-expect-error + objTyped.set('other', 100); + + // @ts-expect-error + objTyped.set({ example: undefined }); + + // $ExpectType false | Object + objTyped.set({}); + + // @ts-expect-error + objTyped.set('example', undefined); + + // $ExpectType false | Object + objTypedOptional.set({ example: undefined }); + + // $ExpectType false | Object + objTypedOptional.set('example', undefined); + + // $ExpectType false | Object + objTypedOptional.set({}); + } + + interface AttributesAllTypes { + someString: string; + someNumber: number; + someBoolean: boolean; + someDate: Date; + someJSONObject: AttributesAllTypes; + someJSONArray: AttributesAllTypes[]; + someRegExp: RegExp; + someUndefined: undefined; + someNull: null; + someParseObjectUntyped: Parse.Object; + someParseObjectTyped: Parse.Object; + someParseACL: Parse.ACL; + someParseGeoPoint: Parse.GeoPoint; + someParsePolygon: Parse.Polygon; + someParseRelation: Parse.Relation; + someParseFile: Parse.File; + } + + function testToJSON(objUntyped: Parse.Object, objTyped: Parse.Object) { + // $ExpectType ToJSON & JSONBaseAttributes + const JSONUntyped = objUntyped.toJSON(); + // $ExpectType string + JSONUntyped.objectId; + // $ExpectType string + JSONUntyped.createdAt; + // $ExpectType string + JSONUntyped.updatedAt; + // $ExpectType any + JSONUntyped.anything; + + // $ExpectType ToJSON & JSONBaseAttributes + const JSONTyped = objTyped.toJSON(); + // $ExpectType string + JSONTyped.objectId; + // $ExpectType string + JSONTyped.createdAt; + // $ExpectType string + JSONTyped.updatedAt; + // $ExpectType string + JSONTyped.someString; + // $ExpectType number + JSONTyped.someNumber; + // $ExpectType boolean + JSONTyped.someBoolean; + // $ExpectType { __type: "Date"; iso: string; } + JSONTyped.someDate; + // $ExpectType ToJSON + JSONTyped.someJSONObject; + // $ExpectType ToJSON[] + JSONTyped.someJSONArray; + // $ExpectType string + JSONTyped.someRegExp; + // $ExpectType undefined + JSONTyped.someUndefined; + // $ExpectType null + JSONTyped.someNull; + // $ExpectType Pointer | (ToJSON & JSONBaseAttributes) + JSONTyped.someParseObjectUntyped; + // $ExpectType Pointer | (ToJSON & JSONBaseAttributes) + JSONTyped.someParseObjectTyped; + // $ExpectType any + JSONTyped.someParseACL; + // $ExpectType any + JSONTyped.someParseGeoPoint; + // $ExpectType any + JSONTyped.someParsePolygon; + // $ExpectType any + JSONTyped.someParseRelation; + // $ExpectType { __type: string; name: string; url: string; } + JSONTyped.someParseFile; + } + + function testUnset(objUntyped: Parse.Object, objTyped: Parse.Object<{ example: string }>) { + // $ExpectType false | Object + objUntyped.unset('whatever'); + + // $ExpectType false | Object<{ example: string; }> + objTyped.unset('example'); + + // @ts-expect-error + objTyped.unset('other'); + } + + function testValidate(obj: Parse.Object<{}>) { + // Note: The attributes being validated don't necessarily have to match the current object's attributes + + // $ExpectType false | Error + obj.validate({ someAttrToValidate: 'hello' }); + } + + function testNullableArrays(objTyped: Parse.Object<{ stringList?: string[] | null }>) { + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.add('stringList', 'foo'); + + // @ts-expect-error + objTyped.add('stringList', 4); + + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.addAll('stringList', ['foo']); + + // @ts-expect-error + objTyped.addAll('stringList', [4]); + + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.addAllUnique('stringList', ['foo', 'bar']); + + // @ts-expect-error + objTyped.addAllUnique('stringList', [4]); + + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.addUnique('stringList', 'foo'); + + // @ts-expect-error + objTyped.addUnique('stringList', 4); + + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.remove('stringList', 'bar'); + + // @ts-expect-error + objTyped.remove('stringList', 4); + + // $ExpectType false | Object<{ stringList?: string[] | null | undefined; }> + objTyped.removeAll('stringList', ['bar']); + + // @ts-expect-error + objTyped.removeAll('stringList', [4]); + } +} + +function testInstallation() { + function testConstructor() { + // $ExpectType Installation + new Parse.Installation(); + + // $ExpectType Installation<{ example: number; }> + new Parse.Installation({ example: 100 }); + + // @ts-expect-error + new Parse.Installation<{ example: number }>(); + + // @ts-expect-error + new Parse.Installation<{ example: number }>({ example: 'hello' }); + } +} + +function testQuery() { + function testConstructor() { + // $ExpectType Query> + new Parse.Query('TestObject'); + + // $ExpectType Query> + new Parse.Query(Parse.Role); + + // $ExpectType Query> + new Parse.Query(Parse.User); + + // $ExpectType Query> + new Parse.Query>('TestObject'); + + // $ExpectType Query> + new Parse.Query>(Parse.Role); + + // $ExpectType Query> + new Parse.Query>(Parse.User); + } + + async function testQueryMethodTypes() { + class AnotherSubClass extends Parse.Object<{ x: any }> { + constructor() { + super('Another', { x: 'example' }); + } + } + class MySubClass extends Parse.Object<{ + attribute1: string; + attribute2: number; + attribute3: AnotherSubClass; + attribute4: string[]; + }> {} + const query = new Parse.Query(MySubClass); + + // $ExpectType Query + query.addAscending(['attribute1', 'attribute2', 'updatedAt']); + // @ts-expect-error + query.addAscending(['attribute1', 'unexistenProp']); + + // $ExpectType Query + query.addDescending(['attribute1', 'attribute2', 'createdAt']); + // @ts-expect-error + query.addDescending(['attribute1', 'unexistenProp']); + + // $ExpectType Query + query.ascending(['attribute1', 'attribute2', 'objectId']); + // @ts-expect-error + query.ascending(['attribute1', 'nonexistentProp']); + + // $ExpectType Query + query.containedBy('attribute1', ['a', 'b', 'c']); + // $ExpectType Query + query.containedBy('attribute3', ['objectId1', 'objectId2', 'objectId3']); + // @ts-expect-error + query.containedBy('attribute2', ['a', 'b', 'c']); + // @ts-expect-error + query.containedBy('attribute1', [1, 2, 3]); + // @ts-expect-error + query.containedBy('nonexistentProp', ['a', 'b', 'c']); + + // $ExpectType Query + query.containedIn('attribute1', ['a', 'b', 'c']); + // $ExpectType Query + query.containedIn('attribute3', ['objectId1', 'objectId2', 'objectId3']); + // @ts-expect-error + query.containedIn('attribute2', ['a', 'b', 'c']); + // @ts-expect-error + query.containedIn('attribute1', [1, 2, 3]); + // @ts-expect-error + query.containedIn('nonexistentProp', ['a', 'b', 'c']); + + // $ExpectType Query + query.contains('attribute1', 'a substring'); + // @ts-expect-error + query.contains('nonexistentProp', 'a substring'); + + // $ExpectType Query + query.containsAll('attribute1', ['a', 'b', 'c']); + // @ts-expect-error + query.containsAll('nonexistentProp', ['a', 'b', 'c']); + + // $ExpectType Query + query.containsAllStartingWith('attribute1', ['a', 'b', 'c']); + // @ts-expect-error + query.containsAllStartingWith('nonexistentProp', ['a', 'b', 'c']); + + // $ExpectType Query + query.descending(['attribute1', 'attribute2', 'objectId']); + // @ts-expect-error + query.descending(['attribute1', 'nonexistentProp']); + + // $ExpectType Query + query.doesNotExist('attribute1'); + // @ts-expect-error + query.doesNotExist('nonexistentProp'); + + // $ExpectType Query + query.doesNotMatchKeyInQuery('attribute1', 'x', new Parse.Query(AnotherSubClass)); + // @ts-expect-error + query.doesNotMatchKeyInQuery('unexistenProp', 'x', new Parse.Query(AnotherSubClass)); + // @ts-expect-error + query.doesNotMatchKeyInQuery('attribute1', 'unknownKey', new Parse.Query(AnotherSubClass)); + // $ExpectType Query + query.doesNotMatchKeyInQuery('objectId', 'x', new Parse.Query(AnotherSubClass)); + // $ExpectType Query + query.doesNotMatchKeyInQuery('updatedAt', 'x', new Parse.Query(AnotherSubClass)); + + // $ExpectType Query + query.doesNotMatchQuery('attribute1', new Parse.Query('Example')); + // @ts-expect-error + query.doesNotMatchQuery('nonexistentProp', new Parse.Query('Example')); + + // $ExpectType Query + query.endsWith('attribute1', 'asuffixstring'); + // @ts-expect-error + query.endsWith('nonexistentProp', 'asuffixstring'); + + // $ExpectType Query + query.equalTo('attribute2', 0); + // $ExpectType Query + query.equalTo('attribute3', new AnotherSubClass()); + // $ExpectType Query + query.equalTo('attribute3', new AnotherSubClass().toPointer()); + // @ts-expect-error + query.equalTo('attribute1', new AnotherSubClass().toPointer()); + // @ts-expect-error + query.equalTo('attribute2', 'a string value'); + // @ts-expect-error + query.equalTo('nonexistentProp', 'any value'); + + // $ExpectType Query + query.equalTo('attribute4', 'a_string_value'); // Can query contents of array + // Can query array itself if equal too (mongodb $eq matches the array exactly or the contains an element that matches the array exactly) + // $ExpectType Query + query.equalTo('attribute4', ['a_string_value']); + + // $ExpectType Query + query.notEqualTo('attribute4', 'a_string_value'); + // $ExpectType Query + query.notEqualTo('attribute4', ['a_string_value']); + + // @ts-expect-error + query.equalTo('attribute4', 5); + // @ts-expect-error + query.notEqualTo('attribute4', 5); + // @ts-expect-error + query.equalTo('attribute4', [5]); + // @ts-expect-error + query.notEqualTo('attribute4', [5]); + + // $ExpectType Query + query.exists('attribute1'); + // @ts-expect-error + query.exists('nonexistentProp'); + + // $ExpectType Query + query.fullText('attribute1', 'full text'); + // @ts-expect-error + query.fullText('nonexistentProp', 'full text'); + + // $ExpectType Query + query.greaterThan('attribute2', 1000); + // @ts-expect-error + query.greaterThan('attribute2', '1000'); + // @ts-expect-error + query.greaterThan('nonexistentProp', 1000); + + // $ExpectType Query + query.greaterThanOrEqualTo('attribute2', 1000); + // @ts-expect-error + query.greaterThanOrEqualTo('attribute2', '1000'); + // @ts-expect-error + query.greaterThanOrEqualTo('nonexistentProp', 1000); + + // $ExpectType Query + query.include(['attribute1', 'attribute2']); + // $ExpectType Query + query.include('attribute3.someProp'); + // @ts-expect-error + query.include(['attribute1', 'nonexistentProp']); + + // $ExpectType Query + query.lessThan('attribute2', 1000); + // @ts-expect-error + query.lessThan('attribute2', '1000'); + // @ts-expect-error + query.lessThan('nonexistentProp', 1000); + + // $ExpectType Query + query.lessThanOrEqualTo('attribute2', 1000); + // @ts-expect-error + query.lessThanOrEqualTo('attribute2', '1000'); + // @ts-expect-error + query.lessThanOrEqualTo('nonexistentProp', 1000); + + // $ExpectType Query + query.matches('attribute1', /a regex/); + // @ts-expect-error + query.matches('nonexistentProp', /a regex/); + + // $ExpectType Query + query.matchesKeyInQuery('attribute1', 'x', new Parse.Query(AnotherSubClass)); + // @ts-expect-error + query.matchesKeyInQuery('nonexistentProp', 'x', new Parse.Query(AnotherSubClass)); + // @ts-expect-error + query.matchesKeyInQuery('attribute1', 'unknownKey', new Parse.Query(AnotherSubClass)); + + // $ExpectType Query + query.matchesQuery('attribute1', new Parse.Query('Example')); + // @ts-expect-error + query.matchesQuery('nonexistentProp', new Parse.Query('Example')); + + // $ExpectType Query + query.near('attribute1', new Parse.GeoPoint()); + // @ts-expect-error + query.near('nonexistentProp', new Parse.GeoPoint()); + + // $ExpectType Query + query.notContainedIn('attribute2', [1, 2, 3]); + // @ts-expect-error + query.notContainedIn('attribute2', ['1', '2', '3']); + // @ts-expect-error + query.notContainedIn('nonexistentProp', [1, 2, 3]); + + // $ExpectType Query + query.notEqualTo('attribute1', '1'); + // @ts-expect-error + query.notEqualTo('attribute1', 1); + // @ts-expect-error + query.notEqualTo('nonexistentProp', 1); + + // $ExpectType Query + query.polygonContains('attribute1', new Parse.GeoPoint()); + // @ts-expect-error + query.polygonContains('nonexistentProp', new Parse.GeoPoint()); + + // $ExpectType Query + query.select('attribute1', 'attribute2'); + // @ts-expect-error + query.select('attribute1', 'nonexistentProp'); + + // $ExpectType Query + query.startsWith('attribute1', 'prefix string'); + // @ts-expect-error + query.startsWith('nonexistentProp', 'prefix string'); + + // $ExpectType Query + query.withCount(true); + + // $ExpectType Query + query.withinGeoBox('attribute1', new Parse.GeoPoint(), new Parse.GeoPoint()); + // @ts-expect-error + query.withinGeoBox('nonexistentProp', new Parse.GeoPoint(), new Parse.GeoPoint()); + + // $ExpectType Query + query.withinKilometers('attribute1', new Parse.GeoPoint(), 100); + // @ts-expect-error + query.withinKilometers('nonexistentProp', new Parse.GeoPoint(), 100); + + // $ExpectType Query + query.withinMiles('attribute1', new Parse.GeoPoint(), 100); + // @ts-expect-error + query.withinMiles('nonexistentProp', new Parse.GeoPoint(), 100); + + // $ExpectType Query + query.withinPolygon('attribute1', [ + [12.3, 45.6], + [-78.9, 10.1], + ]); + // @ts-expect-error + query.withinPolygon('nonexistentProp', [ + [12.3, 45.6], + [-78.9, 10.1], + ]); + + // $ExpectType Query + query.withinRadians('attribute1', new Parse.GeoPoint(), 100); + // @ts-expect-error + query.withinRadians('nonexistentProp', new Parse.GeoPoint(), 100); + } + + async function testQueryMethods( + queryUntyped: Parse.Query, + queryTyped: Parse.Query> + ) { + // $ExpectType Object + await queryUntyped.get('objectId'); + + // $ExpectType Object[] + await queryUntyped.find(); + + // $ExpectType string[] + await queryTyped.distinct('example'); + + // $ExpectType Object | undefined + await queryUntyped.first(); + + // $ExpectType Object<{ example: string; }> + await queryTyped.get('objectId'); + + // $ExpectType Object<{ example: string; }>[] + await queryTyped.find(); + + // $ExpectType Object<{ example: string; }> | undefined + await queryTyped.first(); + } +} + +function testRole() { + function testConstructor(acl: Parse.ACL) { + // $ExpectType Role> + new Parse.Role<{ example: string }>('TestRole', acl); + } + + function testAttributes(roleUntyped: Parse.Role, roleTyped: Parse.Role<{ example: number }>) { + // $ExpectType Attributes + roleUntyped.attributes; + + // $ExpectType { example: number; } + roleTyped.attributes; + } +} + +// $ExpectType Session new Parse.Session(); -// $ExpectType ParseSession +// $ExpectType Session<{ example: number; }> new Parse.Session({ example: 100 }); // @ts-expect-error: invalid type @@ -2065,102 +2096,99 @@ new Parse.Session<{ example: number }>(); // @ts-expect-error: invalid type new Parse.Session<{ example: number }>({ example: 'hello' }); -// function testUser() { -// function testConstructor() { -// // $ExpectType User -// new Parse.User(); - -// // $ExpectType User<{ example: number; }> -// new Parse.User({ example: 100 }); - -// // @ts-expect-error -// new Parse.User<{ example: number }>(); - -// // @ts-expect-error -// new Parse.User<{ example: number }>({ example: 'hello' }); -// } -// async function testAuthenticationProvider() { -// const authProvider: Parse.AuthProvider = { -// authenticate: () => {}, -// getAuthType: () => 'customAuthorizationProvider', -// restoreAuthentication: () => false, -// deauthenticate: () => {}, -// }; -// const authData: Parse.AuthData = { -// id: 'some-user-authentication-id', -// access_token: 'some-access-token', -// expiration_date: new Date().toISOString(), -// }; -// Parse.User._registerAuthenticationProvider(authProvider); - -// const user = await Parse.User.logInWith( -// authProvider, -// { authData }, -// { sessionToken: 'some-session-token', useMasterKey: true }, -// ); -// const isLinked = user._isLinked(authProvider); -// const unlinkedUser = await user._unlinkFrom(authProvider); -// const linkedUser = await user.linkWith(authProvider, { authData }); -// } -// } - -// function testEncryptingUser() { -// function testSecretKey() { -// Parse.secret = 'secret!'; -// } - -// function testEnableEncryptedUserKey() { -// Parse.encryptedUser = true; -// } - -// function testEnablingEncryptedUser() { -// Parse.enableEncryptedUser(); -// } - -// function testIsEncryptedUserEnabled() { -// Parse.isEncryptedUserEnabled(); -// } -// } - -// function testEventuallyQueue() { -// function test() { -// const obj = new Parse.Object('TestObject'); -// // $ExpectType Promise -// Parse.EventuallyQueue.clear(); -// // $ExpectType Promise -// Parse.EventuallyQueue.getQueue(); -// // $ExpectType boolean -// Parse.EventuallyQueue.isPolling(); -// // $ExpectType Promise -// Parse.EventuallyQueue.save(obj); -// // $ExpectType Promise -// Parse.EventuallyQueue.save(obj, {}); -// // $ExpectType Promise -// Parse.EventuallyQueue.destroy(obj); -// // $ExpectType Promise -// Parse.EventuallyQueue.destroy(obj, {}); -// // $ExpectType Promise -// Parse.EventuallyQueue.length(); -// // $ExpectType Promise -// Parse.EventuallyQueue.sendQueue(); -// // $ExpectType void -// Parse.EventuallyQueue.stopPoll(); -// // $ExpectType void -// Parse.EventuallyQueue.poll(); -// // $ExpectType void -// Parse.EventuallyQueue.poll(300); -// // @ts-expect-error -// Parse.EventuallyQueue.poll('300'); -// } -// } - -// function LiveQueryEvents() { -// function testLiveQueryEvents() { -// Parse.LiveQuery.on('open', () => { -// }); -// Parse.LiveQuery.on('close', () => { -// }); -// Parse.LiveQuery.on('error', (error: any) => { -// }); -// } -// } +function testUser() { + function testConstructor() { + // $ExpectType User + new Parse.User(); + + // $ExpectType User<{ example: number; }> + new Parse.User({ example: 100 }); + + // @ts-expect-error + new Parse.User<{ example: number }>(); + + // @ts-expect-error + new Parse.User<{ example: number }>({ example: 'hello' }); + } + async function testAuthenticationProvider() { + const authProvider: Parse.AuthProvider = { + authenticate: () => {}, + getAuthType: () => 'customAuthorizationProvider', + restoreAuthentication: () => false, + deauthenticate: () => {}, + }; + const authData: Parse.AuthData = { + id: 'some-user-authentication-id', + access_token: 'some-access-token', + expiration_date: new Date().toISOString(), + }; + Parse.User._registerAuthenticationProvider(authProvider); + + const user = await Parse.User.logInWith( + authProvider, + { authData }, + { sessionToken: 'some-session-token', useMasterKey: true } + ); + const isLinked = user._isLinked(authProvider); + const unlinkedUser = await user._unlinkFrom(authProvider); + const linkedUser = await user.linkWith(authProvider, { authData }); + } +} + +function testEncryptingUser() { + function testSecretKey() { + Parse.secret = 'secret!'; + } + + function testEnableEncryptedUserKey() { + Parse.encryptedUser = true; + } + + function testEnablingEncryptedUser() { + Parse.enableEncryptedUser(); + } + + function testIsEncryptedUserEnabled() { + Parse.isEncryptedUserEnabled(); + } +} + +function testEventuallyQueue() { + function test() { + const obj = new Parse.Object('TestObject'); + // $ExpectType Promise + Parse.EventuallyQueue.clear(); + // $ExpectType Promise + Parse.EventuallyQueue.getQueue(); + // $ExpectType boolean + Parse.EventuallyQueue.isPolling(); + // $ExpectType Promise + Parse.EventuallyQueue.save(obj); + // $ExpectType Promise + Parse.EventuallyQueue.save(obj, {}); + // $ExpectType Promise + Parse.EventuallyQueue.destroy(obj); + // $ExpectType Promise + Parse.EventuallyQueue.destroy(obj, {}); + // $ExpectType Promise + Parse.EventuallyQueue.length(); + // $ExpectType Promise + Parse.EventuallyQueue.sendQueue(); + // $ExpectType void + Parse.EventuallyQueue.stopPoll(); + // $ExpectType void + Parse.EventuallyQueue.poll(); + // $ExpectType void + Parse.EventuallyQueue.poll(300); + // @ts-expect-error + Parse.EventuallyQueue.poll('300'); + } +} + +function LiveQueryEvents() { + function testLiveQueryEvents() { + Parse.LiveQuery.on('open', () => {}); + Parse.LiveQuery.on('close', () => {}); + Parse.LiveQuery.on('error', (error: any) => {}); + } +} diff --git a/types/tsconfig.json b/types/tsconfig.json index d18d38fbe..040fee57f 100644 --- a/types/tsconfig.json +++ b/types/tsconfig.json @@ -13,7 +13,11 @@ // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index". // If the library is global (cannot be imported via `import` or `require`), leave this out. "baseUrl": ".", - "paths": { "parse": ["."] } + "paths": { + "parse": ["."], + "parse/node": ["./node.d.ts"], + "parse/react-native": ["./react-native.d.ts"] + } }, "include": [ "tests.ts"