Parse and build URL query strings

JavaScript
// Convert between query strings and plain objects, preserving repeated keys.
function parseQuery(input) {
  const params = input instanceof URL ? input.searchParams : new URLSearchParams(input);
  const result = Object.create(null); // no prototype, so any key is safe
  for (const [key, value] of params) {
    result[key] = key in result ? [].concat(result[key], value) : value;
  }
  return result;
}

function buildQuery(values) {
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(values)) {
    for (const item of [].concat(value)) {
      if (item !== undefined && item !== null) params.append(key, String(item));
    }
  }
  return params.toString();
}

const query = parseQuery('?tag=js&tag=web&q=hello+world');
console.log(JSON.stringify(query)); // {"tag":["js","web"],"q":"hello world"}
console.log(buildQuery({ tag: ['js', 'web'], q: 'hello world' }));
// tag=js&tag=web&q=hello+world