Commit 62891a13 authored by Alejandro Celaya's avatar Alejandro Celaya Committed by Alejandro Celaya

Migrate features module to TypeScript

parent 32ddd01d
import { TinyEmitter } from 'tiny-emitter'; import { TinyEmitter } from 'tiny-emitter';
import { warnOnce } from '../shared/warn-once'; import { warnOnce } from '../shared/warn-once';
import type { FeatureFlags as IFeatureFlags } from '../types/annotator';
/**
* @typedef {import('../types/annotator').FeatureFlags} IFeatureFlags
*/
/** /**
* List of feature flags that annotator code tests for. * List of feature flags that annotator code tests for.
*
* @type {string[]}
*/ */
const annotatorFlags = ['html_side_by_side', 'styled_highlight_clusters']; const annotatorFlags = ['html_side_by_side', 'styled_highlight_clusters'];
/** /**
* An observable container of feature flags. * An observable container of feature flags.
*
* @implements {IFeatureFlags}
*/ */
export class FeatureFlags extends TinyEmitter { export class FeatureFlags extends TinyEmitter implements IFeatureFlags {
/** Map of flag name to enabled state. */
private _flags: Map<string, boolean>;
private _knownFlags: string[];
/** /**
* @param {string[]} knownFlags - Test seam. This is a list of known flags * @param knownFlags - Test seam. This is a list of known flags used to catch
* used to catch mistakes where code checks for an obsolete feature flag. * mistakes where code checks for an obsolete feature flag.
*/ */
constructor(knownFlags = annotatorFlags) { constructor(knownFlags: string[] = annotatorFlags) {
super(); super();
/** this._flags = new Map<string, boolean>();
* Map of flag name to enabled state.
*
* @type {Map<string, boolean>}
*/
this._flags = new Map();
this._knownFlags = knownFlags; this._knownFlags = knownFlags;
} }
/** /**
* Update the stored flags and notify observers via a "flagsChanged" event. * Update the stored flags and notify observers via a "flagsChanged" event.
*
* @param {Record<string, boolean>} flags
*/ */
update(flags) { update(flags: Record<string, boolean>) {
this._flags.clear(); this._flags.clear();
for (let [flag, on] of Object.entries(flags)) { for (const [flag, on] of Object.entries(flags)) {
this._flags.set(flag, on); this._flags.set(flag, on);
} }
this.emit('flagsChanged'); this.emit('flagsChanged');
...@@ -54,11 +44,8 @@ export class FeatureFlags extends TinyEmitter { ...@@ -54,11 +44,8 @@ export class FeatureFlags extends TinyEmitter {
* This will return false if the feature flags have not yet been received from * This will return false if the feature flags have not yet been received from
* the backend. Code that uses a feature flag should handle subsequent changes * the backend. Code that uses a feature flag should handle subsequent changes
* to the flag's state by listening for the "flagsChanged" event. * to the flag's state by listening for the "flagsChanged" event.
*
* @param {string} flag
* @return {boolean}
*/ */
flagEnabled(flag) { flagEnabled(flag: string): boolean {
if (!this._knownFlags.includes(flag)) { if (!this._knownFlags.includes(flag)) {
warnOnce('Looked up unknown feature', flag); warnOnce('Looked up unknown feature', flag);
return false; return false;
...@@ -72,7 +59,7 @@ export class FeatureFlags extends TinyEmitter { ...@@ -72,7 +59,7 @@ export class FeatureFlags extends TinyEmitter {
* To test whether an individual flag is enabled, use {@link flagEnabled} * To test whether an individual flag is enabled, use {@link flagEnabled}
* instead. * instead.
*/ */
allFlags() { allFlags(): Record<string, boolean> {
return Object.fromEntries(this._flags); return Object.fromEntries(this._flags);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment