diff --git a/packages/optimizely-sdk/.eslintrc.js b/packages/optimizely-sdk/.eslintrc.js index 2c4fe5fd9..67f297049 100644 --- a/packages/optimizely-sdk/.eslintrc.js +++ b/packages/optimizely-sdk/.eslintrc.js @@ -14,7 +14,9 @@ module.exports = { Promise: 'readonly', }, parserOptions: { - ecmaVersion: 6, + // Note: The TS compiler determines what syntax is accepted. We're using TS version 3.3.3333. + // This seems to roughly correspond to "2018" for this setting. + ecmaVersion: 2018, sourceType: 'module', }, overrides: [ diff --git a/packages/optimizely-sdk/lib/core/optimizely_config/index.js b/packages/optimizely-sdk/lib/core/optimizely_config/index.js index 43527fe1d..89322c4df 100644 --- a/packages/optimizely-sdk/lib/core/optimizely_config/index.js +++ b/packages/optimizely-sdk/lib/core/optimizely_config/index.js @@ -110,12 +110,26 @@ function getFeaturesMap(configObj, allExperiments) { }, {}); } -export var getOptimizelyConfig = function(configObj) { - // Fetch all feature variables from feature flags to merge them with variation variables - var experimentsMap = getExperimentsMap(configObj); - return { - experimentsMap: experimentsMap, - featuresMap: getFeaturesMap(configObj, experimentsMap), - revision: configObj.revision, - }; -}; +/** + * The OptimizelyConfig class + * @param {Object} configObj + * @param {string} datafile + */ +export function OptimizelyConfig(configObj, datafile) { + this.experimentsMap = getExperimentsMap(configObj); + this.featuresMap = getFeaturesMap(configObj, this.experimentsMap); + this.revision = configObj.revision; + this.__datafile = datafile; +} + +/** + * Get the datafile + * @returns {string} JSON string representation of the datafile that was used to create the current config object + */ +OptimizelyConfig.prototype.getDatafile = function() { + return this.__datafile; +} + +export default { + OptimizelyConfig: OptimizelyConfig +} diff --git a/packages/optimizely-sdk/lib/core/optimizely_config/index.tests.js b/packages/optimizely-sdk/lib/core/optimizely_config/index.tests.js index f39b86918..1239d3d14 100644 --- a/packages/optimizely-sdk/lib/core/optimizely_config/index.tests.js +++ b/packages/optimizely-sdk/lib/core/optimizely_config/index.tests.js @@ -16,7 +16,7 @@ import { assert } from 'chai'; import { cloneDeep } from 'lodash'; -import { getOptimizelyConfig } from './index'; +import { OptimizelyConfig } from './index'; import { createProjectConfig } from '../project_config'; import { getTestProjectConfigWithFeatures } from '../../tests/test_data'; @@ -41,7 +41,7 @@ describe('lib/core/optimizely_config', function() { var projectConfigObject; beforeEach(function() { projectConfigObject = createProjectConfig(cloneDeep(datafile)); - optimizelyConfigObject = getOptimizelyConfig(projectConfigObject); + optimizelyConfigObject = new OptimizelyConfig(projectConfigObject, JSON.stringify(datafile)); }); it('should return all experiments except rollouts', function() { diff --git a/packages/optimizely-sdk/lib/core/project_config/index.js b/packages/optimizely-sdk/lib/core/project_config/index.js index 4db5003d5..e0a0e3690 100644 --- a/packages/optimizely-sdk/lib/core/project_config/index.js +++ b/packages/optimizely-sdk/lib/core/project_config/index.js @@ -18,8 +18,8 @@ import { sprintf, objectValues } from '@optimizely/js-sdk-utils'; import { assign, keyBy } from '../../utils/fns'; import { ERROR_MESSAGES, - LOG_MESSAGES, LOG_LEVEL, + LOG_MESSAGES, FEATURE_VARIABLE_TYPES, } from '../../utils/enums'; import configValidator from '../../utils/config_validator'; @@ -58,11 +58,14 @@ function createMutationSafeDatafileCopy(datafile) { /** * Creates projectConfig object to be used for quick project property lookup - * @param {Object} datafile JSON datafile representing the project - * @return {Object} Object representing project configuration + * @param {Object} datafileObj JSON datafile representing the project + * @param {string=} datafileStr JSON string representation of the datafile + * @return {Object} Object representing project configuration */ -export var createProjectConfig = function(datafile) { - var projectConfig = createMutationSafeDatafileCopy(datafile); +export var createProjectConfig = function(datafileObj, datafileStr=null) { + var projectConfig = createMutationSafeDatafileCopy(datafileObj); + + projectConfig.__datafileStr = datafileStr === null ? JSON.stringify(datafileObj) : datafileStr; /* * Conditions of audiences in projectConfig.typedAudiences are not @@ -512,7 +515,7 @@ export var getTypeCastValue = function(variableValue, variableType, logger) { /** * Returns an object containing all audiences in the project config. Keys are audience IDs * and values are audience objects. - * @param projectConfig + * @param {Object} projectConfig * @returns {Object} */ export var getAudiencesById = function(projectConfig) { @@ -521,8 +524,8 @@ export var getAudiencesById = function(projectConfig) { /** * Returns true if an event with the given key exists in the datafile, and false otherwise - * @param {Object} projectConfig - * @param {string} eventKey + * @param {Object} projectConfig + * @param {string} eventKey * @returns {boolean} */ export var eventWithKeyExists = function(projectConfig, eventKey) { @@ -530,35 +533,74 @@ export var eventWithKeyExists = function(projectConfig, eventKey) { }; /** - * + * Returns true if experiment belongs to any feature, false otherwise. * @param {Object} projectConfig * @param {string} experimentId - * @returns {boolean} Returns true if experiment belongs to - * any feature, false otherwise. + * @returns {boolean} */ export var isFeatureExperiment = function(projectConfig, experimentId) { return projectConfig.experimentFeatureMap.hasOwnProperty(experimentId); }; +/** + * Returns the JSON string representation of the datafile + * @param {Object} projectConfig + * @returns {string} + */ +export var toDatafile = function(projectConfig) { + return projectConfig.__datafileStr; +} + +/** + * @typedef {Object} TryCreatingProjectConfigResult + * @property {Object|null} configObj + * @property {Error|null} error + */ + /** * Try to create a project config object from the given datafile and * configuration properties. - * If successful, return the project config object, otherwise throws an error - * @param {Object} config - * @param {Object} config.datafile - * @param {Object} config.jsonSchemaValidator - * @param {Object} config.logger - * @return {Object} Project config object + * Returns an object with configObj and error properties. + * If successful, configObj is the project config object, and error is null. + * Otherwise, configObj is null and error is an error with more information. + * @param {Object} config + * @param {Object|string} config.datafile + * @param {Object} config.jsonSchemaValidator + * @param {Object} config.logger + * @returns {TryCreatingProjectConfigResult} */ export var tryCreatingProjectConfig = function(config) { - configValidator.validateDatafile(config.datafile); - if (!config.jsonSchemaValidator) { - config.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.SKIPPING_JSON_VALIDATION, MODULE_NAME)); + + var newDatafileObj; + try { + newDatafileObj = configValidator.validateDatafile(config.datafile); + } catch (error) { + return { configObj: null, error }; + } + + if (config.jsonSchemaValidator) { + try { + config.jsonSchemaValidator.validate(newDatafileObj); + config.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.VALID_DATAFILE, MODULE_NAME)); + } catch (error) { + return { configObj: null, error }; + } } else { - config.jsonSchemaValidator.validate(config.datafile); - config.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.VALID_DATAFILE, MODULE_NAME)); + config.logger.log(LOG_LEVEL.INFO, sprintf(LOG_MESSAGES.SKIPPING_JSON_VALIDATION, MODULE_NAME)); + } + + var createProjectConfigArgs = [newDatafileObj]; + if (typeof config.datafile === 'string') { + // Since config.datafile was validated above, we know that it is a valid JSON string + createProjectConfigArgs.push(config.datafile); } - return this.createProjectConfig(config.datafile); + + var newConfigObj = createProjectConfig(...createProjectConfigArgs); + + return { + configObj: newConfigObj, + error: null, + }; }; export default { @@ -583,5 +625,6 @@ export default { getAudiencesById: getAudiencesById, eventWithKeyExists: eventWithKeyExists, isFeatureExperiment: isFeatureExperiment, + toDatafile: toDatafile, tryCreatingProjectConfig: tryCreatingProjectConfig, }; diff --git a/packages/optimizely-sdk/lib/core/project_config/index.tests.js b/packages/optimizely-sdk/lib/core/project_config/index.tests.js index a2f01f8dd..aae687c8c 100644 --- a/packages/optimizely-sdk/lib/core/project_config/index.tests.js +++ b/packages/optimizely-sdk/lib/core/project_config/index.tests.js @@ -14,7 +14,7 @@ * limitations under the License. */ import sinon from 'sinon'; -import { assert } from 'chai'; +import { assert, expect, config } from 'chai'; import { forEach, cloneDeep } from 'lodash'; import { getLogger } from '@optimizely/js-sdk-logging'; import { sprintf } from '@optimizely/js-sdk-utils'; @@ -712,75 +712,91 @@ describe('lib/core/project_config', function() { stubJsonSchemaValidator = { validate: sinon.stub().returns(true), }; - sinon.stub(projectConfig, 'createProjectConfig').returns({}); sinon.stub(configValidator, 'validateDatafile').returns(true); sinon.spy(logger, 'error'); }); afterEach(function() { - projectConfig.createProjectConfig.restore(); configValidator.validateDatafile.restore(); logger.error.restore(); }); it('returns a project config object created by createProjectConfig when all validation is applied and there are no errors', function() { - configValidator.validateDatafile.returns(true); - stubJsonSchemaValidator.validate.returns(true); + var configDatafile = { + foo: 'bar', + experiments: [ + {key: 'a'}, + {key: 'b'} + ] + } + configValidator.validateDatafile.returns(configDatafile); var configObj = { foo: 'bar', experimentKeyMap: { - a: { key: 'a' }, - b: { key: 'b' }, + "a": { key: "a", variationKeyMap: {} }, + "b": { key: "b", variationKeyMap: {} } }, }; - projectConfig.createProjectConfig.returns(configObj); + + stubJsonSchemaValidator.validate.returns(true); + var result = projectConfig.tryCreatingProjectConfig({ - datafile: { foo: 'bar' }, + datafile: configDatafile, jsonSchemaValidator: stubJsonSchemaValidator, logger: logger, }); - assert.deepEqual(result, configObj); + + assert.deepInclude(result.configObj, configObj) }); - it('throws an error when validateDatafile throws', function() { + it('returns an error when validateDatafile throws', function() { configValidator.validateDatafile.throws(); stubJsonSchemaValidator.validate.returns(true); - assert.throws(function() { - projectConfig.tryCreatingProjectConfig({ - datafile: { foo: 'bar' }, - jsonSchemaValidator: stubJsonSchemaValidator, - logger: logger, - }); + var { error } = projectConfig.tryCreatingProjectConfig({ + datafile: { foo: 'bar' }, + jsonSchemaValidator: stubJsonSchemaValidator, + logger: logger, }); + assert.isNotNull(error); }); - it('throws an error when jsonSchemaValidator.validate throws', function() { + it('returns an error when jsonSchemaValidator.validate throws', function() { configValidator.validateDatafile.returns(true); stubJsonSchemaValidator.validate.throws(); - assert.throws(function() { - var result = projectConfig.tryCreatingProjectConfig({ - datafile: { foo: 'bar' }, - jsonSchemaValidator: stubJsonSchemaValidator, - logger: logger, - }); + var { error } = projectConfig.tryCreatingProjectConfig({ + datafile: { foo: 'bar' }, + jsonSchemaValidator: stubJsonSchemaValidator, + logger: logger, }); + assert.isNotNull(error); }); it('skips json validation when jsonSchemaValidator is not provided', function() { - configValidator.validateDatafile.returns(true); + + var configDatafile = { + foo: 'bar', + experiments: [ + {key: 'a'}, + {key: 'b'} + ] + } + + configValidator.validateDatafile.returns(configDatafile); + var configObj = { foo: 'bar', experimentKeyMap: { - a: { key: 'a' }, - b: { key: 'b' }, + a: { key: 'a', variationKeyMap: {} }, + b: { key: 'b', variationKeyMap: {} }, }, }; - projectConfig.createProjectConfig.returns(configObj); + var result = projectConfig.tryCreatingProjectConfig({ - datafile: { foo: 'bar' }, + datafile: configDatafile, logger: logger, }); - assert.deepEqual(result, configObj); + + assert.deepInclude(result.configObj, configObj); sinon.assert.notCalled(logger.error); }); }); diff --git a/packages/optimizely-sdk/lib/core/project_config/project_config_manager.js b/packages/optimizely-sdk/lib/core/project_config/project_config_manager.js index 3c8a723f5..7e32cd766 100644 --- a/packages/optimizely-sdk/lib/core/project_config/project_config_manager.js +++ b/packages/optimizely-sdk/lib/core/project_config/project_config_manager.js @@ -20,8 +20,7 @@ import { HttpPollingDatafileManager } from '@optimizely/js-sdk-datafile-manager' import { assign } from '../../utils/fns'; import { ERROR_MESSAGES } from '../../utils/enums'; import projectConfig from '../../core/project_config'; -import { getOptimizelyConfig } from '../optimizely_config'; -import configValidator from '../../utils/config_validator'; +import optimizelyConfig from '../optimizely_config'; var logger = getLogger(); var MODULE_NAME = 'PROJECT_CONFIG_MANAGER'; @@ -92,22 +91,8 @@ ProjectConfigManager.prototype.__initialize = function(config) { return; } - var initialDatafile = this.__getDatafileFromConfig(config); - var projectConfigCreationEx; - if (initialDatafile) { - try { - this.__configObj = projectConfig.tryCreatingProjectConfig({ - datafile: initialDatafile, - jsonSchemaValidator: this.jsonSchemaValidator, - logger: logger, - }); - this.__optimizelyConfigObj = getOptimizelyConfig(this.__configObj); - } catch (ex) { - logger.error(ex); - projectConfigCreationEx = ex; - this.__configObj = null; - } - } else { + var handleNewDatafileException = this.__handleNewDatafile(config.datafile); + if (handleNewDatafileException) { this.__configObj = null; } @@ -118,8 +103,8 @@ ProjectConfigManager.prototype.__initialize = function(config) { if (this.__validateDatafileOptions(config.datafileOptions)) { assign(datafileManagerConfig, config.datafileOptions); } - if (initialDatafile && this.__configObj) { - datafileManagerConfig.datafile = initialDatafile; + if (this.__configObj) { + datafileManagerConfig.datafile = projectConfig.toDatafile(this.__configObj) } this.datafileManager = new HttpPollingDatafileManager(datafileManagerConfig); this.datafileManager.start(); @@ -134,7 +119,7 @@ ProjectConfigManager.prototype.__initialize = function(config) { } else { this.__readyPromise = Promise.resolve({ success: false, - reason: getErrorMessage(projectConfigCreationEx, 'Invalid datafile'), + reason: getErrorMessage(handleNewDatafileException, 'Invalid datafile'), }); } }; @@ -148,25 +133,14 @@ ProjectConfigManager.prototype.__initialize = function(config) { * successful result. */ ProjectConfigManager.prototype.__onDatafileManagerReadyFulfill = function() { - var newDatafile = this.datafileManager.get(); - var newConfigObj; - try { - newConfigObj = projectConfig.tryCreatingProjectConfig({ - datafile: newDatafile, - jsonSchemaValidator: this.jsonSchemaValidator, - logger: logger, - }); - } catch (ex) { - logger.error(ex); + var newDatafileError = this.__handleNewDatafile(this.datafileManager.get()); + if (newDatafileError) { return { success: false, - reason: getErrorMessage(ex), + reason: getErrorMessage(newDatafileError), }; } - this.__handleNewConfigObj(newConfigObj); - return { - success: true, - }; + return { success: true }; }; /** @@ -189,45 +163,7 @@ ProjectConfigManager.prototype.__onDatafileManagerReadyReject = function(err) { * update listeners if successful */ ProjectConfigManager.prototype.__onDatafileManagerUpdate = function() { - var newDatafile = this.datafileManager.get(); - var newConfigObj; - try { - newConfigObj = projectConfig.tryCreatingProjectConfig({ - datafile: newDatafile, - jsonSchemaValidator: this.jsonSchemaValidator, - logger: logger, - }); - } catch (ex) { - logger.error(ex); - } - if (newConfigObj) { - this.__handleNewConfigObj(newConfigObj); - } -}; - -/** - * If the argument config contains a valid datafile object or string, - * return a datafile object based on that provided datafile, otherwise - * return null. - * @param {Object} config - * @param {Object|string=} config.datafile - * @return {Object|null} - */ -ProjectConfigManager.prototype.__getDatafileFromConfig = function(config) { - var initialDatafile = null; - try { - if (config.datafile) { - configValidator.validateDatafile(config.datafile); - if (typeof config.datafile === 'string' || config.datafile instanceof String) { - initialDatafile = JSON.parse(config.datafile); - } else { - initialDatafile = config.datafile; - } - } - } catch (ex) { - logger.error(ex); - } - return initialDatafile; + this.__handleNewDatafile(this.datafileManager.get()); }; /** @@ -248,25 +184,34 @@ ProjectConfigManager.prototype.__validateDatafileOptions = function(datafileOpti }; /** - * Update internal project config object to be argument object when the argument - * object has a different revision than the current internal project config - * object. If the internal object is updated, call update listeners. - * @param {Object} newConfigObj + * Handle new datafile by attemping to create a new Project Config object. If successful and + * the new config object's revision is newer than the current one, sets/updates the project config + * and optimizely config object instance variables and returns null for the error. If unsuccessful, + * the project config and optimizely config objects will not be updated, and the error is returned. + * @param {Object|string} newDatafile + * @returns {Error|null} error */ -ProjectConfigManager.prototype.__handleNewConfigObj = function(newConfigObj) { - var oldConfigObj = this.__configObj; +ProjectConfigManager.prototype.__handleNewDatafile = function(newDatafile) { + var { configObj, error } = projectConfig.tryCreatingProjectConfig({ + datafile: newDatafile, + jsonSchemaValidator: this.jsonSchemaValidator, + logger: logger + }); - var oldRevision = oldConfigObj ? oldConfigObj.revision : 'null'; - if (oldRevision === newConfigObj.revision) { - return; + if (error) { + logger.error(error); + } else { + var oldRevision = this.__configObj ? this.__configObj.revision : 'null'; + if (oldRevision !== configObj.revision) { + this.__configObj = configObj; + this.__optimizelyConfigObj = new optimizelyConfig.OptimizelyConfig(this.__configObj, projectConfig.toDatafile(this.__configObj)); + this.__updateListeners.forEach(function(listener) { + listener(configObj); + }); + } } - this.__configObj = newConfigObj; - this.__optimizelyConfigObj = getOptimizelyConfig(newConfigObj); - - this.__updateListeners.forEach(function(listener) { - listener(newConfigObj); - }); + return error; }; /** diff --git a/packages/optimizely-sdk/lib/core/project_config/project_config_manager.tests.js b/packages/optimizely-sdk/lib/core/project_config/project_config_manager.tests.js index e43b95fc5..24e4752bf 100644 --- a/packages/optimizely-sdk/lib/core/project_config/project_config_manager.tests.js +++ b/packages/optimizely-sdk/lib/core/project_config/project_config_manager.tests.js @@ -23,7 +23,7 @@ import * as datafileManager from '@optimizely/js-sdk-datafile-manager'; import projectConfig from './index'; import { ERROR_MESSAGES, LOG_MESSAGES } from '../../utils/enums'; import testData from '../../tests/test_data'; -import * as optimizelyConfig from '../optimizely_config/index'; +import optimizelyConfig from '../optimizely_config/index'; import projectConfigManager from './project_config_manager'; import * as jsonSchemaValidator from '../../utils/json_schema_validator'; @@ -144,6 +144,7 @@ describe('lib/core/project_config/project_config_manager', function() { sinon.assert.calledOnce(stubLogHandler.log); var logMessage = stubLogHandler.log.args[0][1]; assert.strictEqual(logMessage, sprintf(LOG_MESSAGES.VALID_DATAFILE, 'PROJECT_CONFIG')); + return manager.onReady(); }); }); @@ -188,7 +189,7 @@ describe('lib/core/project_config/project_config_manager', function() { sinon.assert.calledWithExactly( datafileManager.HttpPollingDatafileManager, sinon.match({ - datafile: config, + datafile: JSON.stringify(config), sdkKey: '12345', autoUpdate: true, updateInterval: 10000, @@ -202,7 +203,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(cloneDeep(configWithFeatures)), + get: sinon.stub().returns(JSON.stringify(cloneDeep(configWithFeatures))), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -240,7 +241,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(testData.getTestProjectConfigWithFeatures()), + get: sinon.stub().returns(JSON.stringify(testData.getTestProjectConfigWithFeatures())), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -267,7 +268,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(testData.getTestProjectConfigWithFeatures()), + get: sinon.stub().returns(JSON.stringify(testData.getTestProjectConfigWithFeatures())), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -305,7 +306,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(invalidDatafile), + get: sinon.stub().returns(JSON.stringify(invalidDatafile)), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -353,7 +354,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(testData.getTestProjectConfigWithFeatures()), + get: sinon.stub().returns(JSON.stringify(testData.getTestProjectConfigWithFeatures())), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -380,7 +381,7 @@ describe('lib/core/project_config/project_config_manager', function() { datafileManager.HttpPollingDatafileManager.returns({ start: sinon.stub(), stop: sinon.stub(), - get: sinon.stub().returns(testData.getTestProjectConfigWithFeatures()), + get: sinon.stub().returns(JSON.stringify(testData.getTestProjectConfigWithFeatures())), on: sinon.stub().returns(function() {}), onReady: sinon.stub().returns(Promise.resolve()), }); @@ -404,11 +405,11 @@ describe('lib/core/project_config/project_config_manager', function() { describe('test caching of optimizely config', function() { beforeEach(function() { - sinon.stub(optimizelyConfig, 'getOptimizelyConfig'); + sinon.stub(optimizelyConfig, 'OptimizelyConfig'); }); afterEach(function() { - optimizelyConfig.getOptimizelyConfig.restore(); + optimizelyConfig.OptimizelyConfig.restore(); }); it('should return the same config until revision is changed', function() { @@ -417,10 +418,10 @@ describe('lib/core/project_config/project_config_manager', function() { sdkKey: '12345', }); // creating optimizely config once project config manager for the first time - sinon.assert.calledOnce(optimizelyConfig.getOptimizelyConfig); + sinon.assert.calledOnce(optimizelyConfig.OptimizelyConfig); // validate it should return the existing optimizely config manager.getOptimizelyConfig(); - sinon.assert.calledOnce(optimizelyConfig.getOptimizelyConfig); + sinon.assert.calledOnce(optimizelyConfig.OptimizelyConfig); // create config with new revision var fakeDatafileManager = datafileManager.HttpPollingDatafileManager.getCall(0).returnValue; var updateListener = fakeDatafileManager.on.getCall(0).args[1]; @@ -429,7 +430,7 @@ describe('lib/core/project_config/project_config_manager', function() { fakeDatafileManager.get.returns(newDatafile); updateListener({ datafile: newDatafile }); // verify the optimizely config is updated - sinon.assert.calledTwice(optimizelyConfig.getOptimizelyConfig); + sinon.assert.calledTwice(optimizelyConfig.OptimizelyConfig); }); }); }); diff --git a/packages/optimizely-sdk/lib/index.browser.js b/packages/optimizely-sdk/lib/index.browser.js index 00c2b231f..8a4286ec5 100644 --- a/packages/optimizely-sdk/lib/index.browser.js +++ b/packages/optimizely-sdk/lib/index.browser.js @@ -44,16 +44,17 @@ var hasRetriedEvents = false; /** * Creates an instance of the Optimizely class - * @param {Object} config - * @param {Object} config.datafile - * @param {Object} config.errorHandler - * @param {Object} config.eventDispatcher - * @param {Object} config.logger - * @param {Object} config.logLevel - * @param {Object} config.userProfileService - * @param {Object} config.eventBatchSize - * @param {Object} config.eventFlushInterval - * @return {Object} the Optimizely object + * @param {Object} config + * @param {Object|string} config.datafile + * @param {Object} config.errorHandler + * @param {Object} config.eventDispatcher + * @param {Object} config.logger + * @param {Object} config.logLevel + * @param {Object} config.userProfileService + * @param {Object} config.eventBatchSize + * @param {Object} config.eventFlushInterval + * @param {string} config.sdkKey + * @return {Object} the Optimizely object */ var createInstance = function(config) { try { diff --git a/packages/optimizely-sdk/lib/index.node.js b/packages/optimizely-sdk/lib/index.node.js index f1de12064..bcdac59b7 100644 --- a/packages/optimizely-sdk/lib/index.node.js +++ b/packages/optimizely-sdk/lib/index.node.js @@ -39,15 +39,17 @@ var DEFAULT_EVENT_FLUSH_INTERVAL = 30000; // Unit is ms, default is 30s /** * Creates an instance of the Optimizely class - * @param {Object} config - * @param {Object} config.datafile - * @param {Object} config.errorHandler - * @param {Object} config.eventDispatcher - * @param {Object} config.logger - * @param {Object} config.userProfileService - * @param {Object} config.eventBatchSize - * @param {Object} config.eventFlushInterval - * @return {Object} the Optimizely object + * @param {Object} config + * @param {Object|string} config.datafile + * @param {Object} config.errorHandler + * @param {Object} config.eventDispatcher + * @param {Object} config.logger + * @param {Object} config.logLevel + * @param {Object} config.userProfileService + * @param {Object} config.eventBatchSize + * @param {Object} config.eventFlushInterval + * @param {string} config.sdkKey + * @return {Object} the Optimizely object */ var createInstance = function(config) { try { diff --git a/packages/optimizely-sdk/lib/index.react_native.js b/packages/optimizely-sdk/lib/index.react_native.js index b610a0a1e..d69bbcae3 100644 --- a/packages/optimizely-sdk/lib/index.react_native.js +++ b/packages/optimizely-sdk/lib/index.react_native.js @@ -41,16 +41,17 @@ var DEFAULT_EVENT_MAX_QUEUE_SIZE = 10000; /** * Creates an instance of the Optimizely class - * @param {Object} config - * @param {Object} config.datafile - * @param {Object} config.errorHandler - * @param {Object} config.eventDispatcher - * @param {Object} config.logger - * @param {Object} config.logLevel - * @param {Object} config.userProfileService - * @param {Object} config.eventBatchSize - * @param {Object} config.eventFlushInterval - * @return {Object} the Optimizely object + * @param {Object} config + * @param {Object|string} config.datafile + * @param {Object} config.errorHandler + * @param {Object} config.eventDispatcher + * @param {Object} config.logger + * @param {Object} config.logLevel + * @param {Object} config.userProfileService + * @param {Object} config.eventBatchSize + * @param {Object} config.eventFlushInterval + * @param {string} config.sdkKey + * @return {Object} the Optimizely object */ var createInstance = function(config) { try { diff --git a/packages/optimizely-sdk/lib/optimizely/index.js b/packages/optimizely-sdk/lib/optimizely/index.js index 3c8ab6f50..fd15337da 100644 --- a/packages/optimizely-sdk/lib/optimizely/index.js +++ b/packages/optimizely-sdk/lib/optimizely/index.js @@ -42,16 +42,17 @@ var DEFAULT_ONREADY_TIMEOUT = 30000; /** * The Optimizely class - * @param {Object} config - * @param {string} config.clientEngine - * @param {string} config.clientVersion - * @param {Object} config.datafile - * @param {Object} config.errorHandler - * @param {Object} config.eventDispatcher - * @param {Object} config.logger - * @param {Object} config.userProfileService - * @param {Object} config.eventBatchSize - * @param {Object} config.eventFlushInterval + * @param {Object} config + * @param {string} config.clientEngine + * @param {string} config.clientVersion + * @param {Object|string} config.datafile + * @param {Object} config.errorHandler + * @param {Object} config.eventDispatcher + * @param {Object} config.logger + * @param {Object} config.userProfileService + * @param {Object} config.eventBatchSize + * @param {Object} config.eventFlushInterval + * @param {string} config.sdkKey */ function Optimizely(config) { var clientEngine = config.clientEngine; diff --git a/packages/optimizely-sdk/lib/utils/config_validator/index.ts b/packages/optimizely-sdk/lib/utils/config_validator/index.ts index e28da4bbe..d71841581 100644 --- a/packages/optimizely-sdk/lib/utils/config_validator/index.ts +++ b/packages/optimizely-sdk/lib/utils/config_validator/index.ts @@ -50,14 +50,15 @@ export const validate = function(config: unknown): boolean { /** * Validates the datafile - * @param {string} datafile - * @return {boolean} true if the datafile is valid + * @param {Object|string} datafile + * @return {Object} The datafile object if the datafile is valid * @throws If the datafile is not valid for any of the following reasons: - The datafile string is undefined - The datafile string cannot be parsed as a JSON object - The datafile version is not supported */ -export const validateDatafile = function(datafile: unknown): boolean { +// eslint-disable-next-line +export const validateDatafile = function(datafile: unknown): any { if (!datafile) { throw new Error(sprintf(ERROR_MESSAGES.NO_DATAFILE_SPECIFIED, MODULE_NAME)); } @@ -74,8 +75,9 @@ export const validateDatafile = function(datafile: unknown): boolean { throw new Error(sprintf(ERROR_MESSAGES.INVALID_DATAFILE_VERSION, MODULE_NAME, datafile['version'])); } } - return true; -} + + return datafile; +}; /** * Provides utility methods for validating that the configuration options are valid diff --git a/packages/optimizely-sdk/package-lock.json b/packages/optimizely-sdk/package-lock.json index 2a08f18b7..5a7bbe35f 100644 --- a/packages/optimizely-sdk/package-lock.json +++ b/packages/optimizely-sdk/package-lock.json @@ -381,9 +381,9 @@ "dev": true }, "@optimizely/js-sdk-datafile-manager": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@optimizely/js-sdk-datafile-manager/-/js-sdk-datafile-manager-0.7.0.tgz", - "integrity": "sha512-pphm9o9ats3TCPgKiSfZm35Fk/tF0Tz/RXSqcEJZd1u6Bm1kYNze0ZBHCr3NTH927vo0gglNZZxB/UEELpdYBg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@optimizely/js-sdk-datafile-manager/-/js-sdk-datafile-manager-0.8.0.tgz", + "integrity": "sha512-eTpWhLisgXLlUFy0Qz6SP0yKYYwyP8DDLt6nwZky33lka2kustQMnfI0uhNN8EAdx/vayxuTdmaYRWBy+pS7Vg==", "requires": { "@optimizely/js-sdk-logging": "^0.1.0", "@optimizely/js-sdk-utils": "^0.4.0", @@ -5431,7 +5431,7 @@ "mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", "dev": true, "requires": { "browser-stdout": "1.3.1", @@ -5450,7 +5450,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -5465,7 +5465,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "^3.0.0" diff --git a/packages/optimizely-sdk/package.json b/packages/optimizely-sdk/package.json index 3db51121b..a444a0ece 100644 --- a/packages/optimizely-sdk/package.json +++ b/packages/optimizely-sdk/package.json @@ -41,7 +41,7 @@ }, "homepage": "https://github.com/optimizely/javascript-sdk/tree/master/packages/optimizely-sdk", "dependencies": { - "@optimizely/js-sdk-datafile-manager": "^0.7.0", + "@optimizely/js-sdk-datafile-manager": "^0.8.0", "@optimizely/js-sdk-event-processor": "^0.6.0", "@optimizely/js-sdk-logging": "^0.1.0", "@optimizely/js-sdk-utils": "^0.4.0",