From b95257371d0ebb166d3a147a771ad9aecba0fbb8 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 6 Aug 2020 10:03:44 +0200 Subject: [PATCH] fix(query): remove undefined values Close #3276 --- src/util/query.js | 68 +++++++++++++++++++---------------- test/unit/specs/query.spec.js | 11 ++++++ 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/util/query.js b/src/util/query.js index b2c5286a5..c017f2b5d 100644 --- a/src/util/query.js +++ b/src/util/query.js @@ -9,9 +9,10 @@ const commaRE = /%2C/g // fixed encodeURIComponent which is more conformant to RFC3986: // - escapes [!'()*] // - preserve commas -const encode = str => encodeURIComponent(str) - .replace(encodeReserveRE, encodeReserveReplacer) - .replace(commaRE, ',') +const encode = str => + encodeURIComponent(str) + .replace(encodeReserveRE, encodeReserveReplacer) + .replace(commaRE, ',') const decode = decodeURIComponent @@ -30,11 +31,15 @@ export function resolveQuery ( } for (const key in extraQuery) { const value = extraQuery[key] - parsedQuery[key] = Array.isArray(value) ? value.map(v => '' + v) : '' + value + parsedQuery[key] = Array.isArray(value) + ? value.map(castQueryParamValue) + : castQueryParamValue(value) } return parsedQuery } +const castQueryParamValue = value => (value == null ? value : '' + value) + function parseQuery (query: string): Dictionary { const res = {} @@ -47,9 +52,7 @@ function parseQuery (query: string): Dictionary { query.split('&').forEach(param => { const parts = param.replace(/\+/g, ' ').split('=') const key = decode(parts.shift()) - const val = parts.length > 0 - ? decode(parts.join('=')) - : null + const val = parts.length > 0 ? decode(parts.join('=')) : null if (res[key] === undefined) { res[key] = val @@ -64,33 +67,38 @@ function parseQuery (query: string): Dictionary { } export function stringifyQuery (obj: Dictionary): string { - const res = obj ? Object.keys(obj).map(key => { - const val = obj[key] - - if (val === undefined) { - return '' - } + const res = obj + ? Object.keys(obj) + .map(key => { + const val = obj[key] - if (val === null) { - return encode(key) - } + if (val === undefined) { + return '' + } - if (Array.isArray(val)) { - const result = [] - val.forEach(val2 => { - if (val2 === undefined) { - return + if (val === null) { + return encode(key) } - if (val2 === null) { - result.push(encode(key)) - } else { - result.push(encode(key) + '=' + encode(val2)) + + if (Array.isArray(val)) { + const result = [] + val.forEach(val2 => { + if (val2 === undefined) { + return + } + if (val2 === null) { + result.push(encode(key)) + } else { + result.push(encode(key) + '=' + encode(val2)) + } + }) + return result.join('&') } - }) - return result.join('&') - } - return encode(key) + '=' + encode(val) - }).filter(x => x.length > 0).join('&') : null + return encode(key) + '=' + encode(val) + }) + .filter(x => x.length > 0) + .join('&') + : null return res ? `?${res}` : '' } diff --git a/test/unit/specs/query.spec.js b/test/unit/specs/query.spec.js index 58060ff2c..9c73debe4 100644 --- a/test/unit/specs/query.spec.js +++ b/test/unit/specs/query.spec.js @@ -20,10 +20,21 @@ describe('Query utils', () => { }) }) + it('should keep undefined and null query values', () => { + const query = resolveQuery('', { a: undefined, b: null }) + expect(query).toEqual({ a: undefined, b: null }) + }) + + it('should keep null query values in arrays', () => { + const query = resolveQuery('', { baz: [null, '2'] }) + expect(query).toEqual({ baz: [null, '2'] }) + }) + it('should cast query values into string', () => { const query = resolveQuery('foo=bar&foo=k', { baz: 1 }) expect(query.baz).toBe('1') }) + it('should cast query array values into string', () => { const query = resolveQuery('foo=bar&foo=k', { baz: [1, '2'] }) expect(query.baz).toEqual(['1', '2'])