diff --git a/packages/react-core/__tests__/utils/featureFlags.test.js b/packages/react-core/__tests__/utils/featureFlags.test.js new file mode 100644 index 000000000..7d8453323 --- /dev/null +++ b/packages/react-core/__tests__/utils/featureFlags.test.js @@ -0,0 +1,64 @@ +import { hasFlag, setFlags, clearFlags } from '../../src/utils/featureFlags'; + +describe('Feature flags', () => { + afterEach(() => { + clearFlags(); + }); + + test('are not set initially', () => { + expect(hasFlag('A')).toStrictEqual(false); + expect(hasFlag('B')).toStrictEqual(false); + expect(hasFlag('C')).toStrictEqual(false); + }); + + test('can be set using an array of strings', () => { + setFlags(['A', 'B']); + expect(hasFlag('A')).toStrictEqual(true); + expect(hasFlag('B')).toStrictEqual(true); + expect(hasFlag('C')).toStrictEqual(false); + + setFlags([]); + expect(hasFlag('A')).toStrictEqual(false); + expect(hasFlag('B')).toStrictEqual(false); + expect(hasFlag('C')).toStrictEqual(false); + }); + + test('can be set using an object', () => { + setFlags({ + A: 10, + B: true, + C: false, + D: undefined, + E: null, + F: [], + G: {} + }); + expect(hasFlag('A')).toStrictEqual(true); + expect(hasFlag('B')).toStrictEqual(true); + expect(hasFlag('C')).toStrictEqual(false); + expect(hasFlag('D')).toStrictEqual(false); + expect(hasFlag('E')).toStrictEqual(false); + expect(hasFlag('F')).toStrictEqual(true); + expect(hasFlag('G')).toStrictEqual(true); + + setFlags({}); + expect(hasFlag('A')).toStrictEqual(false); + expect(hasFlag('B')).toStrictEqual(false); + expect(hasFlag('C')).toStrictEqual(false); + }); + + test('are cleared', () => { + setFlags(['A']); + expect(hasFlag('A')).toStrictEqual(true); + clearFlags(); + expect(hasFlag('A')).toStrictEqual(false); + }); + + const invaild = [10, '', 'A', false, { '': 10 }, ['A', '']]; + test.each(invaild)('fail in case of invalid flags %p', (x) => { + const t = () => { + setFlags(x); + }; + expect(t).toThrow(); + }); +}); diff --git a/packages/react-core/src/index.d.ts b/packages/react-core/src/index.d.ts index b89218369..f067bffd9 100644 --- a/packages/react-core/src/index.d.ts +++ b/packages/react-core/src/index.d.ts @@ -36,3 +36,9 @@ export { groupValuesByDateColumn } from './operations/groupByDate'; export { SpatialIndex } from './operations/constants/SpatialIndexTypes' export { FEATURE_SELECTION_MODES, EDIT_MODES, MASK_ID } from './utils/featureSelectionConstants'; + +export { + hasFlag as _hasFeatureFlag, + setFlags as _setFeatureFlags, + clearFlags as _clearFeatureFlags +} from './utils/featureFlags'; \ No newline at end of file diff --git a/packages/react-core/src/index.js b/packages/react-core/src/index.js index d55052d3a..31456ac87 100644 --- a/packages/react-core/src/index.js +++ b/packages/react-core/src/index.js @@ -47,3 +47,9 @@ export { EDIT_MODES, MASK_ID } from './utils/featureSelectionConstants'; + +export { + hasFlag as _hasFeatureFlag, + setFlags as _setFeatureFlags, + clearFlags as _clearFeatureFlags +} from './utils/featureFlags'; diff --git a/packages/react-core/src/utils/featureFlags.d.ts b/packages/react-core/src/utils/featureFlags.d.ts new file mode 100644 index 000000000..3b18740e9 --- /dev/null +++ b/packages/react-core/src/utils/featureFlags.d.ts @@ -0,0 +1,3 @@ +export function setFlags(flags: Record | string[]): void +export function clearFlags(): void +export function hasFlag(flag: string): boolean diff --git a/packages/react-core/src/utils/featureFlags.js b/packages/react-core/src/utils/featureFlags.js new file mode 100644 index 000000000..a91489645 --- /dev/null +++ b/packages/react-core/src/utils/featureFlags.js @@ -0,0 +1,30 @@ +let featureFlags = []; + +export function setFlags(flags) { + const isValidFlag = (f) => typeof f === 'string' && f; + + if (Array.isArray(flags) && flags.every(isValidFlag)) { + featureFlags = flags; + } else if ( + !Array.isArray(flags) && + typeof flags === 'object' && + Object.keys(flags).every(isValidFlag) + ) { + featureFlags = []; + for (const [flag, value] of Object.entries(flags)) { + if (value) { + featureFlags.push(flag); + } + } + } else { + throw new Error(`Invalid feature flags: ${flags}`); + } +} + +export function clearFlags() { + featureFlags = []; +} + +export function hasFlag(flag) { + return featureFlags.includes(flag); +}