From a970b95dac078baf0cc932f61125b4e8a97ff909 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Tue, 23 Jun 2026 01:37:48 +0100 Subject: [PATCH] fix: do not expand empty list or associative array under key operators RFC 6570 section 2.3 defines a list or associative array with zero members as undefined, so an undefined value contributes nothing to an expansion. The key operators (?, &, ;) emitted a "name=" pair for an empty collection anyway: parseTemplate('{?list}').expand({ list: [] }); // was "?list=", now "" The non-key branch already guarded on `tmp.length`; the key branch did not. Guard both. An empty string value stays defined and still expands to "name=", matching RFC 6570 section 3.2.8. The official RFC 6570 test suite's "Empty Variables" cases now pass; two unit-test assertions that encoded the old behavior are corrected. --- lib/url-template.js | 10 ++++++---- test/url-template-test.js | 14 ++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/url-template.js b/lib/url-template.js index 92c234b..e7405f8 100644 --- a/lib/url-template.js +++ b/lib/url-template.js @@ -73,10 +73,12 @@ function getValues(context, operator, key, modifier) { }); } - if (isKeyOperator(operator)) { - result.push(encodeUnreserved(key) + '=' + tmp.join(',')); - } else if (tmp.length !== 0) { - result.push(tmp.join(',')); + if (tmp.length !== 0) { + if (isKeyOperator(operator)) { + result.push(encodeUnreserved(key) + '=' + tmp.join(',')); + } else { + result.push(tmp.join(',')); + } } } } diff --git a/test/url-template-test.js b/test/url-template-test.js index 2df84d2..e1367b9 100644 --- a/test/url-template-test.js +++ b/test/url-template-test.js @@ -179,15 +179,21 @@ describe('uri-template', () => { test('variable empty list', () => { assert('{/emptylist}', ''); assert('{/emptylist*}', ''); - assert('{?emptylist}', '?emptylist='); + // RFC 6570 section 2.3: a list with zero members is undefined, so a key + // operator must not emit a "name=" pair for it (unlike an empty string). + assert('{?emptylist}', ''); assert('{?emptylist*}', ''); + assert('{&emptylist}', ''); + assert('{;emptylist}', ''); }); test('variable empty object', () => { assert('{/emptyobject}', ''); assert('{/emptyobject*}', ''); - assert('{?emptyobject}', '?emptyobject='); + assert('{?emptyobject}', ''); assert('{?emptyobject*}', ''); + assert('{&emptyobject}', ''); + assert('{;emptyobject}', ''); }); test('variable undefined list item', () => { @@ -362,8 +368,8 @@ describe('uri-template', () => { assert('{?var,number}', '?var=value&number=2133'); assert('{?undef}', ''); assert('{?emptystring}', '?emptystring='); - assert('{?emptylist}', '?emptylist='); - assert('{?emptyobject}', '?emptyobject='); + assert('{?emptylist}', ''); + assert('{?emptyobject}', ''); assert('{?undef,var,emptystring}', '?var=value&emptystring='); }); });