|
| 1 | +import type { components } from 'api-types' |
| 2 | +import enabledFeaturesRaw from './enabled-features.json' |
| 3 | + |
| 4 | +const enabledFeaturesStaticObj = enabledFeaturesRaw as Omit<typeof enabledFeaturesRaw, '$schema'> |
| 5 | + |
| 6 | +type Profile = components['schemas']['ProfileResponse'] |
| 7 | + |
| 8 | +export type Feature = Profile['disabled_features'][number] | keyof typeof enabledFeaturesStaticObj |
| 9 | + |
| 10 | +const disabledFeaturesStaticArray = Object.entries(enabledFeaturesStaticObj) |
| 11 | + .filter(([_, value]) => !value) |
| 12 | + .map(([key]) => key as Feature) |
| 13 | + |
| 14 | +function checkFeature(feature: Feature, features: Set<Feature>) { |
| 15 | + return !features.has(feature) |
| 16 | +} |
| 17 | + |
| 18 | +type SnakeToCamelCase<S extends string> = S extends `${infer First}_${infer Rest}` |
| 19 | + ? `${First}${SnakeToCamelCase<Capitalize<Rest>>}` |
| 20 | + : S |
| 21 | + |
| 22 | +type FeatureToCamelCase<S extends Feature> = S extends `${infer P}:${infer R}` |
| 23 | + ? `${SnakeToCamelCase<P>}${Capitalize<SnakeToCamelCase<R>>}` |
| 24 | + : SnakeToCamelCase<S> |
| 25 | + |
| 26 | +function featureToCamelCase(feature: Feature) { |
| 27 | + return feature |
| 28 | + .replace(/:/g, '_') |
| 29 | + .split('_') |
| 30 | + .map((word, index) => (index === 0 ? word : word[0].toUpperCase() + word.slice(1))) |
| 31 | + .join('') as FeatureToCamelCase<typeof feature> |
| 32 | +} |
| 33 | + |
| 34 | +function isFeatureEnabled<T extends Feature[]>( |
| 35 | + features: T, |
| 36 | + runtimeDisabledFeatures?: Feature[] |
| 37 | +): { [key in FeatureToCamelCase<T[number]>]: boolean } |
| 38 | +function isFeatureEnabled(features: Feature, runtimeDisabledFeatures?: Feature[]): boolean |
| 39 | +function isFeatureEnabled<T extends Feature | Feature[]>( |
| 40 | + features: T, |
| 41 | + runtimeDisabledFeatures?: Feature[] |
| 42 | +) { |
| 43 | + const disabledFeatures = new Set([ |
| 44 | + ...(runtimeDisabledFeatures ?? []), |
| 45 | + ...disabledFeaturesStaticArray, |
| 46 | + ]) |
| 47 | + |
| 48 | + if (Array.isArray(features)) { |
| 49 | + return Object.fromEntries( |
| 50 | + features.map((feature) => [ |
| 51 | + featureToCamelCase(feature), |
| 52 | + checkFeature(feature, disabledFeatures), |
| 53 | + ]) |
| 54 | + ) |
| 55 | + } |
| 56 | + |
| 57 | + return checkFeature(features, disabledFeatures) |
| 58 | +} |
| 59 | + |
| 60 | +export { isFeatureEnabled } |
0 commit comments