<A>(
bracketPathEntries: ReadonlyArray<
readonly [bracketPath: string, value: A]
>
): Schema.TreeRecord<A>Builds a nested tree object from a list of bracket-path entries.
When to use
Use when you need a schema getter to parse FormData or URLSearchParams entries into structured objects.
- You have flat key-value pairs with bracket-path keys that need nesting.
Details
- A bracket path is a string like
"user[address][city]"that describes nested object/array structure. - Interprets bracket paths and constructs the corresponding nested object.
- Builds and returns a nested object from the input entries.
- Supported syntax:
"foo"→ object key"foo""foo[bar]"→ nested{ foo: { bar: ... } }"foo[0]"→ array index{ foo: [value] }"foo[]"→ append to arrayfoo""→ real empty key
- Duplicate keys for the same path are merged into arrays.
Example (Building a tree from bracket paths)
import { SchemaGetter } from "effect"
const tree = SchemaGetter.makeTreeRecord([
["user[name]", "Alice"],
["user[tags][]", "admin"],
["user[tags][]", "editor"]
])
// { user: { name: "Alice", tags: ["admin", "editor"] } }export function function makeTreeRecord<A>(
bracketPathEntries: ReadonlyArray<
readonly [bracketPath: string, value: A]
>
): Schema.TreeRecord<A>
Builds a nested tree object from a list of bracket-path entries.
When to use
Use when you need a schema getter to parse FormData or URLSearchParams
entries into structured objects.
- You have flat key-value pairs with bracket-path keys that need nesting.
Details
- A bracket path is a string like
"user[address][city]" that describes nested
object/array structure.
- Interprets bracket paths and constructs the corresponding nested object.
- Builds and returns a nested object from the input entries.
- Supported syntax:
"foo" → object key "foo"
"foo[bar]" → nested { foo: { bar: ... } }
"foo[0]" → array index { foo: [value] }
"foo[]" → append to array foo
"" → real empty key
- Duplicate keys for the same path are merged into arrays.
Example (Building a tree from bracket paths)
import { SchemaGetter } from "effect"
const tree = SchemaGetter.makeTreeRecord([
["user[name]", "Alice"],
["user[tags][]", "admin"],
["user[tags][]", "editor"]
])
// { user: { name: "Alice", tags: ["admin", "editor"] } }
makeTreeRecord<function (type parameter) A in makeTreeRecord<A>(bracketPathEntries: ReadonlyArray<readonly [bracketPath: string, value: A]>): Schema.TreeRecord<A>A>(
bracketPathEntries: readonly (readonly [
bracketPath: string,
value: A
])[]
bracketPathEntries: interface ReadonlyArray<T>ReadonlyArray<readonly [stringbracketPath: string, Avalue: function (type parameter) A in makeTreeRecord<A>(bracketPathEntries: ReadonlyArray<readonly [bracketPath: string, value: A]>): Schema.TreeRecord<A>A]>
): import SchemaSchema.type Schema.TreeRecord = /*unresolved*/ anyTreeRecord<function (type parameter) A in makeTreeRecord<A>(bracketPathEntries: ReadonlyArray<readonly [bracketPath: string, value: A]>): Schema.TreeRecord<A>A> {
const const out: anyout: any = {}
bracketPathEntries: readonly (readonly [
bracketPath: string,
value: A
])[]
bracketPathEntries.ReadonlyArray<readonly [bracketPath: string, value: A]>.forEach(callbackfn: (value: readonly [bracketPath: string, value: A], index: number, array: readonly (readonly [bracketPath: string, value: A])[]) => void, thisArg?: any): voidPerforms the specified action for each element in an array.
forEach(([key: stringkey, value: Avalue]) => {
const const tokens: (string | number)[]tokens = function bracketPathToTokens(
bracketPath: string
): Array<string | number>
bracketPathToTokens(key: stringkey)
let let cur: anycur: any = const out: anyout
const tokens: (string | number)[]tokens.Array<string | number>.forEach(callbackfn: (value: string | number, index: number, array: (string | number)[]) => void, thisArg?: any): voidPerforms the specified action for each element in an array.
forEach((token: string | numbertoken, i: numberi) => {
const const isLast: booleanisLast = i: numberi === const tokens: (string | number)[]tokens.Array<string | number>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length - 1
// We are inside an array and see "[]" (empty token) => append
if (var Array: ArrayConstructorArray.ArrayConstructor.isArray(arg: any): arg is any[]isArray(let cur: anycur) && token: string | numbertoken === "") {
if (const isLast: booleanisLast) {
let cur: any[]cur.Array<any>.push(...items: any[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push(value: Avalue)
} else {
// bracket path: "foo[][bar]" => push a new element and descend into it
const const next: string | numbernext = const tokens: (string | number)[]tokens[i: numberi + 1]
const const shouldBeArray: booleanshouldBeArray = typeof const next: string | numbernext === "number" || const next: stringnext === ""
const const index: numberindex = let cur: any[]cur.Array<T>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length
let cur: anycur = function getOrCreateContainer(
self: any,
key: PropertyKey,
shouldBeArray: boolean
): any
getOrCreateContainer(let cur: any[]cur, const index: numberindex, const shouldBeArray: booleanshouldBeArray)
}
} else if (const isLast: booleanisLast) {
// If we're setting a value at a path that already exists
// convert it to an array to support multiple values for the same key
const const hasOwn: booleanhasOwn = var Object: ObjectConstructorProvides functionality common to all JavaScript objects.
Object.ObjectConstructor.hasOwn(o: object, v: PropertyKey): booleanDetermines whether an object has a property with the specified name.
hasOwn(let cur: anycur, token: string | numbertoken)
if (const hasOwn: booleanhasOwn && var Array: ArrayConstructorArray.ArrayConstructor.isArray(arg: any): arg is any[]isArray(let cur: anycur[token: string | numbertoken])) {
let cur: anycur[token: string | numbertoken].Array<any>.push(...items: any[]): numberAppends new elements to the end of an array, and returns the new length of the array.
push(value: Avalue)
} else if (const hasOwn: booleanhasOwn) {
import internalRecordinternalRecord.function set<string | number, any[]>(self: Record<string | number, any[]>, key: string | number, value: any[]): Record<string | number, any[]>set(let cur: anycur, token: string | numbertoken, [let cur: anycur[token: string | numbertoken], value: Avalue])
} else {
import internalRecordinternalRecord.function set<string | number, A>(self: Record<string | number, A>, key: string | number, value: A): Record<string | number, A>set(let cur: anycur, token: string | numbertoken, value: Avalue)
}
} else {
const const next: string | numbernext = const tokens: (string | number)[]tokens[i: numberi + 1]
// if next is a number OR "" (from []), we are building an array
const const shouldBeArray: booleanshouldBeArray = typeof const next: string | numbernext === "number" || const next: stringnext === ""
let cur: anycur = function getOrCreateContainer(
self: any,
key: PropertyKey,
shouldBeArray: boolean
): any
getOrCreateContainer(let cur: anycur, token: string | numbertoken, const shouldBeArray: booleanshouldBeArray)
}
})
})
return const out: anyout
}