From a550a9fc2adf06c428191d37bebc919ec38f0e7c Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Thu, 20 Oct 2022 17:52:59 +1300 Subject: [PATCH] Quote (or don't quote) parameter property values individually before joining Instead of adding quotes to the delimiting comma and around the outside, quote the individual members separately if necessary. This prevents the whole string of multiple values being quoted because of the presence of a delimiting comma. When quotes are required (multiValueSeparateDQuote is true) only URIs are valid, which will get quoted due to the colon. When not required only specific strings (WORK, VOICE, PARCEL, etc.) are valid, none of which need quotes. --- lib/ical/design.js | 2 +- lib/ical/stringify.js | 13 +++++-------- test/stringify_test.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/ical/design.js b/lib/ical/design.js index cfd9fbd2..1778df65 100644 --- a/lib/ical/design.js +++ b/lib/ical/design.js @@ -193,7 +193,7 @@ let commonValues = { let icalParams = { // Although the syntax is DQUOTE uri DQUOTE, I don't think we should - // enfoce anything aside from it being a valid content line. + // enforce anything aside from it being a valid content line. // // At least some params require - if multi values are used - DQUOTEs // for each of its values - e.g. delegated-from="uri1","uri2" diff --git a/lib/ical/stringify.js b/lib/ical/stringify.js index 1a542862..ce50f7fe 100644 --- a/lib/ical/stringify.js +++ b/lib/ical/stringify.js @@ -118,18 +118,16 @@ stringify.property = function(property, designSet, noFold) { } let multiValue = (paramName in designSet.param) && designSet.param[paramName].multiValue; if (multiValue && Array.isArray(value)) { - if (designSet.param[paramName].multiValueSeparateDQuote) { - multiValue = '"' + multiValue + '"'; - } value = value.map(stringify._rfc6868Unescape); + value = value.map(stringify.paramPropertyValue); value = stringify.multiValue(value, multiValue, "unknown", null, designSet); } else { value = stringify._rfc6868Unescape(value); + value = stringify.paramPropertyValue(value); } - line += ';' + paramName.toUpperCase(); - line += '=' + stringify.propertyValue(value); + line += ';' + paramName.toUpperCase() + '=' + value; } if (property.length === 3) { @@ -206,12 +204,11 @@ stringify.property = function(property, designSet, noFold) { * If any of the above are present the result is wrapped * in double quotes. * - * @function ICAL.stringify.propertyValue + * @function ICAL.stringify.paramPropertyValue * @param {String} value Raw property value * @return {String} Given or escaped value when needed */ -stringify.propertyValue = function(value) { - +stringify.paramPropertyValue = function(value) { if ((unescapedIndexOf(value, ',') === -1) && (unescapedIndexOf(value, ':') === -1) && (unescapedIndexOf(value, ';') === -1)) { diff --git a/test/stringify_test.js b/test/stringify_test.js index aecfa109..bc375b6f 100644 --- a/test/stringify_test.js +++ b/test/stringify_test.js @@ -173,5 +173,35 @@ suite('ICAL.stringify', function() { assert.equal(ICAL.stringify.component(subject), expected); }); + + test('multiple types unquoted', function() { + let subject = [ + "vcard", + [ + [ + "adr", + { + type: ["dom", "home", "postal", "parcel"] + }, + "text", + ["", "", "123 Main Street", "Any Town", "CA", "91921-1234"] + ], + [ + "tel", + { + type: ["home", "voice", "x-a", "x-b,x-c"] + }, + "phone-number", + "1234567" + ] + ] + ]; + let expected = + "BEGIN:VCARD\r\n" + + "ADR;TYPE=dom,home,postal,parcel:;;123 Main Street;Any Town;CA;91921-1234\r\n" + + "TEL;TYPE=home,voice,x-a,\"x-b,x-c\":1234567\r\n" + + "END:VCARD"; + assert.equal(ICAL.stringify.component(subject), expected); + }); }); });