Skip to content

Commit a2a5952

Browse files
Add parseQueryString utility and tests in JavaScript
Created utils/utils.js with a parseQueryString implementation that handles leading question marks, URI decoding, '+' to space conversion, and multiple values for the same key. Added comprehensive tests in utils/utils.test.js using the built-in node:test and node:assert modules. Co-authored-by: Ruh-Al-Tarikh <203426218+Ruh-Al-Tarikh@users.noreply.github.com>
1 parent 4613f01 commit a2a5952

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

utils/utils.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Parses a URL query string into an object.
3+
* @param {string} query - The query string to parse.
4+
* @returns {Object} - An object containing the parsed key-value pairs.
5+
*/
6+
function parseQueryString(query) {
7+
if (!query) {
8+
return {};
9+
}
10+
11+
// Remove leading '?' if present
12+
if (query.startsWith('?')) {
13+
query = query.substring(1);
14+
}
15+
16+
const params = {};
17+
const pairs = query.split('&');
18+
19+
for (const pair of pairs) {
20+
if (!pair) continue;
21+
22+
const [rawKey, rawValue] = pair.split('=');
23+
24+
// Replace '+' with space and decode URI components
25+
const key = decodeURIComponent(rawKey.replace(/\+/g, ' '));
26+
const value = rawValue !== undefined
27+
? decodeURIComponent(rawValue.replace(/\+/g, ' '))
28+
: '';
29+
30+
if (!key) continue;
31+
32+
if (Object.prototype.hasOwnProperty.call(params, key)) {
33+
if (Array.isArray(params[key])) {
34+
params[key].push(value);
35+
} else {
36+
params[key] = [params[key], value];
37+
}
38+
} else {
39+
params[key] = value;
40+
}
41+
}
42+
43+
return params;
44+
}
45+
46+
module.exports = { parseQueryString };

utils/utils.test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const { test, describe } = require('node:test');
2+
const assert = require('node:assert');
3+
const { parseQueryString } = require('./utils.js');
4+
5+
describe('parseQueryString', () => {
6+
test('parses basic key-value pairs', () => {
7+
const result = parseQueryString('foo=bar&baz=qux');
8+
assert.deepStrictEqual(result, { foo: 'bar', baz: 'qux' });
9+
});
10+
11+
test('handles empty query string', () => {
12+
assert.deepStrictEqual(parseQueryString(''), {});
13+
assert.deepStrictEqual(parseQueryString(null), {});
14+
assert.deepStrictEqual(parseQueryString(undefined), {});
15+
});
16+
17+
test('handles leading question mark', () => {
18+
const result = parseQueryString('?foo=bar&baz=qux');
19+
assert.deepStrictEqual(result, { foo: 'bar', baz: 'qux' });
20+
});
21+
22+
test('decodes URI components', () => {
23+
const result = parseQueryString('foo%20bar=baz%21');
24+
assert.deepStrictEqual(result, { 'foo bar': 'baz!' });
25+
});
26+
27+
test('replaces + with space', () => {
28+
const result = parseQueryString('foo+bar=baz+qux');
29+
assert.deepStrictEqual(result, { 'foo bar': 'baz qux' });
30+
});
31+
32+
test('handles multiple values for the same key', () => {
33+
const result = parseQueryString('foo=bar&foo=baz&foo=qux');
34+
assert.deepStrictEqual(result, { foo: ['bar', 'baz', 'qux'] });
35+
});
36+
37+
test('handles keys without values', () => {
38+
const result = parseQueryString('foo=&bar');
39+
assert.deepStrictEqual(result, { foo: '', bar: '' });
40+
});
41+
42+
test('handles malformed pairs', () => {
43+
const result = parseQueryString('foo=bar&&&baz=qux');
44+
assert.deepStrictEqual(result, { foo: 'bar', baz: 'qux' });
45+
});
46+
47+
test('handles only key', () => {
48+
const result = parseQueryString('foo');
49+
assert.deepStrictEqual(result, { foo: '' });
50+
});
51+
});

0 commit comments

Comments
 (0)