{"version":3,"sources":["../src/create-flags.tsx","../src/backends/abstract-backend.ts","../src/backends/always-backend.ts","../src/backends/static-backend.ts","../src/backends/computed-backend.ts","../src/backends/null-backend.ts"],"sourcesContent":["/// <reference types=\"react/next\" />\n\nimport React from \"react\";\nimport { Flags, FlagScalar, GetValueFromKeyPath, GetValueFromKeyPathString, KeyPath, KeyPathString } from \"./types\";\nimport { Backend } from \"./backends\";\n\nconst MISSING_CONTEXT = Symbol();\nconst NOOP = () => null;\n\nconst isFlagScalar = (value: any): value is FlagScalar => {\n  return typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\";\n};\n\nexport const createFlags = <F extends Flags>() => {\n  type B = Backend<F>;\n\n  type ProviderProps = React.PropsWithChildren<{\n    backend: B;\n  }>;\n\n  type KeyPathStringFlagProps<K extends KeyPathString<F>> = {\n    keyPath: K;\n    defaultValue: GetValueFromKeyPathString<F, K>;\n    render(value: GetValueFromKeyPathString<F, K>): React.ReactNode;\n    fallback?(): React.ReactNode;\n  };\n\n  type KeyPathFlagProps<KP extends KeyPath<F>> = {\n    keyPath: KP;\n    defaultValue: GetValueFromKeyPath<F, KP>;\n    render(value: GetValueFromKeyPath<F, KP>): React.ReactNode;\n    fallback?(): React.ReactNode;\n  };\n\n  const calleeStr = (keyPath: string[], defaultValue: any, format: \"hook\" | \"component\") => () => {\n    const keyPathStr = JSON.stringify(keyPath);\n    const defaultValueStr = JSON.stringify(defaultValue);\n\n    return format == \"hook\"\n      ? `useFlag(${keyPathStr}, ${defaultValueStr})`\n      : `<Flag keyPath=${keyPathStr} defaultValue=${defaultValueStr} ... />`;\n  };\n\n  const Context = React.createContext<B | typeof MISSING_CONTEXT>(MISSING_CONTEXT);\n  Context.displayName = \"Flag\";\n\n  const FlagBackendProvider: React.FC<ProviderProps> = ({ backend, children }) => {\n    return <Context.Provider value={backend}>{children}</Context.Provider>;\n  };\n  FlagBackendProvider.displayName = \"FlagBackendProvider\";\n\n  const internalUseFlag = (keyPath: string | string[], defaultValue: any, displayCallee: () => string) => {\n    const keyPath_ = (Array.isArray(keyPath) ? keyPath : keyPath.split(\".\")) as KeyPath<F>;\n\n    if (defaultValue === undefined) {\n      throw new Error(`Calling \\`${displayCallee()}\\` requires that you provide a default value that matches the type of the flag.`);\n    }\n\n    const expectedType = typeof defaultValue;\n\n    const backend = React.useContext(Context);\n\n    if (backend === MISSING_CONTEXT) {\n      if (process.env.NODE_ENV !== \"development\") {\n        return defaultValue;\n      }\n\n      throw new Error(`Calling \\`${displayCallee()}\\` requires that the application is wrapped in a \\`<FlagBackendProvider />\\``);\n    }\n\n    const ext = backend.toExternalStore(keyPath_, defaultValue);\n    let result = React.useSyncExternalStore(ext.subscribe, ext.getSnapshot, ext.getServerSnapshot);\n\n    if ((result === undefined || result === null) && process.env.NODE_ENV === \"development\") {\n      console.warn(`\\`${displayCallee()}\\` does not return anything from backend \"${backend.name}\".`);\n    }\n\n    result ??= defaultValue;\n\n    if (!isFlagScalar(result)) {\n      throw new Error(\n        `Calling \\`${displayCallee()}\\` requires that the result is a boolean, number or string. Instead returned ${JSON.stringify(\n          result\n        )}.`\n      );\n    }\n\n    if (typeof result !== expectedType) {\n      if (process.env.NODE_ENV === \"development\") {\n        console.warn(\n          `Expected result of \\`${displayCallee()}\\` to be a ${expectedType} (based on the default value of ${JSON.stringify(\n            defaultValue\n          )}). Instead returned ${JSON.stringify(result)}. Falling back to default value.`\n        );\n      }\n\n      return defaultValue;\n    }\n\n    return result;\n  };\n\n  function Flag<K extends KeyPathString<F>>(props: KeyPathStringFlagProps<K>): JSX.Element;\n  function Flag<KP extends KeyPath<F>>(props: KeyPathFlagProps<KP>): JSX.Element;\n  function Flag({ keyPath, defaultValue, render, fallback }: any): JSX.Element {\n    fallback ??= NOOP;\n\n    const flag = internalUseFlag(keyPath, defaultValue, calleeStr(keyPath, defaultValue, \"component\"));\n\n    return flag === false ? fallback() : render(flag);\n  }\n  Flag.displayName = \"Flag\";\n\n  function useFlag<K extends KeyPathString<F>>(keyPath: K, defaultValue: GetValueFromKeyPathString<F, K>): GetValueFromKeyPathString<F, K>;\n  function useFlag<KP extends KeyPath<F>>(keyPath: KP, defaultValue: GetValueFromKeyPath<F, KP>): GetValueFromKeyPath<F, KP>;\n  function useFlag(keyPath: any, defaultValue: any) {\n    React.useDebugValue(keyPath);\n    return internalUseFlag(keyPath, defaultValue, calleeStr(keyPath, defaultValue, \"hook\"));\n  }\n\n  return {\n    FlagBackendProvider,\n    Flag,\n    useFlag,\n  };\n};\n","import { AsyncMutableRefObject, createAsyncRef } from \"async-ref\";\nimport { GetValueFromKeyPath, KeyPath, Subscriber, Unsubscribe, ExternalStore, Notifier } from \"../types\";\nimport { Backend } from \"./types\";\n\nexport abstract class AbstractBackend<F> implements Backend<F> {\n  public abstract getSnapshot<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T;\n\n  public getServerSnapshot<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {\n    return this.getSnapshot(keyPath, defaultValue);\n  }\n\n  public notify: Notifier = () => this.#listeners.forEach((sub) => sub());\n\n  public get name() {\n    return this.constructor.name;\n  }\n\n  public toExternalStore<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): ExternalStore<T> {\n    const subscribe = this.#subscribe;\n    const getSnapshot = () => this.getSnapshot(keyPath, defaultValue);\n    const getServerSnapshot = () => this.getServerSnapshot(keyPath, defaultValue);\n\n    return {\n      subscribe,\n      getSnapshot,\n      getServerSnapshot,\n    };\n  }\n\n  #listeners = new Set<Subscriber>();\n\n  #subscribe = (sub: Subscriber): Unsubscribe => {\n    this.#listeners.add(sub);\n    return () => this.#listeners.delete(sub);\n  };\n\n  protected createAsyncRef<T>(): AsyncMutableRefObject<T> {\n    return createAsyncRef(this.notify);\n  }\n}\n","import { AbstractBackend } from \"./abstract-backend\";\nimport { GetValueFromKeyPath, KeyPath } from \"../types\";\n\ntype AlwaysMapping = {\n  boolean: boolean;\n  string: string;\n  number: number;\n};\n\nexport class AlwaysBackend<F> extends AbstractBackend<F> {\n  #alwaysMapping: Partial<AlwaysMapping>;\n\n  constructor(alwaysMapping: Partial<AlwaysMapping> = {}) {\n    super();\n    this.#alwaysMapping = alwaysMapping;\n  }\n\n  getSnapshot<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {\n    const type = typeof defaultValue;\n\n    if (type !== \"boolean\" && type !== \"string\" && type !== \"number\") {\n      throw new Error(`AlwaysBackend: dafault value must be a boolean, string or number, but got ${type}`);\n    }\n\n    return (this.#alwaysMapping[type] as T) ?? defaultValue;\n  }\n}\n","import { AbstractBackend } from \"./abstract-backend\";\nimport { GetValueFromKeyPath, KeyPath } from \"../types\";\n\nexport class StaticBackend<F> extends AbstractBackend<F> {\n  #data: Partial<F>;\n\n  constructor(data: Partial<F>) {\n    super();\n    this.#data = data;\n  }\n\n  getSnapshot<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {\n    if (keyPath.length === 0) {\n      return defaultValue;\n    }\n\n    let result: any = this.#data;\n\n    for (const key of keyPath as string[]) {\n      result = result[key];\n\n      if (result === undefined) {\n        return defaultValue;\n      }\n    }\n\n    return result;\n  }\n}\n","import { StaticBackend } from \"./static-backend\";\n\ntype RecursiveComputable<T, Root> = {\n  [K in keyof T]: T[K] extends object ? RecursiveComputable<T[K], Root> : T[K] | ((arg: Root) => T[K]);\n};\n\ntype Computable<T> = RecursiveComputable<T, T>;\n\nconst makeComputable = <T, Root>(data: Computable<T>, getRoot: () => Root): T => {\n  if (typeof data !== \"object\") {\n    return data;\n  }\n\n  return new Proxy(data, {\n    get: (target: Computable<T>, key_: string) => {\n      const key = key_ as keyof Computable<T>;\n      const next = target[key];\n\n      if (typeof next === \"function\") {\n        const root = getRoot();\n        return makeComputable(next(root), getRoot);\n      }\n\n      return makeComputable(next, getRoot);\n    },\n  }) as T;\n};\n\nexport class ComputedBackend<F> extends StaticBackend<F> {\n  constructor(data: Computable<F>) {\n    const computable: F = makeComputable(data, () => computable);\n    super(computable);\n  }\n}\n","import { AbstractBackend } from \"./abstract-backend\";\nimport { GetValueFromKeyPath, KeyPath } from \"../types\";\n\nexport class NullBackend<F> extends AbstractBackend<F> {\n  getSnapshot<KP extends KeyPath<F>, T extends GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {\n    return defaultValue;\n  }\n}\n"],"mappings":"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","names":[]}