Skip to content

Commit

Permalink
Merge pull request #727 from postmanlabs/release/v1.9.0
Browse files Browse the repository at this point in the history
Release version v1.9.0
  • Loading branch information
VShingala committed Jan 18, 2024
2 parents 2427014 + c5aeaa7 commit 5386053
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 85 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## [Unreleased]

## [v1.9.0] - 2024-01-18

### Fixed

- Fix for - [#10139](https://github.com/postmanlabs/postman-app-support/issues/10139) Modify Swift codegen to work with multipart/form-data format, used for video file upload

## [v1.8.0] - 2023-06-27

- Fix for - [#10521](https://github.com/postmanlabs/postman-app-support/issues/10521) Add support for Dart Dio snippet generation
Expand Down Expand Up @@ -140,7 +146,9 @@ v1.0.0 (May 29, 2020)
- Add ES6 syntax support for NodeJS Request, NodeJS Native and NodeJS Unirest
- Fix snippet generation for powershell and jquery, where form data params had no type field

[Unreleased]: https://github.com/postmanlabs/postman-code-generators/compare/v1.8.0...HEAD
[Unreleased]: https://github.com/postmanlabs/postman-code-generators/compare/v1.9.0...HEAD

[v1.9.0]: https://github.com/postmanlabs/postman-code-generators/compare/v1.8.0...v1.9.0

[v1.8.0]: https://github.com/postmanlabs/postman-code-generators/compare/v1.7.2...v1.8.0

Expand Down
1 change: 1 addition & 0 deletions codegens/js-fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Convert function takes three parameters
* `trimRequestBody` - Trim request body fields
* `followRedirect` - Boolean denoting whether to redirect a request
* `requestTimeout` - Integer denoting time after which the request will bail out in milli-seconds
* `asyncAwaitEnabled` : Boolean denoting whether to use async/await syntax

* `callback` - callback function with first parameter as error and second parameter as string for code snippet

Expand Down
71 changes: 45 additions & 26 deletions codegens/js-fetch/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function redirectMode (redirect) {
* @param {boolean} trim trim body option
*/
function parseURLEncodedBody (body, trim) {
var bodySnippet = 'var urlencoded = new URLSearchParams();\n';
var bodySnippet = 'const urlencoded = new URLSearchParams();\n';
_.forEach(body, function (data) {
if (!data.disabled) {
bodySnippet += `urlencoded.append("${sanitize(data.key, trim)}", "${sanitize(data.value, trim)}");\n`;
Expand All @@ -40,7 +40,7 @@ function parseURLEncodedBody (body, trim) {
* @param {boolean} trim trim body option
*/
function parseFormData (body, trim) {
var bodySnippet = 'var formdata = new FormData();\n';
var bodySnippet = 'const formdata = new FormData();\n';
_.forEach(body, function (data) {
if (!data.disabled) {
if (data.type === 'file') {
Expand All @@ -65,7 +65,7 @@ function parseFormData (body, trim) {
* @param {String} indentString Indentation string
*/
function parseRawBody (body, trim, contentType, indentString) {
var bodySnippet = 'var raw = ';
var bodySnippet = 'const raw = ';
// Match any application type whose underlying structure is json
// For example application/vnd.api+json
// All of them have +json as suffix
Expand Down Expand Up @@ -101,7 +101,7 @@ function parseGraphQL (body, trim, indentString) {
catch (e) {
graphqlVariables = {};
}
bodySnippet = 'var graphql = JSON.stringify({\n';
bodySnippet = 'const graphql = JSON.stringify({\n';
bodySnippet += `${indentString}query: "${sanitize(query, trim)}",\n`;
bodySnippet += `${indentString}variables: ${JSON.stringify(graphqlVariables)}\n})`;
return bodySnippet;
Expand All @@ -113,7 +113,7 @@ function parseGraphQL (body, trim, indentString) {
* parses binamry file data
*/
function parseFileData () {
var bodySnippet = 'var file = "<file contents here>";\n';
var bodySnippet = 'const file = "<file contents here>";\n';
return bodySnippet;
}

Expand Down Expand Up @@ -154,7 +154,7 @@ function parseBody (body, trim, indentString, contentType) {
function parseHeaders (headers) {
var headerSnippet = '';
if (!_.isEmpty(headers)) {
headerSnippet = 'var myHeaders = new Headers();\n';
headerSnippet = 'const myHeaders = new Headers();\n';
headers = _.reject(headers, 'disabled');
_.forEach(headers, function (header) {
headerSnippet += `myHeaders.append("${sanitize(header.key, true)}", "${sanitize(header.value)}");\n`;
Expand Down Expand Up @@ -209,6 +209,13 @@ function getOptions () {
type: 'boolean',
default: false,
description: 'Remove white space and additional lines that may affect the server\'s response'
},
{
name: 'Use async/await',
id: 'asyncAwaitEnabled',
type: 'boolean',
default: false,
description: 'Modifies code snippet to use async/await'
}
];
}
Expand Down Expand Up @@ -238,7 +245,6 @@ function convert (request, options, callback) {
headerSnippet = '',
bodySnippet = '',
optionsSnippet = '',
timeoutSnippet = '',
fetchSnippet = '';
indent = indent.repeat(options.indentCount);
if (request.body && request.body.mode === 'graphql' && !request.headers.has('Content-Type')) {
Expand Down Expand Up @@ -294,8 +300,12 @@ function convert (request, options, callback) {
body = request.body && request.body.toJSON();
bodySnippet = parseBody(body, trim, indent, request.headers.get('Content-Type'));

optionsSnippet = `var requestOptions = {\n${indent}`;
optionsSnippet += `method: '${request.method}',\n${indent}`;
if (options.requestTimeout > 0) {
codeSnippet += 'const controller = new AbortController();\n';
codeSnippet += `const timerId = setTimeout(() => controller.abort(), ${options.requestTimeout});\n`;
}
optionsSnippet = `const requestOptions = {\n${indent}`;
optionsSnippet += `method: "${request.method}",\n${indent}`;
if (headerSnippet !== '') {
optionsSnippet += `headers: myHeaders,\n${indent}`;
codeSnippet += headerSnippet + '\n';
Expand All @@ -305,30 +315,39 @@ function convert (request, options, callback) {
optionsSnippet += `body: ${body.mode},\n${indent}`;
codeSnippet += bodySnippet + '\n';
}
optionsSnippet += `redirect: '${redirectMode(options.followRedirect)}'\n};\n`;
if (options.requestTimeout > 0) {
optionsSnippet += `signal: controller.signal,\n${indent}`;
}
optionsSnippet += `redirect: "${redirectMode(options.followRedirect)}"\n};\n`;

codeSnippet += optionsSnippet + '\n';

fetchSnippet = `fetch("${sanitize(request.url.toString())}", requestOptions)\n${indent}`;
fetchSnippet += `.then(response => response.text())\n${indent}`;
fetchSnippet += `.then(result => console.log(result))\n${indent}`;
fetchSnippet += '.catch(error => console.log(\'error\', error));';

if (options.requestTimeout > 0) {
timeoutSnippet = `var promise = Promise.race([\n${indent}`;
timeoutSnippet += `fetch('${request.url.toString()}', requestOptions)\n${indent}${indent}`;
timeoutSnippet += `.then(response => response.text()),\n${indent}`;
timeoutSnippet += `new Promise((resolve, reject) =>\n${indent}${indent}`;
timeoutSnippet += `setTimeout(() => reject(new Error('Timeout')), ${options.requestTimeout})\n${indent}`;
timeoutSnippet += ')\n]);\n\n';
timeoutSnippet += 'promise.then(result => console.log(result)),\n';
timeoutSnippet += 'promise.catch(error => console.log(error));';
codeSnippet += timeoutSnippet;
if (options.asyncAwaitEnabled) {
fetchSnippet += `try {\n${indent}`;
fetchSnippet += `const response = await fetch("${sanitize(request.url.toString())}", requestOptions);\n${indent}`;
fetchSnippet += `const result = await response.text();\n${indent}`;
fetchSnippet += 'console.log(result)\n';
fetchSnippet += `} catch (error) {\n${indent}`;
fetchSnippet += 'console.error(error);\n';
if (options.requestTimeout > 0) {
fetchSnippet += `} finally {\n${indent}`;
fetchSnippet += 'clearTimeout(timerId);\n';
}
fetchSnippet += '};';
}
else {
codeSnippet += fetchSnippet;
fetchSnippet = `fetch("${sanitize(request.url.toString())}", requestOptions)\n${indent}`;
fetchSnippet += `.then((response) => response.text())\n${indent}`;
fetchSnippet += `.then((result) => console.log(result))\n${indent}`;
fetchSnippet += '.catch((error) => console.error(error))';
if (options.requestTimeout > 0) {
fetchSnippet += `\n${indent}.finally(() => clearTimeout(timerId))`;
}
fetchSnippet += ';';
}

codeSnippet += fetchSnippet;

callback(null, codeSnippet);
}

Expand Down
64 changes: 60 additions & 4 deletions codegens/js-fetch/test/unit/convert.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ describe('js-fetch convert function for test collection', function () {
expect.fail(null, null, error);
return;
}

expect(snippet).to.be.a('string');
snippetArray = snippet.split('\n');
for (var i = 0; i < snippetArray.length; i++) {
if (snippetArray[i] === 'var requestOptions = {') { line_no = i + 1; }
if (snippetArray[i] === 'const requestOptions = {') { line_no = i + 1; }
}
expect(snippetArray[line_no].charAt(0)).to.equal(' ');
expect(snippetArray[line_no].charAt(1)).to.equal(' ');
Expand Down Expand Up @@ -95,7 +94,7 @@ describe('js-fetch convert function for test collection', function () {
return;
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('redirect: \'manual\'');
expect(snippet).to.include('redirect: "manual"');
});
});

Expand All @@ -111,7 +110,7 @@ describe('js-fetch convert function for test collection', function () {
return;
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('redirect: \'follow\'');
expect(snippet).to.include('redirect: "follow"');
});
});

Expand Down Expand Up @@ -298,6 +297,62 @@ describe('js-fetch convert function for test collection', function () {
expect(snippet).to.include('fetch("https://postman-echo.com/get?query1=b\'b&query2=c\\"c"');
});
});

it('should return snippet with promise based code when async_await is disabled', function () {
const request = new sdk.Request(mainCollection.item[0].request);

convert(request, {}, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('fetch(');
expect(snippet).to.include('.then((response) => ');
expect(snippet).to.include('.catch((error) => ');
});
});

it('should return snippet with async/await based code when option is enabled', function () {
const request = new sdk.Request(mainCollection.item[0].request);

convert(request, { asyncAwaitEnabled: true }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('const response = await fetch(');
expect(snippet).to.include('const result = await response.text()');
expect(snippet).to.include('catch (error) {');
});
});

it('should return timeout snippet with promise based code when async_await is disabled', function () {
const request = new sdk.Request(mainCollection.item[0].request);

convert(request, { requestTimeout: 3000 }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('const controller');
expect(snippet).to.include('const timerId');
expect(snippet).to.include('.finally(() => clearTimeout(timerId))');
});
});

it('should return timeout snippet with promise based code when async_await is enabled', function () {
const request = new sdk.Request(mainCollection.item[0].request);

convert(request, { requestTimeout: 3000, asyncAwaitEnabled: true }, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('const controller');
expect(snippet).to.include('const timerId');
expect(snippet).to.include('} finally {');
});
});
});

describe('getOptions function', function () {
Expand All @@ -312,6 +367,7 @@ describe('js-fetch convert function for test collection', function () {
expect(getOptions()[2]).to.have.property('id', 'requestTimeout');
expect(getOptions()[3]).to.have.property('id', 'followRedirect');
expect(getOptions()[4]).to.have.property('id', 'trimRequestBody');
expect(getOptions()[5]).to.have.property('id', 'asyncAwaitEnabled');
});
});

Expand Down
3 changes: 3 additions & 0 deletions codegens/libcurl/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ self = module.exports = {
if (body.mode === 'formdata' && options.useMimeType) {
snippet += indentString + 'curl_mime_free(mime);\n';
}
if (headersData) {
snippet += indentString + 'curl_slist_free_all(headers);\n';
}
snippet += '}\n';
snippet += 'curl_easy_cleanup(curl);\n';
(options.includeBoilerplate) &&
Expand Down
32 changes: 32 additions & 0 deletions codegens/libcurl/test/unit/convert.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,38 @@ describe('libcurl convert function', function () {
expect(snippet).to.include('curl_mime_name(part, "invalid src");');
});
});

it('should free up headers list after request is sent', function () {
var request = new sdk.Request({
'method': 'GET',
'header': [
{
'key': 'Accept',
'value': 'application/json'
},
{
'key': 'Content-Type',
'value': 'application/json'
}
],
'url': {
'raw': 'https://google.com',
'protocol': 'https',
'host': [
'google',
'com'
]
}
});
convert(request, {}, function (error, snippet) {
if (error) {
expect.fail(null, null, error);
}
expect(snippet).to.be.a('string');
expect(snippet).to.include('curl_slist_free_all(headers)');
});
});

});

describe('getOptions function', function () {
Expand Down
29 changes: 17 additions & 12 deletions codegens/swift/lib/swift.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,29 +111,34 @@ function parseFormData (body, mode, trim, indent) {
parameters = '[\n' + _.join(parameters, ',\n') + ']';
bodySnippet = `let parameters = ${parameters} as [[String: Any]]\n\n`;
bodySnippet += 'let boundary = "Boundary-\\(UUID().uuidString)"\n';
bodySnippet += 'var body = ""\nvar error: Error? = nil\n';
bodySnippet += 'var body = Data()\nvar error: Error? = nil\n';
bodySnippet += 'for param in parameters {\n';
bodySnippet += `${indent}if param["disabled"] != nil { continue }\n`;
bodySnippet += `${indent}let paramName = param["key"]!\n`;
bodySnippet += `${indent}body += "--\\(boundary)\\r\\n"\n`;
bodySnippet += `${indent}body += Data("--\\(boundary)\\r\\n".utf8)\n`;
// eslint-disable-next-line no-useless-escape
bodySnippet += `${indent}body += "Content-Disposition:form-data; name=\\"\\(paramName)\\"\"\n`;
bodySnippet += `${indent}body += Data("Content-Disposition:form-data; name=\\"\\(paramName)\\"\".utf8)\n`;
bodySnippet += `${indent}if param["contentType"] != nil {\n`;
bodySnippet += `${indent.repeat(2)}body += "\\r\\nContent-Type: \\(param["contentType"] as! String)"\n`;
bodySnippet += `${indent.repeat(2)}body += Data("\\r\\nContent-Type: \\(param["contentType"] as! String)".utf8)\n`;
bodySnippet += `${indent}}\n`;
bodySnippet += `${indent}let paramType = param["type"] as! String\n`;
bodySnippet += `${indent}if paramType == "text" {\n`;
bodySnippet += `${indent.repeat(2)}let paramValue = param["value"] as! String\n`;
bodySnippet += `${indent.repeat(2)}body += "\\r\\n\\r\\n\\(paramValue)\\r\\n"\n`;
bodySnippet += `${indent.repeat(2)}body += Data("\\r\\n\\r\\n\\(paramValue)\\r\\n".utf8)\n`;
bodySnippet += `${indent}} else {\n`;
bodySnippet += `${indent.repeat(2)}let paramSrc = param["src"] as! String\n`;
bodySnippet += `${indent.repeat(2)}let fileData = try NSData(contentsOfFile: paramSrc, options: []) as Data\n`;
bodySnippet += `${indent.repeat(2)}let fileContent = String(data: fileData, encoding: .utf8)!\n`;
bodySnippet += `${indent.repeat(2)}body += "; filename=\\"\\(paramSrc)\\"\\r\\n"\n`;
bodySnippet += `${indent.repeat(2)} + "Content-Type: \\"content-type header\\"\\r\\n\\r\\n`;
bodySnippet += '\\(fileContent)\\r\\n"\n';
bodySnippet += `${indent}}\n}\nbody += "--\\(boundary)--\\r\\n";\n`;
bodySnippet += 'let postData = body.data(using: .utf8)';
bodySnippet += `${indent.repeat(2)}let fileURL = URL(fileURLWithPath: paramSrc)\n`;
bodySnippet += `${indent.repeat(2)}if let fileContent = try? Data(contentsOf: fileURL) {\n`;
bodySnippet += `${indent.repeat(3)}body += Data("; filename=\\"\\(paramSrc)\\"\\r\\n".utf8)\n`;
bodySnippet += `${indent.repeat(3)}body += Data("Content-Type: \\"content-type header\\"\\r\\n".utf8)\n`;
bodySnippet += `${indent.repeat(3)}body += Data("\\r\\n".utf8)\n`;
bodySnippet += `${indent.repeat(3)}body += fileContent\n`;
bodySnippet += `${indent.repeat(3)}body += Data("\\r\\n".utf8)\n`;
bodySnippet += `${indent.repeat(2)}}\n`;
bodySnippet += `${indent}}\n`;
bodySnippet += '}\n';
bodySnippet += 'body += Data("--\\(boundary)--\\r\\n".utf8);\n';
bodySnippet += 'let postData = body\n';
return bodySnippet;
}

Expand Down
2 changes: 1 addition & 1 deletion codegens/swift/test/unit/convert.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('Swift Converter', function () {
}
expect(snippet).to.be.a('string');
expect(snippet).to.contain('if param["contentType"] != nil {');
expect(snippet).to.contain('body += "\\r\\nContent-Type: \\(param["contentType"] as! String)"');
expect(snippet).to.contain('body += Data("\\r\\nContent-Type: \\(param["contentType"] as! String)".utf8)');
});
});

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5386053

Please sign in to comment.