feat(OptimizelyConfig): Add new fields to OptimizelyConfig #698
feat(OptimizelyConfig): Add new fields to OptimizelyConfig #698msohailhussain merged 12 commits intomasterfrom
Conversation
| constructor(configObj: ProjectConfig, datafile: string) { | ||
| this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
| this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
| this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; |
There was a problem hiding this comment.
You can use configObj.sdkKey ?? ''; if you want.
| let cond = ''; | ||
| conditions.forEach((item) => { | ||
| let subAudience = ''; | ||
| // Checks if item is list of conditions means if it is sub audience |
There was a problem hiding this comment.
// Checks if item is list of conditions means it is sub audience
| Audience, | ||
| Experiment, | ||
| FeatureVariable, | ||
| OptimizelyExperimentsMap, | ||
| OptimizelyFeaturesMap, | ||
| OptimizelyVariablesMap, | ||
| FeatureVariable, | ||
| OptimizelyAttribute, | ||
| OptimizelyAudience, | ||
| OptimizelyEvent, | ||
| OptimizelyExperiment, | ||
| OptimizelyVariable, | ||
| OptimizelyVariation, | ||
| Rollout, | ||
| VariationVariable, | ||
| Variation, | ||
| Rollout, |
There was a problem hiding this comment.
NIT: arrange these in alphabetical order
| public audiences: OptimizelyAudience[]; | ||
| public events: OptimizelyEvent[]; | ||
| private datafile: string; | ||
| private static audienceConditionalOperators: string[] = ['and', 'or', 'not']; |
There was a problem hiding this comment.
This can probably be moved to ENUMS?
| constructor(configObj: ProjectConfig, datafile: string) { | ||
| this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
| this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
| this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; |
There was a problem hiding this comment.
| this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; | |
| this.sdkKey = configObj.sdkKey || ''; |
| this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
| this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
| this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; | ||
| this.environmentKey = configObj.environmentKey ? configObj.environmentKey : ''; |
There was a problem hiding this comment.
| this.environmentKey = configObj.environmentKey ? configObj.environmentKey : ''; | |
| this.environmentKey = configObj.environmentKey || ''; |
| * @returns {OptimizelyAudience[]} Array of unique audiences | ||
| */ | ||
| static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] { | ||
| const finalAudiences: OptimizelyAudience[] = []; |
There was a problem hiding this comment.
why call it finalAudiences? can you simply call it audiences
| if (item instanceof Array) { | ||
| subAudience = OptimizelyConfig.GetSerializedAudiences(item, audiencesById); | ||
| subAudience = `(${subAudience})`; | ||
| } else if (OptimizelyConfig.audienceConditionalOperators.includes(item)) { | ||
| cond = item.toUpperCase(); | ||
| } else { | ||
| // Checks if item is audience id | ||
| const audienceName = audiencesById[item] ? audiencesById[item].name : item; | ||
| // if audience condition is "NOT" then add "NOT" at start. Otherwise check if there is already audience id in serializedAudience then append condition between serializedAudience and item | ||
| if (serializedAudience || cond === 'NOT') { | ||
| cond = cond === '' ? 'OR' : cond; | ||
| if (serializedAudience === '') { | ||
| serializedAudience = `${cond} "${audiencesById[item].name}"`; | ||
| } else { | ||
| serializedAudience = serializedAudience.concat(` ${cond} "${audienceName}"`); | ||
| } | ||
| } else { | ||
| serializedAudience = `"${audienceName}"`; | ||
| } | ||
| } | ||
| // Checks if sub audience is empty or not | ||
| if (subAudience !== '') { | ||
| if (serializedAudience !== '' || cond === 'NOT') { | ||
| cond = cond === '' ? 'OR' : cond; | ||
| if (serializedAudience === '') { | ||
| serializedAudience = `${cond} ${subAudience}`; | ||
| } else { | ||
| serializedAudience = serializedAudience.concat(` ${cond} ${subAudience}`); | ||
| } | ||
| } else { | ||
| serializedAudience = serializedAudience.concat(subAudience); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| return serializedAudience; |
There was a problem hiding this comment.
NOT reviewing this code. will leave it to @msohailhussain and @jaeopt as they have more context about this particular peice
|
|
||
| const variableIdMap = OptimizelyConfig.getVariableIdMap(configObj); | ||
|
|
||
| experiments.forEach((experiment) => { |
There was a problem hiding this comment.
you could use map here and assigned the result directly to deliveryRules?
| }, | ||
| {}, | ||
| ) | ||
| experiments.forEach((experiment) => { |
There was a problem hiding this comment.
could do reduce here probably?
| datafileCopy.environmentKey = datafile.environmentKey; | ||
| datafileCopy.sdkKey = datafile.sdkKey; | ||
| } | ||
| datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; |
There was a problem hiding this comment.
| datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; | |
| datafileCopy.environmentKey = datafile.environmentKey || ''; |
| datafileCopy.sdkKey = datafile.sdkKey; | ||
| } | ||
| datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; | ||
| datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : ''; |
There was a problem hiding this comment.
| datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : ''; | |
| datafileCopy.sdkKey = datafile.sdkKey || ''; |
| export type OptimizelyAudience = { | ||
| id: string; | ||
| name: string; | ||
| conditions: unknown[] | string; |
There was a problem hiding this comment.
It appears that we expect conditions type here to just be string since we JSON.stringify the typedAudience/oldAudience conditions
| * @param {string} featureId | ||
| * @returns {[key: string]: Variation} Variations mapped by key | ||
| */ | ||
| static GetVariationsMap( |
There was a problem hiding this comment.
Why this method is also capitalized?
| * @param {[id: string]: Audience} audiencesById | ||
| * @returns {string} Serialized audiences condition string | ||
| */ | ||
| static GetSerializedAudiences( |
There was a problem hiding this comment.
Why are we capitalizing this method?
| export interface OptimizelyExperiment { | ||
| id: string; | ||
| key: string; | ||
| audiences: unknown[] | string; |
| configObj: ProjectConfig, | ||
| featureVariableIdMap: FeatureVariablesMap, | ||
| featureId: string, | ||
| experiments: Experiment[] | undefined |
There was a problem hiding this comment.
This should not be expected undefined as every rollout object should contain experiments. @msohailhussain please correct if I am wrong.
| experiments: Experiment[] | undefined | ||
| ): OptimizelyExperiment[] { | ||
| const deliveryRules: OptimizelyExperiment[] = []; | ||
| if (!experiments) { |
There was a problem hiding this comment.
If above is true, this if statement is unnecessary.
| isFeatureEnabled: boolean | undefined | ||
| ): OptimizelyVariablesMap { | ||
| let variablesMap: OptimizelyVariablesMap = {}; | ||
| if (!featureId) { |
There was a problem hiding this comment.
This statement seems unnecessary as we should expect a valid featureId, right?
| */ | ||
| static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] { | ||
| const finalAudiences: OptimizelyAudience[] = []; | ||
| const typedAudienceIds: { [id: string]: boolean } = {}; |
There was a problem hiding this comment.
i agree. there is one more existing code that's using the same kv map, we should use .includes and only use Ids arrays.
| return (rollouts || []).reduce((experimentIds: { [key: string]: boolean }, rollout) => { | ||
| rollout.experiments.forEach((e) => { | ||
| (experimentIds)[e.id] = true; | ||
| experimentIds[e.id] = true; |
There was a problem hiding this comment.
same comment, use .includes more cleaner.
yavorona
left a comment
There was a problem hiding this comment.
Looks good except for couple of minor comments and failing browser stack tests.
| featureId: string | ||
| ): { [key: string]: Variation } { | ||
| let variationsMap: { [key: string]: OptimizelyVariation } = {}; | ||
| variationsMap = variations.reduce((OptlyVariationsMap: { [key: string]: OptimizelyVariation }, variation) => { |
There was a problem hiding this comment.
optlyVariationsMap instead of OptlyVariationsMap
| isFeatureEnabled: boolean | undefined | ||
| ): OptimizelyVariablesMap { | ||
| const variablesMap = (featureIdVariableMap[featureId] || []).reduce( | ||
| (OptlyVariablesMap: OptimizelyVariablesMap, featureVariable) => { |
There was a problem hiding this comment.
optlyVariablesMap instead of OptlyVariablesMap
jaeopt
left a comment
There was a problem hiding this comment.
Overall looks great!
- One comment about using OptimizelyConfig types internally.
- Also I do not see duplicate-key warning about experimentsMap in OptimizelyConfig and deprecation warning about experimentsMap in OptimizelyFeature.
| groups: Group[]; | ||
| events: Event[]; | ||
| attributes: Array<{ id: string }>; | ||
| attributes: OptimizelyAttribute[]; |
There was a problem hiding this comment.
I think it's not a good idea to use "OptimizelyAttribute" or other "OptimizelyXYZ" types in here.
Even if they look identical for now, we should separate them as public types only.
There was a problem hiding this comment.
makes sense, thanks.
Had already added for Also added for OptimizelyConfig Interface here but forgot about the class which i have added now. Comment on the interface can be seen here: https://github.com/optimizely/javascript-sdk/pull/698/files#diff-2f8a7f1ccf360ce99abd03c811c59f9488fa24db24f8578d808e813e75192acdR347 |
jaeopt
left a comment
There was a problem hiding this comment.
LGTM
nit - add a period (.) at the end of "This experimentsMap is for experiments of legacy projects only" in multiple places.
Summary
The following new public properties are added to OptimizelyConfig:
Test plan
All FSC tests OPTIMIZELY_CONFIG_V2 tests should pass.
FSC OptimizelyConfig link