Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: export public option types #1101

Merged
merged 2 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 0 additions & 83 deletions packages/react/src/common/options.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/react/src/context/use-context-mutator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback, useContext, useRef } from 'react';
import type { EvaluationContext } from '@openfeature/web-sdk';
import { OpenFeature } from '@openfeature/web-sdk';
import { Context } from '../common';
import { Context } from '../internal';

export type ContextMutationOptions = {
/**
Expand Down
11 changes: 4 additions & 7 deletions packages/react/src/evaluation/use-feature-flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
ProviderStatus,
} from '@openfeature/web-sdk';
import { useEffect, useRef, useState } from 'react';
import type { ReactFlagEvaluationOptions} from '../common';
import { DEFAULT_OPTIONS, isEqual, normalizeOptions, suspendUntilReady, useProviderOptions } from '../common';
import type { ReactFlagEvaluationNoSuspenseOptions, ReactFlagEvaluationOptions } from '../options';
import { DEFAULT_OPTIONS, isEqual, normalizeOptions, suspendUntilReady, useProviderOptions } from '../internal';
import { useOpenFeatureClient } from '../provider/use-open-feature-client';
import { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';
import type { FlagQuery } from '../query';
Expand All @@ -33,9 +33,6 @@ type ConstrainedFlagQuery<T> = FlagQuery<
: JsonValue
>;

// suspense options removed for the useSuspenseFlag hooks
type NoSuspenseOptions = Omit<ReactFlagEvaluationOptions, 'suspend' | 'suspendUntilReady' | 'suspendWhileReconciling'>;

/**
* Evaluates a feature flag generically, returning an react-flavored queryable object.
* The resolver method to use is based on the type of the defaultValue.
Expand Down Expand Up @@ -84,13 +81,13 @@ type UseFlagReturn<T extends FlagValue> = ReturnType<typeof useFlag<T>>;
* @param {string} flagKey the flag identifier
* @template {FlagValue} T A optional generic argument constraining the default.
* @param {T} defaultValue the default value; used to determine what resolved type should be used.
* @param {NoSuspenseOptions} options for this evaluation
* @param {ReactFlagEvaluationNoSuspenseOptions} options for this evaluation
* @returns { UseFlagReturn<T> } a queryable object containing useful information about the flag.
*/
export function useSuspenseFlag<T extends FlagValue = FlagValue>(
flagKey: string,
defaultValue: T,
options?: NoSuspenseOptions,
options?: ReactFlagEvaluationNoSuspenseOptions,
): UseFlagReturn<T> {
return useFlag(flagKey, defaultValue, { ...options, suspendUntilReady: true, suspendWhileReconciling: true });
}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from './query';
export * from './provider';
export * from './context';
export * from './tracking';
export * from './options';
// re-export the web-sdk so consumers can access that API from the react-sdk
export * from '@openfeature/web-sdk';
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import type { Client } from '@openfeature/web-sdk';
import React from 'react';
import type { NormalizedOptions, ReactFlagEvaluationOptions} from '../common';
import { normalizeOptions } from '../common';
import type { NormalizedOptions, ReactFlagEvaluationOptions } from '../options';
import { normalizeOptions } from '.';

/**
* The underlying React context.
* DO NOT EXPORT PUBLICLY
* @internal
*/
export const Context = React.createContext<{ client: Client; domain?: string; options: ReactFlagEvaluationOptions } | undefined>(undefined);
export const Context = React.createContext<
{ client: Client; domain?: string; options: ReactFlagEvaluationOptions } | undefined
>(undefined);

/**
* Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.
Expand Down
40 changes: 40 additions & 0 deletions packages/react/src/internal/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { ReactFlagEvaluationOptions, NormalizedOptions } from '../options';

/**
* Default options.
* DO NOT EXPORT PUBLICLY
* @internal
*/
export const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {
updateOnContextChanged: true,
updateOnConfigurationChanged: true,
suspendUntilReady: false,
suspendWhileReconciling: false,
};

/**
* Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).
* DO NOT EXPORT PUBLICLY
* @internal
* @param {ReactFlagEvaluationOptions} options options to normalize
* @returns {NormalizedOptions} normalized options
*/
export const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (
options: ReactFlagEvaluationOptions = {},
) => {
const updateOnContextChanged = options.updateOnContextChanged;
const updateOnConfigurationChanged = options.updateOnConfigurationChanged;

// fall-back the suspense options to the catch-all `suspend` property
const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;
const suspendWhileReconciling =
'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;

return {
// only return these if properly set (no undefined to allow overriding with spread)
...(typeof suspendUntilReady === 'boolean' && { suspendUntilReady }),
...(typeof suspendWhileReconciling === 'boolean' && { suspendWhileReconciling }),
...(typeof updateOnContextChanged === 'boolean' && { updateOnContextChanged }),
...(typeof updateOnConfigurationChanged === 'boolean' && { updateOnConfigurationChanged }),
};
};
53 changes: 53 additions & 0 deletions packages/react/src/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { FlagEvaluationOptions } from '@openfeature/web-sdk';

export type ReactFlagEvaluationOptions = (
| {
/**
* Enable or disable all suspense functionality.
* Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.
* @experimental Suspense is an experimental feature subject to change in future versions.
*/
suspend?: boolean;
suspendUntilReady?: never;
suspendWhileReconciling?: never;
}
| {
/**
* Suspend flag evaluations while the provider is not ready.
* Set to false if you don't want to show suspense fallbacks until the provider is initialized.
* Defaults to false.
* Cannot be used in conjunction with `suspend` option.
* @experimental Suspense is an experimental feature subject to change in future versions.
*/
suspendUntilReady?: boolean;
/**
* Suspend flag evaluations while the provider's context is being reconciled.
* Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.
* Defaults to false.
* Cannot be used in conjunction with `suspend` option.
* @experimental Suspense is an experimental feature subject to change in future versions.
*/
suspendWhileReconciling?: boolean;
suspend?: never;
}
) & {
/**
* Update the component if the provider emits a ConfigurationChanged event.
* Set to false to prevent components from re-rendering when flag value changes
* are received by the associated provider.
* Defaults to true.
*/
updateOnConfigurationChanged?: boolean;
/**
* Update the component when the OpenFeature context changes.
* Set to false to prevent components from re-rendering when attributes which
* may be factors in flag evaluation change.
* Defaults to true.
*/
updateOnContextChanged?: boolean;
} & FlagEvaluationOptions;

// suspense options removed for the useSuspenseFlag hooks
export type ReactFlagEvaluationNoSuspenseOptions = Omit<ReactFlagEvaluationOptions, 'suspend' | 'suspendUntilReady' | 'suspendWhileReconciling'>;

export type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;
4 changes: 2 additions & 2 deletions packages/react/src/provider/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Client} from '@openfeature/web-sdk';
import { OpenFeature } from '@openfeature/web-sdk';
import * as React from 'react';
import type { ReactFlagEvaluationOptions } from '../common';
import { Context } from '../common';
import type { ReactFlagEvaluationOptions } from '../options';
import { Context } from '../internal';

type ClientOrDomain =
| {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/provider/test-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
OpenFeature
} from '@openfeature/web-sdk';
import React from 'react';
import type { NormalizedOptions } from '../common';
import type { NormalizedOptions } from '../options';
import { OpenFeatureProvider } from './provider';

type FlagValueMap = { [flagKey: string]: JsonValue };
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/provider/use-open-feature-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Context } from '../common';
import { Context } from '../internal';
import type { Client } from '@openfeature/web-sdk';

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/provider/use-when-provider-ready.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ProviderStatus } from '@openfeature/web-sdk';
import { useOpenFeatureClient } from './use-open-feature-client';
import { useOpenFeatureClientStatus } from './use-open-feature-client-status';
import type { ReactFlagEvaluationOptions} from '../common';
import { DEFAULT_OPTIONS, useProviderOptions, normalizeOptions, suspendUntilReady } from '../common';
import type { ReactFlagEvaluationOptions } from '../options';
import { DEFAULT_OPTIONS, useProviderOptions, normalizeOptions, suspendUntilReady } from '../internal';

type Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;

Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/is-equal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isEqual } from '../src/common/is-equal';
import { isEqual } from '../src/internal/is-equal';

describe('isEqual', () => {
it('should return true for equal primitive values', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/options.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { normalizeOptions } from '../src/common/options';
import { normalizeOptions } from '../src/internal/options';

describe('normalizeOptions', () => {
// we spread results from this function, so we never want to return null
Expand Down
Loading