Hyperlinkv0.8.0-beta.28

SchemaGetter

SchemaGetter.collectBracketPathEntriesfunctioneffect/SchemaGetter.ts:1844
<A>(isLeaf: (value: unknown) => value is A): (
  input: object
) => Array<[bracketPath: string, value: A]>

Flattens a nested object into bracket-path entries, filtering leaf values by a type guard.

When to use

Use when you need a schema getter to serialize structured objects to flat key-value entries.

  • Building custom FormData or URLSearchParams encoders.

Details

  • This is the inverse of makeTreeRecord.
  • Takes a nested object and produces flat [bracketPath, value] pairs suitable for FormData or URLSearchParams.
  • Returns a curried function: first call provides the leaf type guard, second call provides the object.
  • Recursively traverses objects and arrays.
  • If all elements of an array are leaves, encodes them as multiple entries with the same key (e.g. tags=a&tags=b). Otherwise uses indexed bracket paths (e.g. items[0], items[1]).
  • Non-leaf values that aren't objects or arrays are silently skipped.

Example (Flattening an object to bracket paths)

import { Predicate, SchemaGetter } from "effect"

const collectStrings = SchemaGetter.collectBracketPathEntries(Predicate.isString)
const entries = collectStrings({ user: { name: "Alice", tags: ["admin", "editor"] } })
// [["user[name]", "Alice"], ["user[tags]", "admin"], ["user[tags]", "editor"]]
export function collectBracketPathEntries<A>(isLeaf: (value: unknown) => value is A) {
  return (input: object): Array<[bracketPath: string, value: A]> => {
    const bracketPathEntries: Array<[string, A]> = []

    function append(key: string, value: unknown): void {
      if (isLeaf(value)) {
        bracketPathEntries.push([key, value])
      } else if (Array.isArray(value)) {
        // If all values are leaves, encode as multiple entries with the same key
        const allLeaves = value.every(isLeaf)
        if (allLeaves) {
          value.forEach((v) => {
            bracketPathEntries.push([key, v])
          })
        } else {
          value.forEach((v, i) => {
            append(`${key}[${i}]`, v)
          })
        }
      } else if (typeof value === "object" && value !== null) {
        for (const [k, v] of Object.entries(value)) {
          append(`${key}[${k}]`, v)
        }
      }
    }

    for (const [key, value] of Object.entries(input)) {
      append(key, value)
    }

    return bracketPathEntries
  }
}