diff --git a/package.json b/package.json index 5b2f0c7b37..d0d5a5022a 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ ], "license": "BSD-3-Clause", "dependencies": { - "babel-polyfill": "6.13.0", "bcryptjs": "2.3.0", "body-parser": "1.15.2", "commander": "2.9.0", @@ -66,10 +65,10 @@ "scripts": { "dev": "npm run build && node bin/dev", "build": "babel src/ -d lib/", - "test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js", - "test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/jasmine/bin/jasmine.js && npm run posttest", + "test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js", + "test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 node ./node_modules/jasmine/bin/jasmine.js && npm run posttest", "coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test", - "coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest", + "coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest", "start": "node ./bin/parse-server", "prepublish": "npm run build" }, diff --git a/spec/helper.js b/spec/helper.js index 28fe2a2b90..142bd8e670 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -14,6 +14,11 @@ global.on_db = (db, callback, elseCallback) => { } } +if (global._babelPolyfill) { + console.error('We should not use polyfilled tests'); + process.exit(1); +} + var cache = require('../src/cache').default; var express = require('express'); var facebook = require('../src/authDataManager/facebook'); @@ -214,7 +219,7 @@ afterEach(function(done) { } else { // Other system classes will break Parse.com, so make sure that we don't save anything to _SCHEMA that will // break it. - return ['_User', '_Installation', '_Role', '_Session', '_Product'].includes(className); + return ['_User', '_Installation', '_Role', '_Session', '_Product'].indexOf(className) >= 0; } }}); }); @@ -387,7 +392,7 @@ global.jfail = function(err) { } global.it_exclude_dbs = excluded => { - if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) { + if (excluded.indexOf(process.env.PARSE_SERVER_TEST_DB) >= 0) { return xit; } else { return it; @@ -395,7 +400,7 @@ global.it_exclude_dbs = excluded => { } global.fit_exclude_dbs = excluded => { - if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) { + if (excluded.indexOf(process.env.PARSE_SERVER_TEST_DB) >= 0) { return xit; } else { return fit; diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 5f043252ed..83bb840d92 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -99,7 +99,7 @@ const transformKeyValueForUpdate = (className, restKey, restValue, parseFormatSc } const transformInteriorValue = restValue => { - if (restValue !== null && typeof restValue === 'object' && Object.keys(restValue).some(key => key.includes('$') || key.includes('.'))) { + if (restValue !== null && typeof restValue === 'object' && Object.keys(restValue).some(key => key.includes('$')|| key.includes('.'))) { throw new Parse.Error(Parse.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters"); } // Handle atomic values diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index c364e3c6f1..7e0b8edd80 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -445,7 +445,7 @@ export class PostgresStorageAdapter { relations.push(fieldName) return; } - if (['_rperm', '_wperm'].includes(fieldName)) { + if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) { parseType.contents = { type: 'String' }; } valuesArray.push(fieldName); @@ -678,7 +678,7 @@ export class PostgresStorageAdapter { valuesArray.push(object[fieldName].objectId); break; case 'Array': - if (['_rperm', '_wperm'].includes(fieldName)) { + if (['_rperm', '_wperm'].indexOf(fieldName) >= 0) { valuesArray.push(object[fieldName]); } else { valuesArray.push(JSON.stringify(object[fieldName])); @@ -707,7 +707,7 @@ export class PostgresStorageAdapter { let initialValues = valuesArray.map((val, index) => { let termination = ''; let fieldName = columnsArray[index]; - if (['_rperm','_wperm'].includes(fieldName)) { + if (['_rperm','_wperm'].indexOf(fieldName) >= 0) { termination = '::text[]'; } else if (schema.fields[fieldName] && schema.fields[fieldName].type === 'Array') { termination = '::jsonb'; diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 618d304795..934fc488e3 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -44,6 +44,11 @@ const transformObjectACL = ({ ACL, ...result }) => { } const specialQuerykeys = ['$and', '$or', '_rperm', '_wperm', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count']; + +const isSpecialQueryKey = key => { + return specialQuerykeys.indexOf(key) >= 0; +} + const validateQuery = query => { if (query.ACL) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.'); @@ -73,7 +78,7 @@ const validateQuery = query => { } } } - if (!specialQuerykeys.includes(key) && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) { + if (!isSpecialQueryKey(key) && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) { throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${key}`); } }); @@ -185,6 +190,11 @@ const filterSensitiveData = (isMaster, aclGroup, className, object) => { // one of the provided strings must provide the caller with // write permissions. const specialKeysForUpdate = ['_hashed_password', '_perishable_token', '_email_verify_token', '_email_verify_token_expires_at', '_account_lockout_expires_at', '_failed_login_count']; + +const isSpecialUpdateKey = key => { + return specialKeysForUpdate.indexOf(key) >= 0; +} + DatabaseController.prototype.update = function(className, query, update, { acl, many, @@ -227,7 +237,7 @@ DatabaseController.prototype.update = function(className, query, update, { throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`); } fieldName = fieldName.split('.')[0]; - if (!SchemaController.fieldNameIsValid(fieldName) && !specialKeysForUpdate.includes(fieldName)) { + if (!SchemaController.fieldNameIsValid(fieldName) && !isSpecialUpdateKey(fieldName)) { throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`); } }); diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index d84f45ede2..316d3da362 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -218,7 +218,7 @@ const validNonRelationOrPointerTypes = [ ]; // Returns an error suitable for throwing if the type is invalid const fieldTypeIsInvalid = ({ type, targetClass }) => { - if (['Pointer', 'Relation'].includes(type)) { + if (['Pointer', 'Relation'].indexOf(type) >= 0) { if (!targetClass) { return new Parse.Error(135, `type ${type} needs a class name`); } else if (typeof targetClass !== 'string') { @@ -232,7 +232,7 @@ const fieldTypeIsInvalid = ({ type, targetClass }) => { if (typeof type !== 'string') { return invalidJsonError; } - if (!validNonRelationOrPointerTypes.includes(type)) { + if (validNonRelationOrPointerTypes.indexOf(type) < 0) { return new Parse.Error(Parse.Error.INCORRECT_TYPE, `invalid field type: ${type}`); } return undefined; @@ -520,7 +520,6 @@ export default class SchemaController { } }) .catch(error => { - console.error(error); // The schema still doesn't validate. Give up throw new Parse.Error(Parse.Error.INVALID_JSON, 'schema class name does not revalidate'); }); @@ -541,7 +540,7 @@ export default class SchemaController { validateSchemaData(className, fields, classLevelPermissions, existingFieldNames) { for (let fieldName in fields) { - if (!existingFieldNames.includes(fieldName)) { + if (existingFieldNames.indexOf(fieldName) < 0) { if (!fieldNameIsValid(fieldName)) { return { code: Parse.Error.INVALID_KEY_NAME, diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 6f737f6d58..7b752736b1 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -8,6 +8,7 @@ import RequestSchema from './RequestSchema'; import { matchesQuery, queryHash } from './QueryTools'; import { ParsePubSub } from './ParsePubSub'; import { SessionTokenCache } from './SessionTokenCache'; +import _ from 'lodash'; class ParseLiveQueryServer { clientId: number; @@ -116,7 +117,7 @@ class ParseLiveQueryServer { if (!isSubscriptionMatched) { continue; } - for (let [clientId, requestIds] of subscription.clientRequestIds.entries()) { + for (let [clientId, requestIds] of _.entries(subscription.clientRequestIds)) { let client = this.clients.get(clientId); if (typeof client === 'undefined') { continue; @@ -159,7 +160,7 @@ class ParseLiveQueryServer { for (let subscription of classSubscriptions.values()) { let isOriginalSubscriptionMatched = this._matchesSubscription(originalParseObject, subscription); let isCurrentSubscriptionMatched = this._matchesSubscription(currentParseObject, subscription); - for (let [clientId, requestIds] of subscription.clientRequestIds.entries()) { + for (let [clientId, requestIds] of _.entries(subscription.clientRequestIds)) { let client = this.clients.get(clientId); if (typeof client === 'undefined') { continue; @@ -269,7 +270,7 @@ class ParseLiveQueryServer { this.clients.delete(clientId); // Delete client from subscriptions - for (let [requestId, subscriptionInfo] of client.subscriptionInfos.entries()) { + for (let [requestId, subscriptionInfo] of _.entries(client.subscriptionInfos)) { let subscription = subscriptionInfo.subscription; subscription.deleteClientSubscription(clientId, requestId); diff --git a/src/ParseServer.js b/src/ParseServer.js index ca87883673..e4b325c521 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -9,10 +9,6 @@ var batch = require('./batch'), path = require('path'), authDataManager = require('./authDataManager'); -if (!global._babelPolyfill) { - require('babel-polyfill'); -} - import defaults from './defaults'; import * as logging from './logger'; import AppCache from './cache'; diff --git a/src/Routers/ClassesRouter.js b/src/Routers/ClassesRouter.js index e1d186c1ae..ee0d23ab45 100644 --- a/src/Routers/ClassesRouter.js +++ b/src/Routers/ClassesRouter.js @@ -1,7 +1,7 @@ import PromiseRouter from '../PromiseRouter'; import rest from '../rest'; - +import _ from 'lodash'; import url from 'url'; const ALLOWED_GET_QUERY_KEYS = ['keys', 'include']; @@ -115,7 +115,7 @@ export class ClassesRouter extends PromiseRouter { static JSONFromQuery(query) { let json = {}; - for (let [key, value] of Object.entries(query)) { + for (let [key, value] of _.entries(query)) { try { json[key] = JSON.parse(value); } catch (e) {