iterable-to-json
v0.2.0
Published
Convert any iterable with dot notation keys into a deeply-nested JSON value.
Maintainers
Readme
Iterable to JSON
Convert any key/value iterable into a deeply-nested JSON value.
Why?
Many modern web APIs use iterables of [key, value] pairs:
new FormData(request)new URLSearchParams(location.search)Object.entries(obj)/new Map(entries)
Yet once you have those pairs, turning them into the structured object you actually need is surprisingly fiddly:
- Keys may describe deeply-nested objects (
user.address.city) - They often mix arrays and objects (
items[3].price) - There can be multiple values for the same key (
tags=js&tags=ts) - Sparse indices (
array[8]=foo) must be preserved
iterable-to-json does all of that in one tiny function. Give it any
key/value iterable and get back JSON.
Installation
npm install iterable-to-json
# or
pnpm add iterable-to-json
# or
yarn add iterable-to-jsonQuick start
import { iterableToJson } from 'iterable-to-json';
const formData = new FormData();
formData.append('user.name', 'Ada');
formData.append('user.hobbies[0]', 'Computation');
formData.append('user.hobbies[1]', 'Flying');
formData.append('flags', 'true'); // multiple entries…
formData.append('flags', 'false'); // …become arrays
const json = iterableToJson(formData);
console.log(json);
/*
{
user: {
name: 'Ada',
hobbies: ['Computation', 'Flying']
},
flags: ['true', 'false']
}
*/Key syntax
| Pattern | Produces |
| --------------------------------------- | --------------------------------------- |
| user.name = "Ada" | { user: { name: "Ada" } } |
| items[0] = "foo" / items[1] = "bar" | { items: ["foo", "bar"] } |
| matrix[2][4] = "x" | { matrix: [ , , [ , , , , "x" ] ] } |
| meta[0].key.value = "v" (mixed) | { meta: [ { key: { value: "v" } } ] } |
| [0].key = "value" (top-level array) | [ { key: "value" } ] |
| Duplicate keys (tags=js&tags=ts) | { tags: ["js", "ts"] } |
- Dot notation (
.) → object keys - Bracket notation (
[index]) → array indices - Numeric keys without brackets (e.g.
obj.0) are treated as object keys, not arrays — mirroring JSON semantics. - Missing indices create
undefined"holes" so sparse arrays keep their correct positions.
Decoding rules
iterableToJson only operates on the keys of the iterable. Values are
left exactly as received.
Example
import { iterableToJson } from 'iterable-to-json';
const params = new URLSearchParams('active=true');
const raw = iterableToJson(params);
/*
raw === {
active: 'true' // still a string
}
*/You should almost always validate data received from FormData or
URLSearchParams. As such, you should rely on a validation library such as
Valibot or Zod to coerce values if
needed.
Example coercion with Valibot
import { v } from 'valibot';
const schema = v.object({
active: v.union([
v.boolean(), // accept booleans
v.pipe(
v.union([v.literal('true'), v.literal('false')]),
v.transform((value) => value === 'true'),
), // accept strings and coerce to booleans
]),
});
const typed = v.parse(schema, raw); // { active: true }Example coercion with plain JavaScript
const coerced = { active: raw.active === 'true' };API
function iterableToJson<T = unknown>(
iterable: Iterable<[string, T]>,
): DecodedValue<T>;DecodedValue<T>
A distributive conditional type that maps the decoded structure to the union of
possible leaf values T. For most apps you can ignore it – IntelliSense
will "just know".
Supported environments
Works everywhere (that you can use a for...of loop).
Feedback
Please open an issue if you find a bug or have a feature request.
