ProvenPin Install

qs nested query strings: working versions (tested 2026-10-15)

Parse and stringify nested query strings with qs, covering nested objects, bracket/index/repeat/comma array formats, depth limits and a typed filter parser offline.

passed8 passed · 0 failed2026-10-15 22:58 UTC
Status
passed
Last passed
2026-10-15 22:58 UTC
Tests
8 / 8
Language
TypeScript
Runtime
node v22.23.3
pinned versions4
qs@6.16.1@types/qs@6.15.1@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38820570375

The code

Exactly the files that passed. Your agent can pull them with get_recipe("qs-nested-query-strings") (install), or see them on GitHub.

package.json
{
  "name": "qs-nested-query-strings",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {"qs":"6.16.1"},
  "devDependencies": {"@types/qs":"6.15.1","@types/node":"26.6.5","tsx":"4.23.15"}
}
src/query.ts
import { parse, stringify, type IParseOptions, type ParsedQs, type IStringifyOptions } from "qs";

export const DEFAULT_DEPTH = 5;

export function parseNested(input: string, options: IParseOptions = {}): ParsedQs {
  return parse(input, { depth: DEFAULT_DEPTH, ...options }) as ParsedQs;
}

export function stringifyNested(value: Record<string, unknown>, options: IStringifyOptions = {}): string {
  return stringify(value, { depth: DEFAULT_DEPTH, ...options });
}

export type Filter = {
  q?: string;
  tags: string[];
  price?: { min?: number; max?: number };
  inStock?: boolean;
};

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function toNumber(value: unknown): number | undefined {
  if (typeof value === "string" && value.trim() !== "") {
    const parsed = Number(value);
    if (Number.isFinite(parsed)) return parsed;
  }
  return undefined;
}

export function parseFilter(input: string): Filter {
  const raw = parse(input, { depth: DEFAULT_DEPTH });
  const filter: Filter = { tags: [] };

  if (typeof raw.q === "string") filter.q = raw.q;

  const tags = raw.tags;
  if (typeof tags === "string") {
    filter.tags = [tags];
  } else if (Array.isArray(tags)) {
    filter.tags = tags.filter((tag): tag is string => typeof tag === "string");
  }

  const price = raw.price;
  if (isRecord(price)) {
    const min = toNumber(price.min);
    const max = toNumber(price.max);
    if (min !== undefined || max !== undefined) {
      filter.price = {};
      if (min !== undefined) filter.price.min = min;
      if (max !== undefined) filter.price.max = max;
    }
  }

  const inStock = raw.inStock;
  if (inStock === "true" || inStock === "1") {
    filter.inStock = true;
  } else if (inStock === "false" || inStock === "0") {
    filter.inStock = false;
  }

  return filter;
}

export function toQuery(filter: Filter, options: IStringifyOptions = {}): string {
  const payload: Record<string, unknown> = {};
  if (filter.q !== undefined) payload.q = filter.q;
  if (filter.tags.length > 0) payload.tags = filter.tags;
  if (filter.price !== undefined) payload.price = filter.price;
  if (filter.inStock !== undefined) payload.inStock = filter.inStock ? "true" : "false";
  return stringify(payload, { skipNulls: true, ...options });
}
test/query.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseNested, stringifyNested, parseFilter, toQuery } from "../src/query.ts";

test("parses nested objects and indexed arrays", () => {
  const parsed = parseNested("user[name]=ada&user[roles][0]=admin&user[roles][1]=dev");
  assert.deepEqual(parsed, { user: { name: "ada", roles: ["admin", "dev"] } });
});

test("parses bracket and repeat array formats", () => {
  assert.deepEqual(parseNested("tags[]=a&tags[]=b"), { tags: ["a", "b"] });
  assert.deepEqual(parseNested("tags=a&tags=b"), { tags: ["a", "b"] });
});

test("parses comma separated arrays", () => {
  assert.deepEqual(parseNested("tags=a,b,c", { comma: true }), { tags: ["a", "b", "c"] });
});

test("stringifies arrays in each format", () => {
  const value = { tags: ["a", "b"] };
  assert.equal(stringifyNested(value, { arrayFormat: "indices", encode: false }), "tags[0]=a&tags[1]=b");
  assert.equal(stringifyNested(value, { arrayFormat: "brackets", encode: false }), "tags[]=a&tags[]=b");
  assert.equal(stringifyNested(value, { arrayFormat: "repeat", encode: false }), "tags=a&tags=b");
  assert.equal(stringifyNested(value, { arrayFormat: "comma", encode: false }), "tags=a,b");
});

test("enforces the depth limit while parsing", () => {
  assert.deepEqual(parseNested("a[b][c][d][e][f][g][h][i]=j", { depth: 1 }), {
    a: { b: { "[c][d][e][f][g][h][i]": "j" } },
  });
});

test("parses a typed filter", () => {
  const filter = parseFilter("q=phone&tags[]=mobile&tags[]=sale&price[min]=10&price[max]=99&inStock=true");
  assert.deepEqual(filter, {
    q: "phone",
    tags: ["mobile", "sale"],
    price: { min: 10, max: 99 },
    inStock: true,
  });
});

test("ignores non numeric and non boolean values", () => {
  assert.deepEqual(parseFilter("price[min]=cheap&inStock=maybe"), { tags: [] });
});

test("round-trips a filter through toQuery and parseFilter", () => {
  const filter = { q: "phone", tags: ["sale", "mobile"], price: { min: 10 }, inStock: false };
  const query = toQuery(filter, { encode: false });
  assert.equal(query, "q=phone&tags[0]=sale&tags[1]=mobile&price[min]=10&inStock=false");
  assert.deepEqual(parseFilter(query), filter);
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.