Skip to content

Commit da59e1b

Browse files
author
Ankit Saini
authored
Merge pull request #464 from postmanlabs/release/1.1.3
Release/1.1.3
2 parents 31dc9f6 + bc121e9 commit da59e1b

File tree

31 files changed

+345
-81
lines changed

31 files changed

+345
-81
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
v1.1.3 (Mar 1, 2020)
2+
* Use proper indentation for JSON bodies in Javascript and Nodejs codegens
3+
* Fix for - [445](https://github.com/postmanlabs/postman-code-generators/issues/445) Add proper indentation in nodejs-axios when bodytype is urlencoded
4+
* Fix for - [248](https://github.com/postmanlabs/postman-code-generators/issues/248) Use quoteType everywhere in curl, not just in the url
5+
* Fix for - [454](https://github.com/postmanlabs/postman-code-generators/issues/454) Fix encoding when generating HTTP code snippets
6+
* Fix for - [426](https://github.com/postmanlabs/postman-code-generators/issues/426) Use json.dumps in Python codegens if Content-Type is JSON
7+
18
v1.1.2 (Dec 15, 2020)
29
* Fix for - [8736](https://github.com/postmanlabs/postman-app-support/issues/8736) Add content type support for individual form-data fields
310
* Fix for - [8635](https://github.com/postmanlabs/postman-app-support/issues/8635) Use Json.parse for all json like application types

codegens/curl/lib/index.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ self = module.exports = {
2323
format = options.longFormat;
2424
trim = options.trimRequestBody;
2525
silent = options.silent;
26-
url = getUrlStringfromUrlObject(request.url);
2726
quoteType = options.quoteType === 'single' ? '\'' : '"';
27+
url = getUrlStringfromUrlObject(request.url, quoteType);
2828

2929
snippet = silent ? `curl ${form('-s', format)}` : 'curl';
3030

@@ -72,14 +72,14 @@ self = module.exports = {
7272
if (!header.key) {
7373
return;
7474
}
75-
snippet += indent + `${form('-H', format)} '${sanitize(header.key, true)}`;
75+
snippet += indent + `${form('-H', format)} ${quoteType}${sanitize(header.key, true, quoteType)}`;
7676
// If the header value is an empty string then add a semicolon after key
7777
// otherwise the header would be ignored by curl
7878
if (header.value) {
79-
snippet += `: ${sanitize(header.value)}'`;
79+
snippet += `: ${sanitize(header.value, false, quoteType)}${quoteType}`;
8080
}
8181
else {
82-
snippet += ';\'';
82+
snippet += ';' + quoteType;
8383
}
8484
});
8585
}
@@ -130,12 +130,13 @@ self = module.exports = {
130130
// Using the long form below without considering the longFormat option,
131131
// to generate more accurate and correct snippet
132132
snippet += indent + '--data-urlencode';
133-
snippet += ` '${sanitize(data.key, trim)}=${sanitize(data.value, trim)}'`;
133+
snippet += ` ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
134+
`${sanitize(data.value, trim, quoteType)}${quoteType}`;
134135
}
135136
});
136137
break;
137138
case 'raw':
138-
snippet += indent + `--data-raw '${sanitize(body.raw.toString(), trim)}'`;
139+
snippet += indent + `--data-raw ${quoteType}${sanitize(body.raw.toString(), trim, quoteType)}${quoteType}`;
139140
break;
140141
case 'graphql':
141142
// eslint-disable-next-line no-case-declarations
@@ -147,35 +148,38 @@ self = module.exports = {
147148
catch (e) {
148149
graphqlVariables = {};
149150
}
150-
snippet += indent + `--data-raw '${sanitize(JSON.stringify({
151+
snippet += indent + `--data-raw ${quoteType}${sanitize(JSON.stringify({
151152
query: query,
152153
variables: graphqlVariables
153-
}), trim)}'`;
154+
}), trim, quoteType)}${quoteType}`;
154155
break;
155156
case 'formdata':
156157
_.forEach(body.formdata, function (data) {
157158
if (!(data.disabled)) {
158159
if (data.type === 'file') {
159160
snippet += indent + `${form('-F', format)}`;
160-
snippet += ` '${sanitize(data.key, trim)}=@"${sanitize(data.src, trim, true, true)}"'`;
161+
snippet += ` ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
162+
`${sanitize(`@"${sanitize(data.src, trim, '"', true)}"`, trim, quoteType, quoteType === '"')}`;
163+
snippet += quoteType;
161164
}
162165
else {
163166
snippet += indent + `${form('-F', format)}`;
164-
snippet += ` '${sanitize(data.key, trim)}="${sanitize(data.value, trim, true, true)}"`;
167+
snippet += ` ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
168+
sanitize(`"${sanitize(data.value, trim, '"', true)}"`, trim, quoteType, quoteType === '"');
165169
if (data.contentType) {
166170
snippet += `;type=${data.contentType}`;
167171
}
168-
snippet += '\'';
172+
snippet += quoteType;
169173
}
170174
}
171175
});
172176
break;
173177
case 'file':
174178
snippet += indent + '--data-binary';
175-
snippet += ` '@${sanitize(body[body.mode].src, trim)}'`;
179+
snippet += ` ${quoteType}@${sanitize(body[body.mode].src, trim)}${quoteType}`;
176180
break;
177181
default:
178-
snippet += `${form('-d', format)} ''`;
182+
snippet += `${form('-d', format)} ${quoteType}${quoteType}`;
179183
}
180184
}
181185
}

codegens/curl/lib/util.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ var self = module.exports = {
55
*
66
* @param {String} inputString
77
* @param {Boolean} [trim] - indicates whether to trim string or not
8-
* @param {Boolean} [doubleQuotes] - indicates whether to escape double quotes(") and backslash(\\)
8+
* @param {Boolean} [quoteType] - indicates which quoteType has to be escaped
99
* @param {Boolean} [backSlash] - indicates whether to escape backslash(\\)
1010
* @returns {String}
1111
*/
12-
sanitize: function (inputString, trim, doubleQuotes, backSlash) {
12+
sanitize: function (inputString, trim, quoteType, backSlash) {
1313
if (typeof inputString !== 'string') {
1414
return '';
1515
}
@@ -18,12 +18,14 @@ var self = module.exports = {
1818
inputString = inputString.replace(/\\/g, '\\\\');
1919
}
2020

21-
if (doubleQuotes) {
21+
if (quoteType === '"') {
2222
inputString = inputString.replace(/"/g, '\\"');
2323
}
24+
else if (quoteType === '\'') {
25+
// for curl escaping of single quotes inside single quotes involves changing of ' to '\''
26+
inputString = inputString.replace(/'/g, "'\\''"); // eslint-disable-line quotes
27+
}
2428

25-
// for curl escaping of single quotes inside single quotes involves changing of ' to '\''
26-
inputString = inputString.replace(/'/g, "'\\''"); // eslint-disable-line quotes
2729
return trim ? inputString.trim() : inputString;
2830
},
2931

@@ -126,12 +128,13 @@ var self = module.exports = {
126128
/**
127129
*
128130
* @param {*} urlObject The request sdk request.url object
131+
* @param {boolean} quoteType The user given quoteType
129132
* @returns {String} The final string after parsing all the parameters of the url including
130133
* protocol, auth, host, port, path, query, hash
131134
* This will be used because the url.toString() method returned the URL with non encoded query string
132135
* and hence a manual call is made to getQueryString() method with encode option set as true.
133136
*/
134-
getUrlStringfromUrlObject: function (urlObject) {
137+
getUrlStringfromUrlObject: function (urlObject, quoteType) {
135138
var url = '';
136139
if (!urlObject) {
137140
return url;
@@ -161,7 +164,7 @@ var self = module.exports = {
161164
url += '#' + urlObject.hash;
162165
}
163166

164-
return self.sanitize(url);
167+
return self.sanitize(url, false, quoteType);
165168
},
166169

167170
/**

codegens/curl/test/unit/convert.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,39 @@ describe('curl convert function', function () {
466466
});
467467
});
468468

469+
it('should generate valid snippets when quoteType is "double"', function () {
470+
// url = https://a"b'c.com/'d/"e
471+
var request = new sdk.Request({
472+
'method': 'POST',
473+
'body': {
474+
'mode': 'formdata',
475+
'formdata': [
476+
{
477+
'key': 'json',
478+
'value': '{"hello": "world"}',
479+
'contentType': 'application/json',
480+
'type': 'text'
481+
}
482+
]
483+
},
484+
'url': {
485+
'raw': "https://a\"b'c.com/'d/\"e", // eslint-disable-line quotes
486+
'host': [
487+
'a"b\'c',
488+
'com'
489+
]
490+
}
491+
});
492+
convert(request, {quoteType: 'double'}, function (error, snippet) {
493+
if (error) {
494+
expect.fail(null, null, error);
495+
}
496+
497+
expect(snippet).to.include('"a\\"b\'c.com"');
498+
expect(snippet).to.include('"json=\\"{\\\\\\"hello\\\\\\": \\\\\\"world\\\\\\"}\\";type=application/json"');
499+
});
500+
});
501+
469502
describe('getUrlStringfromUrlObject function', function () {
470503
var rawUrl, urlObject, outputUrlString;
471504

codegens/http/lib/util.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,30 @@ function convertPropertyListToString (propertyList, joinUsing, includeDisabled =
117117
}), joinUsing);
118118
}
119119

120+
/**
121+
* Url encodes the members of the property list.
122+
*
123+
* @param {Object} propertyList propertyList
124+
* @param {String} joinUsing specify string that should be used to join the list of properties
125+
* @param {Boolean} includeDisabled indicated whether or not to include disabled properties
126+
* @param {Boolean} trimRequestBody indicates whether or not to trim request body
127+
* @returns {String} Stringified and Url encoded property List
128+
*/
129+
function convertPropListToStringUrlEncoded (propertyList, joinUsing, includeDisabled = false, trimRequestBody = false) {
130+
const properties = getMembersOfPropertyList(propertyList, includeDisabled),
131+
keyvalues = [];
132+
133+
properties.forEach((property) => {
134+
const key = trimRequestBody ? property.key.trim() : property.key,
135+
value = trimRequestBody ? property.value.trim() : property.value,
136+
keyvalue = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
137+
138+
keyvalues.push(keyvalue);
139+
});
140+
141+
return keyvalues.join(joinUsing);
142+
}
143+
120144

121145
/**
122146
* Returns the request headers as a string
@@ -181,7 +205,8 @@ function getBody (request, trimRequestBody) {
181205
case URL_ENCODED:
182206
/* istanbul ignore else */
183207
if (!_.isEmpty(request.body[request.body.mode])) {
184-
requestBody += convertPropertyListToString(request.body[request.body.mode], '&', false, trimRequestBody);
208+
const propertyList = request.body[request.body.mode];
209+
requestBody += convertPropListToStringUrlEncoded(propertyList, '&', false, trimRequestBody);
185210
}
186211
return trimRequestBody ? requestBody.trim() : requestBody;
187212

codegens/http/test/resources/expected-http-messages.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Length: 586\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\n\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"pl\"\n\n'a'\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"qu\"\n\n\"b\"\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"hdjkljh\"\n\nc\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"sa\"\n\nd\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"Special\"\n\n!@#$%&*()^_+=`~ \n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"more\"\n\n,./';[]}{\":?><|\\\\\n----WebKitFormBoundary7MA4YWxkTrZu0gW\n",
88
"POST /post?a=!@$^*()_-`%26&b=,./';[]}{\":/?><|| HTTP/1.1\nHost: postman-echo.com",
99
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 284\n\nDuis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, id semper sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat.!@#$%^&*()+POL:},'';,[;[;\n\n\n",
10-
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 81\n\n1='a'&2=\"b\"&'3'=c&\"4\"=d&Special=!@%23$%%26*()^_=`~ &more=,./';[]}{\":?><|\\\\ ",
10+
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 147\n\n1='a'&2=%22b%22&'3'=c&%224%22=d&Special=!%40%23%24%25%26*()%5E_%3D%60~%20%20%20%20&more=%2C.%2F'%3B%5B%5D%7D%7B%22%3A%3F%3E%3C%7C%5C%5C%20%20%20%20",
1111
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/json\nContent-Length: 52\n\n{\n \"json\": \"Test-Test!@#$%^&*()+POL:},'';,[;[;:>\"\n}",
1212
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/javascript\nContent-Length: 30\n\nvar val = 6;\nconsole.log(val);",
1313
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: text/xml\nContent-Length: 48\n\n<xml>\n\tTest Test!@#$%^&*()+POL:},'';,[;[;\n</xml>",
@@ -33,7 +33,7 @@
3333
"trimmedResult": [
3434
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 281\n\nDuis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, id semper sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat.!@#$%^&*()+POL:},'';,[;[;",
3535
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Length: 581\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\n\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"pl\"\n\n'a'\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"qu\"\n\n\"b\"\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"hdjkljh\"\n\nc\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"sa\"\n\nd\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"Special\"\n\n!@#$%&*()^_+=`~\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"more\"\n\n,./';[]}{\":?><|\\\\\n----WebKitFormBoundary7MA4YWxkTrZu0gW",
36-
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 73\n\n1='a'&2=\"b\"&'3'=c&\"4\"=d&Special=!@%23$%%26*()^_=`~&more=,./';[]}{\":?><|\\\\"
36+
"POST /post HTTP/1.1\nHost: postman-echo.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 123\n\n1='a'&2=%22b%22&'3'=c&%224%22=d&Special=!%40%23%24%25%26*()%5E_%3D%60~&more=%2C.%2F'%3B%5B%5D%7D%7B%22%3A%3F%3E%3C%7C%5C%5C"
3737
]
3838

3939
}

codegens/js-fetch/lib/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,17 @@ function parseFormData (body, trim) {
6262
* @param {Object} body Raw body data
6363
* @param {boolean} trim trim body option
6464
* @param {String} contentType Content type of the body being sent
65+
* @param {String} indentString Indentation string
6566
*/
66-
function parseRawBody (body, trim, contentType) {
67+
function parseRawBody (body, trim, contentType, indentString) {
6768
var bodySnippet = 'var raw = ';
6869
// Match any application type whose underlying structure is json
6970
// For example application/vnd.api+json
7071
// All of them have +json as suffix
7172
if (contentType && (contentType === 'application/json' || contentType.match(/\+json$/))) {
7273
try {
7374
let jsonBody = JSON.parse(body);
74-
bodySnippet += `JSON.stringify(${JSON.stringify(jsonBody)});\n`;
75+
bodySnippet += `JSON.stringify(${JSON.stringify(jsonBody, null, indentString.length)});\n`;
7576
}
7677
catch (error) {
7778
bodySnippet += `"${sanitize(body.toString(), trim)}";\n`;
@@ -130,7 +131,7 @@ function parseBody (body, trim, indentString, contentType) {
130131
case 'urlencoded':
131132
return parseURLEncodedBody(body.urlencoded, trim);
132133
case 'raw':
133-
return parseRawBody(body.raw, trim, contentType);
134+
return parseRawBody(body.raw, trim, contentType, indentString);
134135
case 'graphql':
135136
return parseGraphQL(body.graphql, trim, indentString);
136137
case 'formdata':

codegens/js-fetch/test/unit/convert.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('js-fetch convert function for test collection', function () {
7979
expect.fail(null, null, error);
8080
}
8181
expect(snippet).to.be.a('string');
82-
expect(snippet).to.contain('var raw = JSON.stringify({"data":{"hello":"world"}});');
82+
expect(snippet).to.contain('JSON.stringify({\n "data": {\n "hello": "world"\n }\n});');
8383
});
8484
});
8585

@@ -211,7 +211,7 @@ describe('js-fetch convert function for test collection', function () {
211211
expect.fail(null, null, error);
212212
}
213213
expect(snippet).to.be.a('string');
214-
expect(snippet).to.include('var raw = JSON.stringify({"json":"Test-Test"})');
214+
expect(snippet).to.include('JSON.stringify({\n "json": "Test-Test"\n})');
215215
});
216216
});
217217

codegens/js-jquery/lib/util/parseBody.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ module.exports = function (request, trimRequestBody, indentation, contentType) {
2727
// eslint-disable-next-line max-depth
2828
try {
2929
let jsonBody = JSON.parse(request.body[request.body.mode]);
30-
requestBody += `${indentation}"data": JSON.stringify(${JSON.stringify(jsonBody)}),\n`;
30+
requestBody += `${indentation}"data": JSON.stringify(${JSON.stringify(jsonBody,
31+
null, indentation.length).replace(/\n/g, `\n${indentation}`)}),\n`;
3132
}
3233
catch (error) {
3334
requestBody += `${indentation}"data": ` +

codegens/js-jquery/test/unit/converter.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('jQuery converter', function () {
103103
expect.fail(null, null, error);
104104
}
105105
expect(snippet).to.be.a('string');
106-
expect(snippet).to.contain('"data": JSON.stringify({"data":{"hello":"world"}})');
106+
expect(snippet).to.contain('JSON.stringify({\n "data": {\n "hello": "world"\n }\n })');
107107
});
108108
});
109109

@@ -163,7 +163,7 @@ describe('jQuery converter', function () {
163163
expect.fail(null, null, error);
164164
}
165165
expect(snippet).to.be.a('string');
166-
expect(snippet).to.include('"data": JSON.stringify({"json":"Test-Test"})');
166+
expect(snippet).to.include('"data": JSON.stringify({\n "json": "Test-Test"\n }');
167167
});
168168
});
169169

0 commit comments

Comments
 (0)