feature-flags.js 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. /** global Scenario */
  2. /**
  3. * @param {Array<string>} flags
  4. * @param {Function} scenarios
  5. **/
  6. module.exports.FFlagMatrix = function (flags, scenarios) {
  7. // create a matrix of all possible flag combinations
  8. let length = flags.length ** 2;
  9. if (length === 1) length = 2;
  10. const flagMatrix = [];
  11. for (let i = 0; i < length; i++) {
  12. flagMatrix.push({
  13. ...flags.reduce((acc, flag) => ({ ...acc, [flag]: false }), {}),
  14. });
  15. }
  16. // update each flag combination with all possible states
  17. // e.g. [ { flag1: false, flag2: false }, { flag1: true, flag2: false }, ... ]
  18. flags.forEach((flag, index) => {
  19. flagMatrix.forEach((currentFlags, flagIndex) => {
  20. const state = Boolean((flagIndex >> index) & 1);
  21. flagMatrix[flagIndex][flag] = state;
  22. });
  23. });
  24. flagMatrix.forEach((currentFlags) => {
  25. this.flags = currentFlags;
  26. scenarios.bind(this)(currentFlags);
  27. });
  28. };
  29. /**
  30. * @param {string} scenarioName
  31. * @param {Function} scenario
  32. **/
  33. module.exports.FFlagScenario = function (scenarioName, scenario) {
  34. if (!this.flags) throw new Error("FFlagMatrix must wrap calls to FFlagScenario");
  35. const variant = ` :: ${Object.entries(this.flags)
  36. .map(([flag, state]) => `${flag}=${state}`)
  37. .join(",")}`;
  38. return Scenario(scenarioName + variant, scenario);
  39. };