Browse Source

[breaking] feat: code generators

Acathur 4 years ago
parent
commit
ff2d828cef
100 changed files with 7090 additions and 0 deletions
  1. 12 0
      dist/codegens/csharp-restsharp/index.d.ts
  2. 2 0
      dist/codegens/csharp-restsharp/index.js
  3. 9 0
      dist/codegens/csharp-restsharp/lib/index.d.ts
  4. 5 0
      dist/codegens/csharp-restsharp/lib/index.js
  5. 22 0
      dist/codegens/csharp-restsharp/lib/parseRequest.d.ts
  6. 112 0
      dist/codegens/csharp-restsharp/lib/parseRequest.js
  7. 9 0
      dist/codegens/csharp-restsharp/lib/restsharp.d.ts
  8. 192 0
      dist/codegens/csharp-restsharp/lib/restsharp.js
  9. 29 0
      dist/codegens/csharp-restsharp/lib/util.d.ts
  10. 115 0
      dist/codegens/csharp-restsharp/lib/util.js
  11. 26 0
      dist/codegens/curl/index.d.ts
  12. 2 0
      dist/codegens/curl/index.js
  13. 23 0
      dist/codegens/curl/lib/index.d.ts
  14. 229 0
      dist/codegens/curl/lib/index.js
  15. 5 0
      dist/codegens/curl/lib/util.d.ts
  16. 187 0
      dist/codegens/curl/lib/util.js
  17. 26 0
      dist/codegens/golang/index.d.ts
  18. 2 0
      dist/codegens/golang/index.js
  19. 23 0
      dist/codegens/golang/lib/index.d.ts
  20. 313 0
      dist/codegens/golang/lib/index.js
  21. 4 0
      dist/codegens/golang/lib/util.d.ts
  22. 132 0
      dist/codegens/golang/lib/util.js
  23. 21 0
      dist/codegens/index.d.ts
  24. 39 0
      dist/codegens/index.js
  25. 12 0
      dist/codegens/java-okhttp/index.d.ts
  26. 2 0
      dist/codegens/java-okhttp/index.js
  27. 9 0
      dist/codegens/java-okhttp/lib/index.d.ts
  28. 5 0
      dist/codegens/java-okhttp/lib/index.js
  29. 31 0
      dist/codegens/java-okhttp/lib/okhttp.d.ts
  30. 178 0
      dist/codegens/java-okhttp/lib/okhttp.js
  31. 24 0
      dist/codegens/java-okhttp/lib/parseRequest.d.ts
  32. 139 0
      dist/codegens/java-okhttp/lib/parseRequest.js
  33. 3 0
      dist/codegens/java-okhttp/lib/util.d.ts
  34. 112 0
      dist/codegens/java-okhttp/lib/util.js
  35. 91 0
      dist/codegens/lodash.d.ts
  36. 172 0
      dist/codegens/lodash.js
  37. 5 0
      dist/codegens/nodejs-native/index.d.ts
  38. 2 0
      dist/codegens/nodejs-native/index.js
  39. 2 0
      dist/codegens/nodejs-native/lib/index.d.ts
  40. 5 0
      dist/codegens/nodejs-native/lib/index.js
  41. 17 0
      dist/codegens/nodejs-native/lib/parseRequest.d.ts
  42. 145 0
      dist/codegens/nodejs-native/lib/parseRequest.js
  43. 2 0
      dist/codegens/nodejs-native/lib/request.d.ts
  44. 285 0
      dist/codegens/nodejs-native/lib/request.js
  45. 3 0
      dist/codegens/nodejs-native/lib/util.d.ts
  46. 112 0
      dist/codegens/nodejs-native/lib/util.js
  47. 11 0
      dist/codegens/php-curl/index.d.ts
  48. 2 0
      dist/codegens/php-curl/index.js
  49. 8 0
      dist/codegens/php-curl/lib/index.d.ts
  50. 5 0
      dist/codegens/php-curl/lib/index.js
  51. 8 0
      dist/codegens/php-curl/lib/php-curl.d.ts
  52. 168 0
      dist/codegens/php-curl/lib/php-curl.js
  53. 2 0
      dist/codegens/php-curl/lib/util/parseBody.d.ts
  54. 74 0
      dist/codegens/php-curl/lib/util/parseBody.js
  55. 3 0
      dist/codegens/php-curl/lib/util/sanitize.d.ts
  56. 120 0
      dist/codegens/php-curl/lib/util/sanitize.js
  57. 13 0
      dist/codegens/postman-collection-lite/collection/form-param.d.ts
  58. 85 0
      dist/codegens/postman-collection-lite/collection/form-param.js
  59. 1 0
      dist/codegens/postman-collection-lite/collection/header-list.d.ts
  60. 58 0
      dist/codegens/postman-collection-lite/collection/header-list.js
  61. 13 0
      dist/codegens/postman-collection-lite/collection/header.d.ts
  62. 239 0
      dist/codegens/postman-collection-lite/collection/header.js
  63. 6 0
      dist/codegens/postman-collection-lite/collection/property-base.d.ts
  64. 199 0
      dist/codegens/postman-collection-lite/collection/property-base.js
  65. 7 0
      dist/codegens/postman-collection-lite/collection/property-list.d.ts
  66. 592 0
      dist/codegens/postman-collection-lite/collection/property-list.js
  67. 21 0
      dist/codegens/postman-collection-lite/collection/property.d.ts
  68. 135 0
      dist/codegens/postman-collection-lite/collection/property.js
  69. 13 0
      dist/codegens/postman-collection-lite/collection/query-param.d.ts
  70. 244 0
      dist/codegens/postman-collection-lite/collection/query-param.js
  71. 11 0
      dist/codegens/postman-collection-lite/collection/request-body.d.ts
  72. 206 0
      dist/codegens/postman-collection-lite/collection/request-body.js
  73. 33 0
      dist/codegens/postman-collection-lite/collection/request.d.ts
  74. 317 0
      dist/codegens/postman-collection-lite/collection/request.js
  75. 1 0
      dist/codegens/postman-collection-lite/collection/url.d.ts
  76. 363 0
      dist/codegens/postman-collection-lite/collection/url.js
  77. 1 0
      dist/codegens/postman-collection-lite/collection/variable-list.d.ts
  78. 166 0
      dist/codegens/postman-collection-lite/collection/variable-list.js
  79. 19 0
      dist/codegens/postman-collection-lite/collection/variable.d.ts
  80. 358 0
      dist/codegens/postman-collection-lite/collection/variable.js
  81. 2 0
      dist/codegens/postman-collection-lite/index.d.ts
  82. 5 0
      dist/codegens/postman-collection-lite/index.js
  83. 11 0
      dist/codegens/python-http.client/index.d.ts
  84. 2 0
      dist/codegens/python-http.client/index.js
  85. 8 0
      dist/codegens/python-http.client/lib/index.d.ts
  86. 5 0
      dist/codegens/python-http.client/lib/index.js
  87. 8 0
      dist/codegens/python-http.client/lib/python-httpclient.d.ts
  88. 183 0
      dist/codegens/python-http.client/lib/python-httpclient.js
  89. 2 0
      dist/codegens/python-http.client/lib/util/parseBody.d.ts
  90. 92 0
      dist/codegens/python-http.client/lib/util/parseBody.js
  91. 3 0
      dist/codegens/python-http.client/lib/util/sanitize.d.ts
  92. 130 0
      dist/codegens/python-http.client/lib/util/sanitize.js
  93. 11 0
      dist/codegens/ruby/index.d.ts
  94. 2 0
      dist/codegens/ruby/index.js
  95. 8 0
      dist/codegens/ruby/lib/index.d.ts
  96. 5 0
      dist/codegens/ruby/lib/index.js
  97. 8 0
      dist/codegens/ruby/lib/ruby.d.ts
  98. 206 0
      dist/codegens/ruby/lib/ruby.js
  99. 2 0
      dist/codegens/ruby/lib/util/parseBody.d.ts
  100. 0 0
      dist/codegens/ruby/lib/util/parseBody.js

+ 12 - 0
dist/codegens/csharp-restsharp/index.d.ts

@@ -0,0 +1,12 @@
+declare const _exports: {
+    convert: (request: any, options: {
+        indentType: string;
+        indentCount: string;
+        includeBoilerplate?: boolean;
+        followRedirect: boolean;
+        trimRequestBody: boolean;
+        requestTimeout: number;
+    }, callback: Function) => string;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/csharp-restsharp/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 9 - 0
dist/codegens/csharp-restsharp/lib/index.d.ts

@@ -0,0 +1,9 @@
+export declare const convert: (request: any, options: {
+    indentType: string;
+    indentCount: string;
+    includeBoilerplate?: boolean;
+    followRedirect: boolean;
+    trimRequestBody: boolean;
+    requestTimeout: number;
+}, callback: Function) => string;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/csharp-restsharp/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./restsharp').convert,
+    getOptions: require('./restsharp').getOptions
+};

+ 22 - 0
dist/codegens/csharp-restsharp/lib/parseRequest.d.ts

@@ -0,0 +1,22 @@
+/**
+ * Parses request object and returns csharp-restsharp code snippet for adding request body
+ *
+ * @param {Object} request - JSON object representing body of request
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} code snippet of csharp-restsharp parsed from request object
+ */
+export function parseBody(request: any, trimFields: boolean): string;
+/**
+ * Parses header in Postman-SDK request and returns code snippet of csharp-restsharp for adding headers
+ *
+ * @param {Object} requestJson - Postman SDK request object
+ * @returns {String} code snippet for adding headers in csharp-restsharp
+ */
+export function parseHeader(requestJson: any): string;
+/**
+ * Returns content-type of request body if available else returns text/plain as default
+ *
+ * @param {Object} request - Postman SDK request object
+ * @returns {String} content-type of request body
+ */
+export function parseContentType(request: any): string;

+ 112 - 0
dist/codegens/csharp-restsharp/lib/parseRequest.js

@@ -0,0 +1,112 @@
+"use strict";
+var _ = require('../../lodash'), sanitize = require('./util').sanitize;
+/**
+ * Parses body of request specific requests having form data
+ *
+ * @param {Object} requestBody - JSON object representing body of request
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} code snippet of csharp-restsharp for multipart formdata
+ */
+function parseFormData(requestBody, trimFields) {
+    if (!Array.isArray(requestBody[requestBody.mode])) {
+        return '';
+    }
+    return requestBody[requestBody.mode].reduce((body, data) => {
+        if (data.disabled) {
+            return body;
+        }
+        if (data.type === 'file') {
+            body += `request.AddFile("${sanitize(data.key, trimFields)}", "${sanitize(data.src, trimFields)}");\n`;
+        }
+        else {
+            (!data.value) && (data.value = '');
+            body += `request.AddParameter("${sanitize(data.key, trimFields)}", ` +
+                `"${sanitize(data.value, trimFields)}");\n`;
+        }
+        return body;
+    }, '');
+}
+/**
+ * Returns content-type of request body if available else returns text/plain as default
+ *
+ * @param {Object} request - Postman SDK request object
+ * @returns {String} content-type of request body
+ */
+function parseContentType(request) {
+    return request.getHeaders({ enabled: true, ignoreCase: true })['content-type'] || 'text/plain';
+}
+/**
+ *
+ * @param {Object} requestBody - JSON object representing body of request
+ * @param {boolean} trimFields - Boolean denoting whether to trim body fields
+ * @returns {String} code snippet for graphql body
+ */
+function parseGraphQL(requestBody, trimFields) {
+    let query = requestBody.graphql.query, graphqlVariables;
+    try {
+        graphqlVariables = JSON.parse(requestBody.graphql.variables);
+    }
+    catch (e) {
+        graphqlVariables = {};
+    }
+    return 'request.AddParameter("application/json", ' +
+        `"${sanitize(JSON.stringify({ query: query, variables: graphqlVariables }), trimFields)}",
+           ParameterType.RequestBody);\n`;
+}
+/**
+ * Parses request object and returns csharp-restsharp code snippet for adding request body
+ *
+ * @param {Object} request - JSON object representing body of request
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} code snippet of csharp-restsharp parsed from request object
+ */
+function parseBody(request, trimFields) {
+    var requestBody = request.body ? request.body.toJSON() : {};
+    if (!_.isEmpty(requestBody)) {
+        switch (requestBody.mode) {
+            case 'urlencoded':
+                return parseFormData(requestBody, trimFields);
+            case 'formdata':
+                return parseFormData(requestBody, trimFields);
+            case 'raw':
+                return `request.AddParameter("${parseContentType(request)}", ` +
+                    `${JSON.stringify(requestBody[requestBody.mode])},  ParameterType.RequestBody);\n`;
+            case 'graphql':
+                return parseGraphQL(requestBody, trimFields);
+            /* istanbul ignore next */
+            case 'file':
+                return `request.AddParameter("${parseContentType(request)}", ` +
+                    '"<file contents here>", ParameterType.RequestBody);\n';
+            default:
+                return '';
+        }
+    }
+    return '';
+}
+/**
+ * Parses header in Postman-SDK request and returns code snippet of csharp-restsharp for adding headers
+ *
+ * @param {Object} requestJson - Postman SDK request object
+ * @returns {String} code snippet for adding headers in csharp-restsharp
+ */
+function parseHeader(requestJson) {
+    if (!Array.isArray(requestJson.header)) {
+        return '';
+    }
+    return requestJson.header.reduce((headerSnippet, header) => {
+        if (!header.disabled) {
+            if (sanitize(header.key, true).toLowerCase() === 'user-agent') {
+                headerSnippet += `client.UserAgent = "${sanitize(header.value)}";\n`;
+            }
+            else {
+                headerSnippet += `request.AddHeader("${sanitize(header.key, true)}", "${sanitize(header.value)}");\n`;
+            }
+        }
+        return headerSnippet;
+    }, '');
+}
+module.exports = {
+    parseBody: parseBody,
+    parseHeader: parseHeader,
+    parseContentType: parseContentType
+};

+ 9 - 0
dist/codegens/csharp-restsharp/lib/restsharp.d.ts

@@ -0,0 +1,9 @@
+export declare function getOptions(): any[];
+export declare function convert(request: any, options: {
+    indentType: string;
+    indentCount: string;
+    includeBoilerplate?: boolean;
+    followRedirect: boolean;
+    trimRequestBody: boolean;
+    requestTimeout: number;
+}, callback: Function): string;

+ 192 - 0
dist/codegens/csharp-restsharp/lib/restsharp.js

@@ -0,0 +1,192 @@
+"use strict";
+var _ = require('../../lodash'), parseRequest = require('./parseRequest'), sanitize = require('./util').sanitize, sanitizeOptions = require('./util').sanitizeOptions, addFormParam = require('./util').addFormParam, self;
+/**
+ * Generates snippet in csharp-restsharp by parsing data from Postman-SDK request object
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {Object} options - Options to tweak code snippet
+ * @returns {String} csharp-restsharp code snippet for given request object
+ */
+function makeSnippet(request, options) {
+    const UNSUPPORTED_METHODS_LIKE_POST = ['LINK', 'UNLINK', 'LOCK', 'PROPFIND'], UNSUPPORTED_METHODS_LIKE_GET = ['PURGE', 'UNLOCK', 'VIEW', 'COPY'];
+    var snippet = `var client = new RestClient("${sanitize(request.url.toString())}");\n`, isUnSupportedMethod = UNSUPPORTED_METHODS_LIKE_GET.includes(request.method) ||
+        UNSUPPORTED_METHODS_LIKE_POST.includes(request.method);
+    // if (options.requestTimeout) {
+    //   snippet += `client.Timeout = ${options.requestTimeout};\n`;
+    // }
+    // else {
+    //   snippet += 'client.Timeout = -1;\n';
+    // }
+    // if (!options.followRedirect) {
+    //   snippet += 'client.FollowRedirects = false;\n';
+    // }
+    snippet += `var request = new RestRequest(${isUnSupportedMethod ? '' : ('Method.' + request.method)});\n`;
+    if (request.body && request.body.mode === 'graphql' && !request.headers.has('Content-Type')) {
+        request.addHeader({
+            key: 'Content-Type',
+            value: 'application/json'
+        });
+    }
+    snippet += parseRequest.parseHeader(request.toJSON(), options.trimRequestBody);
+    if (request.body && request.body.mode === 'formdata') {
+        let isFile = false, formdata = request.body.formdata, formdataArray = [];
+        request.body.toJSON().formdata.forEach((data) => {
+            if (!data.disabled && data.type === 'file') {
+                isFile = true;
+            }
+        });
+        // The following statement needs to be added else the multipart/form-data request where there is no file
+        // is being sent as x-www-form-urlencoded by default
+        if (!isFile) {
+            snippet += 'request.AlwaysMultipartFormData = true;\n';
+        }
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        formdata.members.forEach((param) => {
+            let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+            // check if type is file or text
+            if (type === 'file') {
+                // if src is not of type string we check for array(multiple files)
+                if (typeof param.src !== 'string') {
+                    // if src is an array(not empty), iterate over it and add files as separate form fields
+                    if (Array.isArray(param.src) && param.src.length) {
+                        param.src.forEach((filePath) => {
+                            addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                        });
+                    }
+                    // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
+                    else {
+                        addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                    }
+                }
+                // if src is string, directly add the param with src as filepath
+                else {
+                    addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                }
+            }
+            // if type is text, directly add it to formdata array
+            else {
+                addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+            }
+        });
+        request.body.update({
+            mode: 'formdata',
+            formdata: formdataArray
+        });
+    }
+    snippet += parseRequest.parseBody(request, options.trimRequestBody);
+    if (isUnSupportedMethod) {
+        (UNSUPPORTED_METHODS_LIKE_GET.includes(request.method)) &&
+            (snippet += `IRestResponse response = client.ExecuteAsGet(request, "${request.method}");\n`);
+        (UNSUPPORTED_METHODS_LIKE_POST.includes(request.method)) &&
+            (snippet += `IRestResponse response = client.ExecuteAsPost(request, "${request.method}");\n`);
+    }
+    else {
+        snippet += 'IRestResponse response = client.Execute(request);\n';
+    }
+    snippet += 'Console.WriteLine(response.Content);';
+    return snippet;
+}
+self = module.exports = {
+    /**
+       * Used in order to get additional options for generation of C# code snippet (i.e. Include Boilerplate code)
+       *
+       * @module getOptions
+       *
+       * @returns {Array} Additional options specific to generation of csharp-restsharp code snippet
+       */
+    getOptions: function () {
+        return [
+            {
+                name: 'Include boilerplate',
+                id: 'includeBoilerplate',
+                type: 'boolean',
+                default: false,
+                description: 'Include class definition and import statements in snippet'
+            },
+            {
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                availableOptions: ['Tab', 'Space'],
+                default: 'Space',
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response ' +
+                    'before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            }
+        ];
+    },
+    /**
+       * Converts Postman sdk request object to csharp-restsharp code snippet
+       *
+       * @module convert
+       *
+       * @param {Object} request - Postman-SDK request object
+       * @param {Object} options - Options to tweak code snippet generated in C#
+       * @param {String} options.indentType - type for indentation eg: Space, Tab (default: Space)
+       * @param {String} options.indentCount - number of spaces or tabs for indentation. (default: 4 for indentType:
+                                                                           Space, default: 1 for indentType: Tab)
+       * @param {Boolean} [options.includeBoilerplate] - indicates whether to include class definition in C#
+       * @param {Boolean} options.followRedirect - whether to enable followredirect
+       * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not (default: false)
+       * @param {Number} options.requestTimeout - time in milli-seconds after which request will bail out
+                                                       (default: 0 -> never bail out)
+       * @param {Function} callback - Callback function with parameters (error, snippet)
+       * @returns {String} Generated C# snippet via callback
+       */
+    convert: function (request, options, callback) {
+        if (!_.isFunction(callback)) {
+            throw new Error('C#-RestSharp-Converter: Callback is not valid function');
+        }
+        //  String representing value of indentation required
+        var indentString, 
+        //  snippets to include C# class definition according to options
+        headerSnippet = '', footerSnippet = '', 
+        //  snippet to create request in csharp-restsharp
+        snippet = '';
+        options = sanitizeOptions(options, self.getOptions());
+        indentString = options.indentType === 'Tab' ? '\t' : ' ';
+        indentString = indentString.repeat(options.indentCount);
+        if (options.includeBoilerplate) {
+            headerSnippet = 'using System;\n' +
+                'using RestSharp;\n\n' +
+                'namespace ApiTestApp {\n' +
+                indentString + 'class ApiTest {\n' +
+                indentString.repeat(2) + 'static void Main(string[] args) {\n';
+            footerSnippet = indentString.repeat(2) + '}\n' + indentString + '}\n}\n';
+        }
+        snippet = makeSnippet(request, options);
+        //  if boilerplate is included then two more indentString needs to be added in snippet
+        (options.includeBoilerplate) &&
+            (snippet = indentString.repeat(3) + snippet.split('\n').join('\n' + indentString.repeat(3)) + '\n');
+        return callback(null, headerSnippet + snippet + footerSnippet);
+    }
+};

+ 29 - 0
dist/codegens/csharp-restsharp/lib/util.d.ts

@@ -0,0 +1,29 @@
+/**
+ * sanitizes input string by handling escape characters eg: converts '''' to '\'\'' and trim input if required
+ *
+ * @param {String} inputString - Input String to sanitize
+ * @param {Boolean} [trim] - Indicates whether to trim string or not
+ * @returns {String} Sanitized String handling escape characters
+ */
+export function sanitize(inputString: string, trim?: boolean | undefined): string;
+/**
+ * sanitizes input options
+ *
+ * @param {Object} options - Options provided by the user
+ * @param {Array} optionsArray - options array received from getOptions function
+ *
+ * @returns {Object} - Sanitized options object
+ */
+export function sanitizeOptions(options: any, optionsArray: any[]): any;
+/**
+ *
+ * @param {Array} array - form data array
+ * @param {String} key - key of form data param
+ * @param {String} type - type of form data param(file/text)
+ * @param {String} val - value/src property of form data param
+ * @param {String} disabled - Boolean denoting whether the param is disabled or not
+ * @param {String} contentType - content type header of the param
+
+ * Appends a single param to form data array
+ */
+export function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 115 - 0
dist/codegens/csharp-restsharp/lib/util.js

@@ -0,0 +1,115 @@
+"use strict";
+/**
+ * sanitizes input string by handling escape characters eg: converts '''' to '\'\'' and trim input if required
+ *
+ * @param {String} inputString - Input String to sanitize
+ * @param {Boolean} [trim] - Indicates whether to trim string or not
+ * @returns {String} Sanitized String handling escape characters
+ */
+function sanitize(inputString, trim) {
+    /* istanbul ignore next */
+    if (typeof inputString !== 'string') {
+        return '';
+    }
+    inputString = inputString.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+    return trim ? inputString.trim() : inputString;
+}
+/**
+ * sanitizes input options
+ *
+ * @param {Object} options - Options provided by the user
+ * @param {Array} optionsArray - options array received from getOptions function
+ *
+ * @returns {Object} - Sanitized options object
+ */
+function sanitizeOptions(options, optionsArray) {
+    var result = {}, defaultOptions = {}, id;
+    optionsArray.forEach((option) => {
+        defaultOptions[option.id] = {
+            default: option.default,
+            type: option.type
+        };
+        if (option.type === 'enum') {
+            defaultOptions[option.id].availableOptions = option.availableOptions;
+        }
+    });
+    for (id in options) {
+        if (options.hasOwnProperty(id)) {
+            if (defaultOptions[id] === undefined) {
+                continue;
+            }
+            switch (defaultOptions[id].type) {
+                case 'boolean':
+                    if (typeof options[id] !== 'boolean') {
+                        result[id] = defaultOptions[id].default;
+                    }
+                    else {
+                        result[id] = options[id];
+                    }
+                    break;
+                case 'positiveInteger':
+                    if (typeof options[id] !== 'number' || options[id] < 0) {
+                        result[id] = defaultOptions[id].default;
+                    }
+                    else {
+                        result[id] = options[id];
+                    }
+                    break;
+                case 'enum':
+                    if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                        result[id] = defaultOptions[id].default;
+                    }
+                    else {
+                        result[id] = options[id];
+                    }
+                    break;
+                default:
+                    result[id] = options[id];
+            }
+        }
+    }
+    for (id in defaultOptions) {
+        if (defaultOptions.hasOwnProperty(id)) {
+            if (result[id] === undefined) {
+                result[id] = defaultOptions[id].default;
+            }
+        }
+    }
+    return result;
+}
+/**
+ *
+ * @param {Array} array - form data array
+ * @param {String} key - key of form data param
+ * @param {String} type - type of form data param(file/text)
+ * @param {String} val - value/src property of form data param
+ * @param {String} disabled - Boolean denoting whether the param is disabled or not
+ * @param {String} contentType - content type header of the param
+
+ * Appends a single param to form data array
+ */
+function addFormParam(array, key, type, val, disabled, contentType) {
+    if (type === 'file') {
+        array.push({
+            key: key,
+            type: type,
+            src: val,
+            disabled: disabled,
+            contentType: contentType
+        });
+    }
+    else {
+        array.push({
+            key: key,
+            type: type,
+            value: val,
+            disabled: disabled,
+            contentType: contentType
+        });
+    }
+}
+module.exports = {
+    sanitize: sanitize,
+    sanitizeOptions: sanitizeOptions,
+    addFormParam: addFormParam
+};

+ 26 - 0
dist/codegens/curl/index.d.ts

@@ -0,0 +1,26 @@
+declare const _exports: {
+    convert: (request: any, options: any, callback: any) => void;
+    getOptions: () => ({
+        name: string;
+        id: string;
+        type: string;
+        default: boolean;
+        description: string;
+        availableOptions?: undefined;
+    } | {
+        name: string;
+        id: string;
+        availableOptions: string[];
+        type: string;
+        default: string;
+        description: string;
+    } | {
+        name: string;
+        id: string;
+        type: string;
+        default: number;
+        description: string;
+        availableOptions?: undefined;
+    })[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/curl/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 23 - 0
dist/codegens/curl/lib/index.d.ts

@@ -0,0 +1,23 @@
+export declare function convert(request: any, options: any, callback: any): void;
+export declare function getOptions(): ({
+    name: string;
+    id: string;
+    type: string;
+    default: boolean;
+    description: string;
+    availableOptions?: undefined;
+} | {
+    name: string;
+    id: string;
+    availableOptions: string[];
+    type: string;
+    default: string;
+    description: string;
+} | {
+    name: string;
+    id: string;
+    type: string;
+    default: number;
+    description: string;
+    availableOptions?: undefined;
+})[];

+ 229 - 0
dist/codegens/curl/lib/index.js

@@ -0,0 +1,229 @@
+"use strict";
+var sanitize = require('./util').sanitize, sanitizeOptions = require('./util').sanitizeOptions, getUrlStringfromUrlObject = require('./util').getUrlStringfromUrlObject, addFormParam = require('./util').addFormParam, form = require('./util').form, _ = require('../../lodash'), self;
+self = module.exports = {
+    convert: function (request, options, callback) {
+        if (!_.isFunction(callback)) {
+            throw new Error('Curl-Converter: callback is not valid function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        var indent, trim, headersData, body, redirect, timeout, multiLine, format, snippet, silent, url, quoteType;
+        redirect = options.followRedirect;
+        timeout = options.requestTimeout;
+        multiLine = options.multiLine;
+        format = options.longFormat;
+        trim = options.trimRequestBody;
+        silent = options.silent;
+        url = getUrlStringfromUrlObject(request.url);
+        quoteType = options.quoteType === 'single' ? '\'' : '"';
+        snippet = silent ? `curl ${form('-s', format)}` : 'curl';
+        if (redirect) {
+            snippet += ` ${form('-L', format)}`;
+        }
+        if (timeout > 0) {
+            snippet += ` ${form('-m', format)} ${timeout}`;
+        }
+        if ((url.match(/[{[}\]]/g) || []).length > 0) {
+            snippet += ' -g';
+        }
+        if (multiLine) {
+            indent = options.indentType === 'Tab' ? '\t' : ' ';
+            indent = ' ' + options.lineContinuationCharacter + '\n' + indent.repeat(options.indentCount); // eslint-disable-line max-len
+        }
+        else {
+            indent = ' ';
+        }
+        if (request.method === 'HEAD') {
+            snippet += ` ${form('-I', format)} ${quoteType + url + quoteType}`;
+        }
+        else {
+            snippet += ` ${form('-X', format)} ${request.method} ${quoteType + url + quoteType}`;
+        }
+        if (request.body && !request.headers.has('Content-Type')) {
+            if (request.body.mode === 'file') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'text/plain'
+                });
+            }
+            else if (request.body.mode === 'graphql') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'application/json'
+                });
+            }
+        }
+        headersData = request.toJSON().header;
+        if (headersData) {
+            headersData = _.reject(headersData, 'disabled');
+            _.forEach(headersData, (header) => {
+                if (!header.key) {
+                    return;
+                }
+                snippet += indent + `${form('-H', format)} '${sanitize(header.key, true)}`;
+                // If the header value is an empty string then add a semicolon after key
+                // otherwise the header would be ignored by curl
+                if (header.value) {
+                    snippet += `: ${sanitize(header.value)}'`;
+                }
+                else {
+                    snippet += ';\'';
+                }
+            });
+        }
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        if (request.body && request.body.mode === 'formdata') {
+            let formdata = request.body.formdata, formdataArray = [];
+            formdata.members.forEach((param) => {
+                let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                if (type === 'file') {
+                    if (typeof param.src !== 'string') {
+                        if (Array.isArray(param.src) && param.src.length) {
+                            param.src.forEach((filePath) => {
+                                addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                            });
+                        }
+                        else {
+                            addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                        }
+                    }
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                    }
+                }
+                else {
+                    addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                }
+            });
+            request.body.update({
+                mode: 'formdata',
+                formdata: formdataArray
+            });
+        }
+        if (request.body) {
+            body = request.body.toJSON();
+            if (!_.isEmpty(body)) {
+                switch (body.mode) {
+                    case 'urlencoded':
+                        _.forEach(body.urlencoded, function (data) {
+                            if (!data.disabled) {
+                                // Using the long form below without considering the longFormat option,
+                                // to generate more accurate and correct snippet
+                                snippet += indent + '--data-urlencode';
+                                snippet += ` '${sanitize(data.key, trim)}=${sanitize(data.value, trim)}'`;
+                            }
+                        });
+                        break;
+                    case 'raw':
+                        snippet += indent + `--data-raw '${sanitize(body.raw.toString(), trim)}'`;
+                        break;
+                    case 'graphql':
+                        // eslint-disable-next-line no-case-declarations
+                        let query = body.graphql.query, graphqlVariables;
+                        try {
+                            graphqlVariables = JSON.parse(body.graphql.variables);
+                        }
+                        catch (e) {
+                            graphqlVariables = {};
+                        }
+                        snippet += indent + `--data-raw '${sanitize(JSON.stringify({
+                            query: query,
+                            variables: graphqlVariables
+                        }), trim)}'`;
+                        break;
+                    case 'formdata':
+                        _.forEach(body.formdata, function (data) {
+                            if (!(data.disabled)) {
+                                if (data.type === 'file') {
+                                    snippet += indent + `${form('-F', format)}`;
+                                    snippet += ` '${sanitize(data.key, trim)}=@"${sanitize(data.src, trim, true, true)}"'`;
+                                }
+                                else {
+                                    snippet += indent + `${form('-F', format)}`;
+                                    snippet += ` '${sanitize(data.key, trim)}="${sanitize(data.value, trim, true, true)}"`;
+                                    if (data.contentType) {
+                                        snippet += `;type=${data.contentType}`;
+                                    }
+                                    snippet += '\'';
+                                }
+                            }
+                        });
+                        break;
+                    case 'file':
+                        snippet += indent + '--data-binary';
+                        snippet += ` '@${sanitize(body[body.mode].src, trim)}'`;
+                        break;
+                    default:
+                        snippet += `${form('-d', format)} ''`;
+                }
+            }
+        }
+        callback(null, snippet);
+    },
+    getOptions: function () {
+        return [
+            {
+                name: 'Generate multiline snippet',
+                id: 'multiLine',
+                type: 'boolean',
+                default: true,
+                description: 'Split cURL command across multiple lines'
+            },
+            {
+                name: 'Use long form options',
+                id: 'longFormat',
+                type: 'boolean',
+                default: true,
+                description: 'Use the long form for cURL options (--header instead of -H)'
+            },
+            {
+                name: 'Line continuation character',
+                id: 'lineContinuationCharacter',
+                availableOptions: ['\\', '^', '`'],
+                type: 'enum',
+                default: '\\',
+                description: 'Set a character used to mark the continuation of a statement on the next line ' +
+                    '(generally, \\ for OSX/Linux, ^ for Windows cmd and ` for Powershell)'
+            },
+            {
+                name: 'Quote Type',
+                id: 'quoteType',
+                availableOptions: ['single', 'double'],
+                type: 'enum',
+                default: 'single',
+                description: 'String denoting the quote type to use (single or double) for URL ' +
+                    '(Use double quotes when running curl in cmd.exe and single quotes for the rest)'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response before ' +
+                    'timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            },
+            {
+                name: 'Use Silent Mode',
+                id: 'silent',
+                type: 'boolean',
+                default: false,
+                description: 'Display the requested data without showing the cURL progress meter or error messages'
+            }
+        ];
+    }
+};

+ 5 - 0
dist/codegens/curl/lib/util.d.ts

@@ -0,0 +1,5 @@
+export declare function sanitize(inputString: string, trim?: boolean | undefined, doubleQuotes?: boolean | undefined, backSlash?: boolean | undefined): string;
+export declare function form(option: any, format: any): any;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function getUrlStringfromUrlObject(urlObject: any): string;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 187 - 0
dist/codegens/curl/lib/util.js

@@ -0,0 +1,187 @@
+"use strict";
+var self = module.exports = {
+    /**
+       * sanitizes input string by handling escape characters eg: converts '''' to '\'\'', (" to \"  and \ to \\ )
+       * and trim input if required
+       *
+       * @param {String} inputString
+       * @param {Boolean} [trim] - indicates whether to trim string or not
+       * @param {Boolean} [doubleQuotes] - indicates whether to escape double quotes(") and backslash(\\)
+       * @param {Boolean} [backSlash] - indicates whether to escape backslash(\\)
+       * @returns {String}
+       */
+    sanitize: function (inputString, trim, doubleQuotes, backSlash) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        if (backSlash) {
+            inputString = inputString.replace(/\\/g, '\\\\');
+        }
+        if (doubleQuotes) {
+            inputString = inputString.replace(/"/g, '\\"');
+        }
+        // for curl escaping of single quotes inside single quotes involves changing of ' to '\''
+        inputString = inputString.replace(/'/g, "'\\''"); // eslint-disable-line quotes
+        return trim ? inputString.trim() : inputString;
+    },
+    form: function (option, format) {
+        if (format) {
+            switch (option) {
+                case '-s':
+                    return '--silent';
+                case '-L':
+                    return '--location';
+                case '-m':
+                    return '--max-time';
+                case '-I':
+                    return '--head';
+                case '-X':
+                    return '--request';
+                case '-H':
+                    return '--header';
+                case '-d':
+                    return '--data';
+                case '-F':
+                    return '--form';
+                default:
+                    return '';
+            }
+        }
+        else {
+            return option;
+        }
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {*} urlObject The request sdk request.url object
+   * @returns {String} The final string after parsing all the parameters of the url including
+   * protocol, auth, host, port, path, query, hash
+   * This will be used because the url.toString() method returned the URL with non encoded query string
+   * and hence a manual call is made to getQueryString() method with encode option set as true.
+   */
+    getUrlStringfromUrlObject: function (urlObject) {
+        var url = '';
+        if (!urlObject) {
+            return url;
+        }
+        if (urlObject.protocol) {
+            url += (urlObject.protocol.endsWith('://') ? urlObject.protocol : urlObject.protocol + '://');
+        }
+        if (urlObject.auth && urlObject.auth.user) {
+            url = url + ((urlObject.auth.password) ?
+                // ==> username:password@
+                urlObject.auth.user + ':' + urlObject.auth.password : urlObject.auth.user) + '@';
+        }
+        if (urlObject.host) {
+            url += urlObject.getHost();
+        }
+        if (urlObject.port) {
+            url += ':' + urlObject.port.toString();
+        }
+        if (urlObject.path) {
+            url += urlObject.getPath();
+        }
+        if (urlObject.query && urlObject.query.count()) {
+            let queryString = urlObject.getQueryString({ ignoreDisabled: true, encode: true });
+            queryString && (url += '?' + queryString);
+        }
+        if (urlObject.hash) {
+            url += '#' + urlObject.hash;
+        }
+        return self.sanitize(url);
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 26 - 0
dist/codegens/golang/index.d.ts

@@ -0,0 +1,26 @@
+declare const _exports: {
+    convert: (request: any, options: any, callback: any) => void;
+    getOptions: () => ({
+        name: string;
+        id: string;
+        type: string;
+        default: number;
+        description: string;
+        availableOptions?: undefined;
+    } | {
+        name: string;
+        id: string;
+        type: string;
+        availableOptions: string[];
+        default: string;
+        description: string;
+    } | {
+        name: string;
+        id: string;
+        type: string;
+        default: boolean;
+        description: string;
+        availableOptions?: undefined;
+    })[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/golang/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 23 - 0
dist/codegens/golang/lib/index.d.ts

@@ -0,0 +1,23 @@
+export declare function convert(request: any, options: any, callback: any): void;
+export declare function getOptions(): ({
+    name: string;
+    id: string;
+    type: string;
+    default: number;
+    description: string;
+    availableOptions?: undefined;
+} | {
+    name: string;
+    id: string;
+    type: string;
+    availableOptions: string[];
+    default: string;
+    description: string;
+} | {
+    name: string;
+    id: string;
+    type: string;
+    default: boolean;
+    description: string;
+    availableOptions?: undefined;
+})[];

+ 313 - 0
dist/codegens/golang/lib/index.js

@@ -0,0 +1,313 @@
+"use strict";
+var _ = require('../../lodash'), sanitize = require('./util').sanitize, sanitizeMultiline = require('./util').sanitizeMultiline, sanitizeOptions = require('./util').sanitizeOptions, addFormParam = require('./util').addFormParam, isFile = false, self;
+/**
+ * Parses Raw data to fetch syntax
+ *
+ * @param {Object} body Raw body data
+ * @param {boolean} trim trim body option
+ */
+function parseRawBody(body, trim) {
+    var bodySnippet;
+    bodySnippet = `payload := strings.NewReader(\`${sanitizeMultiline(body.toString(), trim)}\`)`;
+    return bodySnippet;
+}
+/**
+ * Parses graphql data to golang syntax
+ *
+ * @param {Object} body Raw body data
+ * @param {boolean} trim trim body option
+ */
+function parseGraphQL(body, trim) {
+    let query = body.query, graphqlVariables, bodySnippet;
+    try {
+        graphqlVariables = JSON.parse(body.variables);
+    }
+    catch (e) {
+        graphqlVariables = {};
+    }
+    bodySnippet = `payload := strings.NewReader("${sanitize(JSON.stringify({
+        query: query,
+        variables: graphqlVariables
+    }), trim)}")`;
+    return bodySnippet;
+}
+/**
+ * Parses URLEncoded body from request to fetch syntax
+ *
+ * @param {Object} body URLEncoded Body
+ * @param {boolean} trim trim body option
+ */
+function parseURLEncodedBody(body, trim) {
+    var payload, bodySnippet;
+    payload = _.reduce(body, function (accumulator, data) {
+        if (!data.disabled) {
+            accumulator.push(`${encodeURIComponent(data.key, trim)}=${encodeURIComponent(data.value, trim)}`);
+        }
+        return accumulator;
+    }, []).join('&');
+    bodySnippet = `payload := strings.NewReader("${payload}")`;
+    return bodySnippet;
+}
+/**
+ * Parses formData body from request to fetch syntax
+ *
+ * @param {Object} body formData Body
+ * @param {boolean} trim trim body option
+ * @param {string} indent indent string
+ */
+function parseFormData(body, trim, indent) {
+    var bodySnippet = `payload := &bytes.Buffer{}\n${indent}writer := multipart.NewWriter(payload)\n`;
+    _.forEach(body, function (data, index) {
+        if (!data.disabled) {
+            if (data.type === 'file') {
+                isFile = true;
+                bodySnippet += `${indent}file, errFile${index + 1} := os.Open("${data.src}")\n`;
+                bodySnippet += `${indent}defer file.Close()\n`;
+                bodySnippet += `${indent}part${index + 1},
+         errFile${index + 1} := writer.CreateFormFile("${sanitize(data.key, trim)}",` +
+                    `filepath.Base("${data.src}"))\n`;
+                bodySnippet += `${indent}_, errFile${index + 1} = io.Copy(part${index + 1}, file)\n`;
+                bodySnippet += `${indent}if errFile${index + 1} != nil {` +
+                    `\n${indent.repeat(2)}fmt.Println(errFile${index + 1})\n` +
+                    `${indent.repeat(2)}return\n${indent}}\n`;
+            }
+            else if (data.contentType) {
+                bodySnippet += `\n${indent}mimeHeader${index + 1} := make(map[string][]string)\n`;
+                bodySnippet += `${indent}mimeHeader${index + 1}["Content-Disposition"] = `;
+                bodySnippet += `append(mimeHeader${index + 1}["Content-Disposition"], "form-data; `;
+                bodySnippet += `name=\\"${sanitize(data.key, trim)}\\"")\n`;
+                bodySnippet += `${indent}mimeHeader${index + 1}["Content-Type"] = append(`;
+                bodySnippet += `mimeHeader${index + 1}["Content-Type"], "${data.contentType}")\n`;
+                bodySnippet += `${indent}fieldWriter${index + 1}, _ := writer.CreatePart(mimeHeader${index + 1})\n`;
+                bodySnippet += `${indent}fieldWriter${index + 1}.Write([]byte("${sanitize(data.value, trim)}"))\n\n`;
+            }
+            else {
+                bodySnippet += `${indent}_ = writer.WriteField("${sanitize(data.key, trim)}",`;
+                bodySnippet += ` "${sanitize(data.value, trim)}")\n`;
+            }
+        }
+    });
+    bodySnippet += `${indent}err := writer.Close()\n${indent}if err != nil ` +
+        `{\n${indent.repeat(2)}fmt.Println(err)\n` +
+        `${indent.repeat(2)}return\n${indent}}\n`;
+    return bodySnippet;
+}
+/**
+ * Parses file body from the Request
+ *
+ */
+function parseFile() {
+    // var bodySnippet = `payload := &bytes.Buffer{}\n${indent}writer := multipart.NewWriter(payload)\n`;
+    // isFile = true;
+    // bodySnippet += `${indent}// add your file name in the next statement in place of path\n`;
+    // bodySnippet += `${indent}file, err := os.Open(path)\n`;
+    // bodySnippet += `${indent}defer file.Close()\n`;
+    // bodySnippet += `${indent}part, err := writer.CreateFormFile("file", filepath.Base(path))\n`;
+    // bodySnippet += `${indent}_, err := io.Copy(part, file)\n`;
+    // bodySnippet += `${indent}err := writer.Close()\n${indent}if err != nil {${indent}fmt.Println(err)}\n`;
+    var bodySnippet = 'payload := strings.NewReader("<file contents here>")\n';
+    return bodySnippet;
+}
+/**
+ * Parses Body from the Request
+ *
+ * @param {Object} body body object from request.
+ * @param {boolean} trim trim body option
+ * @param {string} indent indent string
+ */
+function parseBody(body, trim, indent) {
+    if (!_.isEmpty(body)) {
+        switch (body.mode) {
+            case 'urlencoded':
+                return parseURLEncodedBody(body.urlencoded, trim);
+            case 'raw':
+                return parseRawBody(body.raw, trim);
+            case 'graphql':
+                return parseGraphQL(body.graphql, trim);
+            case 'formdata':
+                return parseFormData(body.formdata, trim, indent);
+            case 'file':
+                return parseFile(body.file, trim, indent);
+            default:
+                return '';
+        }
+    }
+    return '';
+}
+/**
+ * Parses headers from the request.
+ *
+ * @param {Object} headers headers from the request.
+ * @param {string} indent indent string
+ */
+function parseHeaders(headers, indent) {
+    var headerSnippet = '';
+    if (!_.isEmpty(headers)) {
+        headers = _.reject(headers, 'disabled');
+        _.forEach(headers, function (header) {
+            headerSnippet += `${indent}req.Header.Add("${sanitize(header.key, true)}", "${sanitize(header.value)}")\n`;
+        });
+    }
+    return headerSnippet;
+}
+self = module.exports = {
+    convert: function (request, options, callback) {
+        if (!_.isFunction(callback)) {
+            throw new Error('GoLang-Converter: callback is not valid function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        var codeSnippet, indent, trim, timeout, followRedirect, bodySnippet = '', responseSnippet = '', headerSnippet = '';
+        indent = options.indentType === 'Tab' ? '\t' : ' ';
+        indent = indent.repeat(options.indentCount);
+        timeout = options.requestTimeout;
+        followRedirect = options.followRedirect;
+        trim = options.trimRequestBody;
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        if (request.body && request.body.mode === 'formdata') {
+            let formdata = request.body.formdata, formdataArray = [];
+            formdata.members.forEach((param) => {
+                let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                if (type === 'file') {
+                    if (typeof param.src !== 'string') {
+                        if (Array.isArray(param.src) && param.src.length) {
+                            param.src.forEach((filePath) => {
+                                addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                            });
+                        }
+                        else {
+                            addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                        }
+                    }
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                    }
+                }
+                else {
+                    addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                }
+            });
+            request.body.update({
+                mode: 'formdata',
+                formdata: formdataArray
+            });
+        }
+        if (request.body) {
+            bodySnippet = parseBody(request.body.toJSON(), trim, indent);
+        }
+        codeSnippet = 'package main\n\n';
+        codeSnippet += `import (\n${indent}"fmt"\n`;
+        if (timeout > 0) {
+            codeSnippet += `${indent}"time"\n`;
+        }
+        if (request.body && request.body.toJSON().mode === 'formdata') {
+            codeSnippet += `${indent}"bytes"\n${indent}"mime/multipart"\n`;
+        }
+        else if (bodySnippet !== '') {
+            codeSnippet += `${indent}"strings"\n`;
+        }
+        if (isFile) {
+            codeSnippet += `${indent}"os"\n${indent}"path/filepath"\n`;
+            codeSnippet += `${indent}"io"\n`;
+            // Setting isFile as false for further calls to this function
+            isFile = false;
+        }
+        codeSnippet += `${indent}"net/http"\n${indent}"io/ioutil"\n)\n\n`;
+        codeSnippet += `func main() {\n${indent}url := "${encodeURI(request.url.toString())}"\n`;
+        codeSnippet += `${indent}method := "${request.method}"\n\n`;
+        if (bodySnippet !== '') {
+            codeSnippet += indent + bodySnippet + '\n\n';
+        }
+        if (timeout > 0) {
+            codeSnippet += `${indent}timeout := time.Duration(${timeout / 1000} * time.Second)\n`;
+        }
+        codeSnippet += indent + 'client := &http.Client {\n';
+        if (!followRedirect) {
+            codeSnippet += indent.repeat(2) + 'CheckRedirect: func(req *http.Request, via []*http.Request) ';
+            codeSnippet += 'error {\n';
+            codeSnippet += `${indent.repeat(3)}return http.ErrUseLastResponse\n${indent.repeat(2)}},\n`;
+        }
+        if (timeout > 0) {
+            codeSnippet += indent.repeat(2) + 'Timeout: timeout,\n';
+        }
+        codeSnippet += indent + '}\n';
+        if (bodySnippet !== '') {
+            codeSnippet += `${indent}req, err := http.NewRequest(method, url, payload)\n\n`;
+        }
+        else {
+            codeSnippet += `${indent}req, err := http.NewRequest(method, url, nil)\n\n`;
+        }
+        codeSnippet += `${indent}if err != nil {\n${indent.repeat(2)}fmt.Println(err)\n`;
+        codeSnippet += `${indent.repeat(2)}return\n${indent}}\n`;
+        if (request.body && !request.headers.has('Content-Type')) {
+            if (request.body.mode === 'file') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'text/plain'
+                });
+            }
+            else if (request.body.mode === 'graphql') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'application/json'
+                });
+            }
+        }
+        headerSnippet = parseHeaders(request.toJSON().header, indent);
+        if (headerSnippet !== '') {
+            codeSnippet += headerSnippet + '\n';
+        }
+        if (request.body && (request.body.toJSON().mode === 'formdata')) {
+            codeSnippet += `${indent}req.Header.Set("Content-Type", writer.FormDataContentType())\n`;
+        }
+        responseSnippet = `${indent}res, err := client.Do(req)\n`;
+        responseSnippet += `${indent}if err != nil {\n${indent.repeat(2)}fmt.Println(err)\n`;
+        responseSnippet += `${indent.repeat(2)}return\n${indent}}\n`;
+        responseSnippet += `${indent}defer res.Body.Close()\n\n${indent}body, err := ioutil.ReadAll(res.Body)\n`;
+        responseSnippet += `${indent}if err != nil {\n${indent.repeat(2)}fmt.Println(err)\n`;
+        responseSnippet += `${indent.repeat(2)}return\n${indent}}\n`;
+        responseSnippet += `${indent}fmt.Println(string(body))\n}`;
+        codeSnippet += responseSnippet;
+        callback(null, codeSnippet);
+    },
+    getOptions: function () {
+        return [{
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                availableOptions: ['Tab', 'Space'],
+                default: 'Space',
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a ' +
+                    'response before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            }];
+    }
+};

+ 4 - 0
dist/codegens/golang/lib/util.d.ts

@@ -0,0 +1,4 @@
+export declare function sanitize(inputString: string, trim?: boolean | undefined): string;
+export declare function sanitizeMultiline(inputString: string, trim?: boolean | undefined): string;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 132 - 0
dist/codegens/golang/lib/util.js

@@ -0,0 +1,132 @@
+"use strict";
+module.exports = {
+    /**
+       * sanitizes input string by handling escape characters eg: converts '''' to '\'\''
+       * and trim input if required
+       *
+       * @param {String} inputString
+       * @param {Boolean} [trim] - indicates whether to trim string or not
+       * @returns {String}
+       */
+    sanitize: function (inputString, trim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        inputString = inputString.replace(/\\/g, '\\\\')
+            .replace(/"/g, '\\"')
+            .replace(/\n/g, '\\n')
+            .replace(/\r/g, '\\r');
+        return trim ? inputString.trim() : inputString;
+    },
+    /**
+       * sanitizes input string by handling escape characters eg: converts '''' to '\'\''
+       * and trim input if required
+       *
+       * @param {String} inputString
+       * @param {Boolean} [trim] - indicates whether to trim string or not
+       * @returns {String}
+       */
+    sanitizeMultiline: function (inputString, trim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        inputString = inputString
+            .replace(/`/g, '`+"`"+`')
+            .replace(/\r/g, '`+"\r"+`'); // Go discards \r from raw strings, so manually keep them
+        return trim ? inputString.trim() : inputString;
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 21 - 0
dist/codegens/index.d.ts

@@ -0,0 +1,21 @@
+export declare type Lang = 'csharp' | 'curl' | 'golang' | 'java' | 'php' | 'python' | 'ruby' | 'nodejs';
+export declare type BodyMode = 'file' | 'formdata' | 'raw' | 'urlencoded';
+export interface ConvertOptions {
+    url: string;
+    method: string;
+    header?: any[];
+    body?: {
+        mode?: BodyMode;
+        raw?: string;
+        urlencoded?: {
+            key: string;
+            value: string;
+        }[];
+        formdata?: {
+            key: string;
+            value: any;
+            type: 'file' | 'text';
+        }[];
+    };
+}
+export declare const convert: (lang: Lang, opts: ConvertOptions) => Promise<string>;

+ 39 - 0
dist/codegens/index.js

@@ -0,0 +1,39 @@
+import csharp from './csharp-restsharp';
+import curl from './curl';
+import golang from './golang';
+import java from './java-okhttp';
+import php from './php-curl';
+import python from './python-http.client';
+import ruby from './ruby';
+import nodejs from './nodejs-native';
+import { Request } from './postman-collection-lite';
+const langMap = {
+    csharp,
+    curl,
+    golang,
+    java,
+    php,
+    python,
+    ruby,
+    nodejs,
+};
+export const convert = (lang, opts) => {
+    return new Promise((resolve, reject) => {
+        langMap[lang].convert(new Request(opts), {
+            indentCount: 2,
+            indentType: 'Space',
+            trimRequestBody: true,
+            followRedirect: false,
+            ES6_enabled: true,
+            includeBoilerplate: true,
+            longFormat: false,
+        }, (e, snippet) => {
+            if (e) {
+                reject(e);
+            }
+            else {
+                resolve(snippet);
+            }
+        });
+    });
+};

+ 12 - 0
dist/codegens/java-okhttp/index.d.ts

@@ -0,0 +1,12 @@
+declare const _exports: {
+    convert: (request: any, options: {
+        indentType: string;
+        indentCount: string;
+        includeBoilerplate?: boolean;
+        followRedirect: boolean;
+        trimRequestBody: boolean;
+        requestTimeout: number;
+    }, callback: Function) => any;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/java-okhttp/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 9 - 0
dist/codegens/java-okhttp/lib/index.d.ts

@@ -0,0 +1,9 @@
+export declare const convert: (request: any, options: {
+    indentType: string;
+    indentCount: string;
+    includeBoilerplate?: boolean;
+    followRedirect: boolean;
+    trimRequestBody: boolean;
+    requestTimeout: number;
+}, callback: Function) => any;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/java-okhttp/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./okhttp').convert,
+    getOptions: require('./okhttp').getOptions
+};

+ 31 - 0
dist/codegens/java-okhttp/lib/okhttp.d.ts

@@ -0,0 +1,31 @@
+/**
+ * Converts Postman sdk request object to java okhttp code snippet
+ *
+ * @module convert
+ *
+ * @param {Object} request - postman-SDK request object
+ * @param {Object} options - Options to tweak code snippet generated in Java-OkHttp
+ * @param {String} options.indentType - type for indentation eg: Space, Tab
+ * @param {String} options.indentCount - number of spaces or tabs for indentation.
+ * @param {Boolean} [options.includeBoilerplate] - indicates whether to include class definition in java
+ * @param {Boolean} options.followRedirect - whether to enable followredirect
+ * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not
+ * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+ * @param {Function} callback - callback function with parameters (error, snippet)
+ */
+export function convert(request: any, options: {
+    indentType: string;
+    indentCount: string;
+    includeBoilerplate: boolean;
+    followRedirect: boolean;
+    trimRequestBody: boolean;
+    requestTimeout: number;
+}, callback: Function): any;
+/**
+ * Used in order to get options for generation of Java okhattp code snippet (i.e. Include Boilerplate code)
+ *
+ * @module getOptions
+ *
+ * @returns {Array} Options specific to generation of Java okhattp code snippet
+ */
+export function getOptions(): any[];

+ 178 - 0
dist/codegens/java-okhttp/lib/okhttp.js

@@ -0,0 +1,178 @@
+"use strict";
+var _ = require('../../lodash'), parseRequest = require('./parseRequest'), sanitize = require('./util').sanitize, addFormParam = require('./util').addFormParam, sanitizeOptions = require('./util').sanitizeOptions;
+//  Since Java OkHttp requires to add extralines of code to handle methods with body
+const METHODS_WITHOUT_BODY = ['GET', 'HEAD', 'COPY', 'UNLOCK', 'UNLINK', 'PURGE', 'LINK', 'VIEW'];
+/**
+ * returns snippet of java okhttp by parsing data from Postman-SDK request object
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation required for code snippet
+ * @param {Object} options - Options to tweak code snippet
+ * @returns {String} - java okhttp code snippet for given request object
+ */
+function makeSnippet(request, indentString, options) {
+    var isBodyRequired = !(_.includes(METHODS_WITHOUT_BODY, request.method)), snippet = 'OkHttpClient client = new OkHttpClient().newBuilder()\n', requestBody;
+    if (options.requestTimeout > 0) {
+        snippet += indentString + `.setConnectTimeout(${options.requestTimeout}, TimeUnit.MILLISECONDS)\n`;
+    }
+    if (!options.followRedirect) {
+        snippet += indentString + '.followRedirects(false)\n';
+    }
+    snippet += indentString + '.build();\n';
+    if (isBodyRequired) {
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        if (request.body && request.body.mode === 'formdata') {
+            let formdata = request.body.formdata, formdataArray = [];
+            formdata.members.forEach((param) => {
+                let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                if (type === 'file') {
+                    if (typeof param.src !== 'string') {
+                        if (Array.isArray(param.src) && param.src.length) {
+                            param.src.forEach((filePath) => {
+                                addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                            });
+                        }
+                        else {
+                            addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                        }
+                    }
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                    }
+                }
+                else {
+                    addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                }
+            });
+            request.body.update({
+                mode: 'formdata',
+                formdata: formdataArray
+            });
+        }
+        requestBody = (request.body ? request.body.toJSON() : {});
+        //  snippet for creating mediatype object in java based on content-type of request
+        snippet += `MediaType mediaType = MediaType.parse("${parseRequest.parseContentType(request)}");\n`;
+        snippet += parseRequest.parseBody(requestBody, indentString, options.trimRequestBody);
+    }
+    snippet += 'Request request = new Request.Builder()\n';
+    snippet += indentString + `.url("${sanitize(request.url.toString())}")\n`;
+    snippet += indentString + `.method("${request.method}", ${isBodyRequired ? 'body' : 'null'})\n`;
+    if (request.body && request.body.mode === 'graphql' && !request.headers.has('Content-Type')) {
+        request.addHeader({
+            key: 'Content-Type',
+            value: 'application/json'
+        });
+    }
+    //  java-okhttp snippet for adding headers to request
+    snippet += parseRequest.parseHeader(request, indentString);
+    snippet += indentString + '.build();\n';
+    snippet += 'Response response = client.newCall(request).execute();';
+    return snippet;
+}
+/**
+ * Used in order to get options for generation of Java okhattp code snippet (i.e. Include Boilerplate code)
+ *
+ * @module getOptions
+ *
+ * @returns {Array} Options specific to generation of Java okhattp code snippet
+ */
+function getOptions() {
+    return [
+        {
+            name: 'Include boilerplate',
+            id: 'includeBoilerplate',
+            type: 'boolean',
+            default: false,
+            description: 'Include class definition and import statements in snippet'
+        },
+        {
+            name: 'Set indentation count',
+            id: 'indentCount',
+            type: 'positiveInteger',
+            default: 2,
+            description: 'Set the number of indentation characters to add per code level'
+        },
+        {
+            name: 'Set indentation type',
+            id: 'indentType',
+            type: 'enum',
+            availableOptions: ['Tab', 'Space'],
+            default: 'Space',
+            description: 'Select the character used to indent lines of code'
+        },
+        {
+            name: 'Set request timeout',
+            id: 'requestTimeout',
+            type: 'positiveInteger',
+            default: 0,
+            description: 'Set number of milliseconds the request should wait for a response ' +
+                'before timing out (use 0 for infinity)'
+        },
+        {
+            name: 'Follow redirects',
+            id: 'followRedirect',
+            type: 'boolean',
+            default: true,
+            description: 'Automatically follow HTTP redirects'
+        },
+        {
+            name: 'Trim request body fields',
+            id: 'trimRequestBody',
+            type: 'boolean',
+            default: false,
+            description: 'Remove white space and additional lines that may affect the server\'s response'
+        }
+    ];
+}
+/**
+ * Converts Postman sdk request object to java okhttp code snippet
+ *
+ * @module convert
+ *
+ * @param {Object} request - postman-SDK request object
+ * @param {Object} options - Options to tweak code snippet generated in Java-OkHttp
+ * @param {String} options.indentType - type for indentation eg: Space, Tab
+ * @param {String} options.indentCount - number of spaces or tabs for indentation.
+ * @param {Boolean} [options.includeBoilerplate] - indicates whether to include class definition in java
+ * @param {Boolean} options.followRedirect - whether to enable followredirect
+ * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not
+ * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+ * @param {Function} callback - callback function with parameters (error, snippet)
+ */
+function convert(request, options, callback) {
+    if (_.isFunction(options)) {
+        callback = options;
+        options = {};
+    }
+    else if (!_.isFunction(callback)) {
+        throw new Error('Java-OkHttp-Converter: callback is not valid function');
+    }
+    options = sanitizeOptions(options, getOptions());
+    //  String representing value of indentation required
+    var indentString, 
+    //  snippets to include java class definition according to options
+    headerSnippet = '', footerSnippet = '', 
+    //  snippet to create request in java okhttp
+    snippet = '';
+    indentString = options.indentType === 'Tab' ? '\t' : ' ';
+    indentString = indentString.repeat(options.indentCount);
+    if (options.includeBoilerplate) {
+        headerSnippet = 'import java.io.*;\n' +
+            'import okhttp3.*;\n\n' +
+            'public class main {\n' +
+            indentString + 'public static void main(String []args) throws IOException{\n';
+        footerSnippet = indentString.repeat(2) + 'System.out.println(response.body().string());\n' +
+            indentString + '}\n}\n';
+    }
+    snippet = makeSnippet(request, indentString, options);
+    //  if boilerplate is included then two more indentString needs to be added in snippet
+    (options.includeBoilerplate) &&
+        (snippet = indentString.repeat(2) + snippet.split('\n').join('\n' + indentString.repeat(2)) + '\n');
+    return callback(null, headerSnippet + snippet + footerSnippet);
+}
+module.exports = {
+    convert: convert,
+    getOptions: getOptions
+};

+ 24 - 0
dist/codegens/java-okhttp/lib/parseRequest.d.ts

@@ -0,0 +1,24 @@
+/**
+ * parses request object and returns java okhttp code snippet for adding request body
+ *
+ * @param {Object} requestBody - JSON object representing body of request
+ * @param {String} indentString - string for indentation
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} - code snippet of java okhttp parsed from request object
+ */
+export function parseBody(requestBody: any, indentString: string, trimFields: boolean): string;
+/**
+ * Parses header in Postman-SDK request and returns code snippet of java okhttp for adding headers
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation for code snippet
+ * @returns {String} - code snippet for adding headers in java-okhttp
+ */
+export function parseHeader(request: any, indentString: string): string;
+/**
+ * returns content-type of request body if available else returns text/plain as default
+ *
+ * @param {Object} request - Postman SDK request object
+ * @returns {String}- content-type of request body
+ */
+export function parseContentType(request: any): string;

+ 139 - 0
dist/codegens/java-okhttp/lib/parseRequest.js

@@ -0,0 +1,139 @@
+"use strict";
+var _ = require('../../lodash'), sanitize = require('./util').sanitize, path = require('path');
+/**
+ * parses body of request and returns urlencoded string
+ *
+ * @param {Object} requestBody - json object respresenting body of request
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} - urlencoded string for request body
+ */
+function parseUrlencode(requestBody, trimFields) {
+    //  reducing array of urlencoded form data to array of strings
+    return _.reduce(requestBody[requestBody.mode], function (accumalator, data) {
+        if (!data.disabled) {
+            accumalator.push(`${sanitize(data.key, trimFields)}=${sanitize(data.value, trimFields)}`.replace(/&/g, '%26'));
+        }
+        return accumalator;
+    }, []).join('&');
+}
+/**
+ * parses body of request and creates java okhttp code snippet for adding form data
+ *
+ * @param {Object} requestBody - JSON object representing body of request
+ * @param {String} indentString - string for indentation
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} - code snippet of java okhttp for multipart formdata
+ */
+function parseFormData(requestBody, indentString, trimFields) {
+    return _.reduce(requestBody[requestBody.mode], function (body, data) {
+        if (data.disabled) {
+            return body;
+        }
+        /* istanbul ignore next */
+        if (data.type === 'file') {
+            var pathArray = data.src.split(path.sep), fileName = pathArray[pathArray.length - 1];
+            body += indentString + '.addFormDataPart' +
+                `("${sanitize(data.key, trimFields)}","${sanitize(fileName, trimFields)}",\n` +
+                indentString.repeat(2) + 'RequestBody.create(MediaType.parse("application/octet-stream"),\n' +
+                indentString.repeat(2) + `new File("${sanitize(data.src)}")))\n`;
+        }
+        else {
+            !data.value && (data.value = '');
+            body += `${indentString}.addFormDataPart("${sanitize(data.key, trimFields)}",`;
+            if (data.contentType) {
+                body += ` null,\n${indentString.repeat(2)} RequestBody.create(MediaType.parse("${data.contentType}"),`;
+                body += ` "${sanitize(data.value, trimFields)}".getBytes()))\n`;
+            }
+            else {
+                body += `"${sanitize(data.value, trimFields)}")\n`;
+            }
+        }
+        return body;
+    }, '') + indentString + '.build()';
+}
+/**
+ * parses request object and returns java okhttp code snippet for adding request body
+ *
+ * @param {Object} requestBody - JSON object representing body of request
+ * @param {String} indentString - string for indentation
+ * @param {Boolean} trimFields - indicates whether to trim fields of body
+ * @returns {String} - code snippet of java okhttp parsed from request object
+ */
+function parseBody(requestBody, indentString, trimFields) {
+    if (!_.isEmpty(requestBody)) {
+        switch (requestBody.mode) {
+            case 'urlencoded':
+                return 'RequestBody body = RequestBody.create(mediaType, ' +
+                    `"${parseUrlencode(requestBody, trimFields)}");\n`;
+            case 'raw':
+                return 'RequestBody body = RequestBody.create(mediaType, ' +
+                    `${JSON.stringify(requestBody[requestBody.mode])});\n`;
+            case 'graphql':
+                // eslint-disable-next-line no-case-declarations
+                let query = requestBody[requestBody.mode].query, graphqlVariables;
+                try {
+                    graphqlVariables = JSON.parse(requestBody[requestBody.mode].variables);
+                }
+                catch (e) {
+                    graphqlVariables = {};
+                }
+                return 'RequestBody body = RequestBody.create(mediaType, ' +
+                    `"${sanitize(JSON.stringify({
+                        query: query,
+                        variables: graphqlVariables
+                    }), trimFields)}");\n`;
+            case 'formdata':
+                return requestBody.formdata.length ?
+                    'RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)\n' +
+                        `${parseFormData(requestBody, indentString, trimFields)};\n` :
+                    'MediaType JSON = MediaType.parse("application/json; charset=utf-8");\n' +
+                        'RequestBody body = RequestBody.create(JSON, "{}");\n';
+            /* istanbul ignore next */
+            case 'file':
+                // return 'RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)\n' +
+                //                 indentString + `.addFormDataPart("file", "${requestBody[requestBody.mode].src}",\n` +
+                //                 indentString + 'RequestBody.create(MediaType.parse("application/octet-stream"),\n' +
+                //                 indentString + `new File("${requestBody[requestBody.mode].src}"))).build();\n`;
+                return 'RequestBody body = RequestBody.create(mediaType, "<file contents here>");\n';
+            default:
+                return 'RequestBody body = RequestBody.create(mediaType, "");\n';
+        }
+    }
+    return 'RequestBody body = RequestBody.create(mediaType, "");\n';
+}
+/**
+ * Parses header in Postman-SDK request and returns code snippet of java okhttp for adding headers
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation for code snippet
+ * @returns {String} - code snippet for adding headers in java-okhttp
+ */
+function parseHeader(request, indentString) {
+    var headerArray = request.toJSON().header, headerSnippet = '';
+    if (!_.isEmpty(headerArray)) {
+        headerArray = _.reject(headerArray, 'disabled');
+        headerSnippet += _.reduce(headerArray, function (accumalator, header) {
+            accumalator += indentString + `.addHeader("${sanitize(header.key, true)}", ` +
+                `"${sanitize(header.value)}")\n`;
+            return accumalator;
+        }, '');
+    }
+    return headerSnippet;
+}
+/**
+ * returns content-type of request body if available else returns text/plain as default
+ *
+ * @param {Object} request - Postman SDK request object
+ * @returns {String}- content-type of request body
+ */
+function parseContentType(request) {
+    if (request.body && request.body.mode === 'graphql') {
+        return 'application/json';
+    }
+    return request.getHeaders({ enabled: true, ignoreCase: true })['content-type'] || 'text/plain';
+}
+module.exports = {
+    parseBody: parseBody,
+    parseHeader: parseHeader,
+    parseContentType: parseContentType
+};

+ 3 - 0
dist/codegens/java-okhttp/lib/util.d.ts

@@ -0,0 +1,3 @@
+export declare function sanitize(inputString: string, trim?: boolean | undefined): string;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 112 - 0
dist/codegens/java-okhttp/lib/util.js

@@ -0,0 +1,112 @@
+"use strict";
+module.exports = {
+    /**
+       * sanitizes input string by handling escape characters eg: converts '''' to '\'\''
+       * and trim input if required
+       *
+       * @param {String} inputString - Input string being sanitized
+       * @param {Boolean} [trim] - indicates whether to trim string or not
+       * @returns {String}
+       */
+    sanitize: function (inputString, trim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        inputString = inputString.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+        return trim ? inputString.trim() : inputString;
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 91 - 0
dist/codegens/lodash.d.ts

@@ -0,0 +1,91 @@
+declare const _exports: {
+    /**
+     * Creates an inheritance relation between the child and the parent, adding a 'super_' attribute to the
+     * child, and setting up the child prototype.
+     *
+     * @param {Function} child - The target object to create parent references for,.
+     * @param {Function} base - The parent association to assign to the provided child definition.
+     * @returns {*}
+     */
+    inherit: (child: Function, base: Function) => any;
+    /**
+     * Creates a hidden property on an object, which can be changed, but is not enumerable.
+     *
+     * @param {Object} obj
+     * @param {String} name
+     * @param {*} prop
+     * @returns {*}
+     */
+    assignHidden: (obj: any, name: string, prop: any) => any;
+    /**
+     * Creates a property on an object, with the given type.
+     *
+     * @param {Object} obj
+     * @param {String} name
+     * @param {Property} Prop
+     * @param {*} [fallback]
+     * @returns {Prop|undefined}
+     */
+    createDefined: (obj: any, name: string, Prop: any, fallback?: any) => any | undefined;
+    /**
+     * Merges defined keys from the target object onto the source object.
+     *
+     * @param {Object} target
+     * @param {Object} source
+     * @returns {Object}
+     */
+    mergeDefined: (target: any, source: any) => any;
+    /**
+     * Returns the value of a property if defined in object, else the default
+     *
+     * @param {Object} obj
+     * @param {String} prop
+     * @param {*=} def
+     *
+     * @returns {*}
+     */
+    getOwn: (obj: any, prop: string, def?: any | undefined) => any;
+    /**
+     * Creates a clone of an object, but uses the toJSON method if available.
+     *
+     * @param {Object} obj
+     * @returns {*}
+     */
+    cloneElement: (obj: any) => any;
+    isNumeric: (n: any) => boolean;
+    assign: any;
+    clone: any;
+    isArray: any;
+    isEmpty: any;
+    isFunction: any;
+    isNaN: any;
+    isNil: any;
+    isNumber: any;
+    isNull: any;
+    isObject: any;
+    isString: any;
+    isUndefined: any;
+    capitalize: any;
+    reduce: any;
+    filter: any;
+    reject: any;
+    has: any;
+    map: any;
+    forEach: any;
+    includes: any;
+    size: any;
+    join: any;
+    trimEnd: any;
+    findIndex: any;
+    get: any;
+    every: any;
+    keys: any;
+    mapKeys: any;
+    pickBy: any;
+    value: any;
+    unset: any;
+    transform: any;
+    startsWith: any;
+    endsWith: any;
+};
+export = _exports;

+ 172 - 0
dist/codegens/lodash.js

@@ -0,0 +1,172 @@
+"use strict";
+const assign = require('lodash/assign');
+const clone = require('lodash/clone');
+const cloneDeepWith = require('lodash/cloneDeepWith');
+const isArray = require('lodash/isArray');
+const isEmpty = require('lodash/isEmpty');
+const isFunction = require('lodash/isFunction');
+const isNaN = require('lodash/isNaN');
+const isNil = require('lodash/isNil');
+const isNumber = require('lodash/isNumber');
+const isNull = require('lodash/isNull');
+const isObject = require('lodash/isObject');
+const isString = require('lodash/isString');
+const isUndefined = require('lodash/isUndefined');
+const capitalize = require('lodash/capitalize');
+const reduce = require('lodash/reduce');
+const filter = require('lodash/filter');
+const reject = require('lodash/reject');
+const has = require('lodash/has');
+const map = require('lodash/map');
+const forEach = require('lodash/forEach');
+const includes = require('lodash/includes');
+const size = require('lodash/size');
+const join = require('lodash/join');
+const trimEnd = require('lodash/trimEnd');
+const findIndex = require('lodash/findIndex');
+const get = require('lodash/get');
+const every = require('lodash/every');
+const keys = require('lodash/keys');
+const mapKeys = require('lodash/mapKeys');
+const pickBy = require('lodash/pickBy');
+const value = require('lodash/value');
+const unset = require('lodash/unset');
+const transform = require('lodash/transform');
+const startsWith = require('lodash/startsWith');
+const endsWith = require('lodash/endsWith');
+/* istanbul ignore next */
+module.exports = {
+    /**
+     * Creates an inheritance relation between the child and the parent, adding a 'super_' attribute to the
+     * child, and setting up the child prototype.
+     *
+     * @param {Function} child - The target object to create parent references for,.
+     * @param {Function} base - The parent association to assign to the provided child definition.
+     * @returns {*}
+     */
+    inherit: function (child, base) {
+        Object.defineProperty(child, 'super_', {
+            value: isFunction(base) ? base : _.noop,
+            configurable: false,
+            enumerable: false,
+            writable: false
+        });
+        child.prototype = Object.create((isFunction(base) ? base.prototype : base), {
+            constructor: {
+                value: child,
+                enumerable: false,
+                writable: true,
+                configurable: true
+            }
+        });
+        return child;
+    },
+    /**
+     * Creates a hidden property on an object, which can be changed, but is not enumerable.
+     *
+     * @param {Object} obj
+     * @param {String} name
+     * @param {*} prop
+     * @returns {*}
+     */
+    assignHidden: function (obj, name, prop) {
+        Object.defineProperty(obj, name, {
+            value: prop,
+            configurable: true,
+            enumerable: false,
+            writable: true
+        });
+        return obj;
+    },
+    /**
+     * Creates a property on an object, with the given type.
+     *
+     * @param {Object} obj
+     * @param {String} name
+     * @param {Property} Prop
+     * @param {*} [fallback]
+     * @returns {Prop|undefined}
+     */
+    createDefined: function (obj, name, Prop, fallback) {
+        return has(obj, name) ? (new Prop(obj[name])) : fallback;
+    },
+    /**
+     * Merges defined keys from the target object onto the source object.
+     *
+     * @param {Object} target
+     * @param {Object} source
+     * @returns {Object}
+     */
+    mergeDefined: function (target, source) {
+        var key;
+        for (key in source) {
+            if (source.hasOwnProperty(key) && !isUndefined(source[key])) {
+                target[key] = source[key];
+            }
+        }
+        return target;
+    },
+    /**
+     * Returns the value of a property if defined in object, else the default
+     *
+     * @param {Object} obj
+     * @param {String} prop
+     * @param {*=} def
+     *
+     * @returns {*}
+     */
+    getOwn: function (obj, prop, def) {
+        return has(obj, prop) ? obj[prop] : def;
+    },
+    /**
+     * Creates a clone of an object, but uses the toJSON method if available.
+     *
+     * @param {Object} obj
+     * @returns {*}
+     */
+    cloneElement: function (obj) {
+        return cloneDeepWith(obj, function (value) {
+            // falls back to default deepclone if object does not have explicit toJSON().
+            if (value && isFunction(value.toJSON)) {
+                return value.toJSON();
+            }
+        });
+    },
+    isNumeric: function (n) {
+        return !isNaN(n) && isFinite(n);
+    },
+    assign,
+    clone,
+    isArray,
+    isEmpty,
+    isFunction,
+    isNaN,
+    isNil,
+    isNumber,
+    isNull,
+    isObject,
+    isString,
+    isUndefined,
+    capitalize,
+    reduce,
+    filter,
+    reject,
+    has,
+    map,
+    forEach,
+    includes,
+    size,
+    join,
+    trimEnd,
+    findIndex,
+    get,
+    every,
+    keys,
+    mapKeys,
+    pickBy,
+    value,
+    unset,
+    transform,
+    startsWith,
+    endsWith,
+};

+ 5 - 0
dist/codegens/nodejs-native/index.d.ts

@@ -0,0 +1,5 @@
+declare const _exports: {
+    convert: (request: any, options: any, callback: any) => any;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/nodejs-native/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 2 - 0
dist/codegens/nodejs-native/lib/index.d.ts

@@ -0,0 +1,2 @@
+export declare const convert: (request: any, options: any, callback: any) => any;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/nodejs-native/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./request').convert,
+    getOptions: require('./request').getOptions
+};

+ 17 - 0
dist/codegens/nodejs-native/lib/parseRequest.d.ts

@@ -0,0 +1,17 @@
+/**
+ * Parses body object based on mode of body and returns code snippet
+ *
+ * @param {Object} requestbody - json object for body of request
+ * @param {String} indentString - string for indentation
+ * @param {Boolean} trimBody - indicates whether to trim body fields or not
+ * @param {String} contentType Content type of the body being sent
+ */
+export function parseBody(requestbody: any, indentString: string, trimBody: boolean, contentType: string): string;
+/**
+ * parses header of request object and returns code snippet of nodejs native to add header
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation required in code snippet
+ * @returns {String} - code snippet of nodejs native to add header
+ */
+export function parseHeader(request: any, indentString: string): string;

+ 145 - 0
dist/codegens/nodejs-native/lib/parseRequest.js

@@ -0,0 +1,145 @@
+"use strict";
+const _ = require('../../lodash'), sanitize = require('./util').sanitize, path = require('path');
+/**
+ * parses body of request when type of the request body is formdata or urlencoded and
+ * returns code snippet for nodejs to add body
+ *
+ * @param {Array<Object>} dataArray - array containing body elements of request
+ * @param {String} indentString - string required for indentation
+ * @param {Boolean} trimBody - indicates whether to trim body or not
+ */
+function extractFormData(dataArray, indentString, trimBody) {
+    if (!dataArray) {
+        return '';
+    }
+    var snippetString = _.reduce(dataArray, (accumalator, item) => {
+        if (item.disabled) {
+            return accumalator;
+        }
+        accumalator.push(indentString + `'${sanitize(item.key, trimBody)}': '${sanitize(item.value, trimBody)}'`);
+        return accumalator;
+    }, []);
+    return snippetString.join(',\n');
+}
+/**
+ * Generates multipart form data snippet
+ *
+ * @param {*} requestbody
+ */
+function generateMultipartFormData(requestbody) {
+    const boundary = '------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; ', dataArray = requestbody[requestbody.mode];
+    var postData = '';
+    if (dataArray.length) {
+        postData = '"' + boundary + _.reduce(dataArray, (accumalator, dataArrayElement) => {
+            if (!dataArrayElement.disabled || dataArrayElement.disabled === false) {
+                const key = dataArrayElement.key.replace(/"/g, '\'');
+                if (dataArrayElement.type === 'file') {
+                    var pathArray = dataArrayElement.src.split(path.sep), fileName = pathArray[pathArray.length - 1];
+                    const filename = `filename=\\"${fileName}\\"`, contentType = 'Content-Type: \\"{Insert_File_Content_Type}\\"', fileContent = `fs.readFileSync('${dataArrayElement.src}')`;
+                    // eslint-disable-next-line max-len
+                    accumalator.push(`name=\\"${key}\\"; ${filename}\\r\\n${contentType}\\r\\n\\r\\n" + ${fileContent} + "\\r\\n`);
+                }
+                else {
+                    // eslint-disable-next-line no-useless-escape
+                    const value = dataArrayElement.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+                    let field = `name=\\"${key}\\"\\r\\n`;
+                    if (dataArrayElement.contentType) {
+                        field += `Content-Type: ${dataArrayElement.contentType}\\r\\n`;
+                    }
+                    field += `\\r\\n${value}\\r\\n`;
+                    accumalator.push(field);
+                }
+            }
+            return accumalator;
+            // eslint-disable-next-line no-useless-escape
+        }, []).join(`${boundary}`) + '------WebKitFormBoundary7MA4YWxkTrZu0gW--\"';
+    }
+    return postData;
+}
+/**
+ * Parses body object based on mode of body and returns code snippet
+ *
+ * @param {Object} requestbody - json object for body of request
+ * @param {String} indentString - string for indentation
+ * @param {Boolean} trimBody - indicates whether to trim body fields or not
+ * @param {String} contentType Content type of the body being sent
+ */
+function parseBody(requestbody, indentString, trimBody, contentType) {
+    if (requestbody) {
+        switch (requestbody.mode) {
+            case 'raw':
+                // Match any application type whose underlying structure is json
+                // For example application/vnd.api+json
+                // All of them have +json as suffix
+                if (contentType && (contentType === 'application/json' || contentType.match(/\+json$/))) {
+                    try {
+                        let jsonBody = JSON.parse(requestbody[requestbody.mode]);
+                        return `JSON.stringify(${JSON.stringify(jsonBody)})`;
+                    }
+                    catch (error) {
+                        return ` ${JSON.stringify(requestbody[requestbody.mode])}`;
+                    }
+                }
+                return ` ${JSON.stringify(requestbody[requestbody.mode])}`;
+            case 'graphql':
+                // eslint-disable-next-line no-case-declarations
+                let query = requestbody[requestbody.mode].query, graphqlVariables;
+                try {
+                    graphqlVariables = JSON.parse(requestbody[requestbody.mode].variables);
+                }
+                catch (e) {
+                    graphqlVariables = {};
+                }
+                return 'JSON.stringify({\n' +
+                    `${indentString}query: \`${query.trim()}\`,\n` +
+                    `${indentString}variables: ${JSON.stringify(graphqlVariables)}\n})`;
+            case 'formdata':
+                return generateMultipartFormData(requestbody);
+            case 'urlencoded':
+                return `qs.stringify({\n${extractFormData(requestbody[requestbody.mode], indentString, trimBody)}` +
+                    '\n})';
+            case 'file':
+                return '"<file contents here>"';
+            default:
+                return '';
+        }
+    }
+    return '';
+}
+/**
+ * parses header of request object and returns code snippet of nodejs native to add header
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation required in code snippet
+ * @returns {String} - code snippet of nodejs native to add header
+ */
+function parseHeader(request, indentString) {
+    var headerObject = request.getHeaders({ enabled: true }), isEmptyHeader = !Object.keys(headerObject).length;
+    if (isEmptyHeader)
+        return '';
+    var headerSnippet = indentString + '\'headers\': {\n';
+    if (headerObject && Object.keys(headerObject).length) {
+        headerSnippet += _.reduce(Object.keys(headerObject), function (accumalator, key) {
+            if (Array.isArray(headerObject[key])) {
+                var headerValues = [];
+                _.forEach(headerObject[key], (value) => {
+                    headerValues.push(`'${sanitize(value)}'`);
+                });
+                accumalator.push(indentString.repeat(2) + `'${sanitize(key, true)}': [${headerValues.join(', ')}]`);
+            }
+            else {
+                accumalator.push(indentString.repeat(2) + `'${sanitize(key, true)}': '${sanitize(headerObject[key])}'`);
+            }
+            return accumalator;
+        }, []).join(',\n');
+    }
+    if (headerObject && !_.isEmpty(headerObject)) {
+        headerSnippet += '\n';
+    }
+    headerSnippet += indentString + '}';
+    return headerSnippet;
+}
+module.exports = {
+    parseBody: parseBody,
+    parseHeader: parseHeader
+};

+ 2 - 0
dist/codegens/nodejs-native/lib/request.d.ts

@@ -0,0 +1,2 @@
+export declare function getOptions(): any[];
+export declare function convert(request: any, options: any, callback: any): any;

+ 285 - 0
dist/codegens/nodejs-native/lib/request.js

@@ -0,0 +1,285 @@
+"use strict";
+const _ = require('../../lodash'), { Url } = require('../../postman-collection-lite'), sanitizeOptions = require('./util').sanitizeOptions, sanitize = require('./util').sanitize, addFormParam = require('./util').addFormParam, parseRequest = require('./parseRequest');
+var self;
+/**
+ * returns snippet of nodejs(native) by parsing data from Postman-SDK request object
+ *
+ * @param {Object} request - Postman SDK request object
+ * @param {String} indentString - indentation required for code snippet
+ * @param {Object} options
+ * @returns {String} - nodejs(native) code snippet for given request object
+ */
+function makeSnippet(request, indentString, options) {
+    var nativeModule = (request.url.protocol === 'http' ? 'http' : 'https'), snippet, optionsArray = [], postData = '', url, host, path, query;
+    if (options.ES6_enabled) {
+        snippet = 'const ';
+    }
+    else {
+        snippet = 'var ';
+    }
+    if (options.followRedirect) {
+        snippet += `${nativeModule} = require('follow-redirects').${nativeModule};\n`;
+    }
+    else {
+        snippet += `${nativeModule} = require('${nativeModule}');\n`;
+    }
+    if (options.includesFileSystem) {
+        if (options.ES6_enabled) {
+            snippet += 'const ';
+        }
+        else {
+            snippet += 'var ';
+        }
+        snippet += 'fs = require(\'fs\');\n\n';
+    }
+    else {
+        snippet += '\n';
+    }
+    if (_.get(request, 'body.mode') && request.body.mode === 'urlencoded') {
+        if (options.ES6_enabled) {
+            snippet += 'const ';
+        }
+        else {
+            snippet += 'var ';
+        }
+        snippet += 'qs = require(\'querystring\');\n\n';
+    }
+    if (options.ES6_enabled) {
+        snippet += 'const ';
+    }
+    else {
+        snippet += 'var ';
+    }
+    snippet += 'options = {\n';
+    /**
+       * creating string to represent options object using optionArray.join()
+       * example:
+       *  options: {
+       *      method: 'GET',
+       *      hostname: 'www.google.com',
+       *      path: '/x?a=10',
+       *      headers: {
+       *          'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
+       *      }
+       *  }
+       */
+    // The following code handles multiple files in the same formdata param.
+    // It removes the form data params where the src property is an array of filepath strings
+    // Splits that array into different form data params with src set as a single filepath string
+    if (request.body && request.body.mode === 'formdata') {
+        let formdata = request.body.formdata, formdataArray = [];
+        formdata.members.forEach((param) => {
+            let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+            // check if type is file or text
+            if (type === 'file') {
+                // if src is not of type string we check for array(multiple files)
+                if (typeof param.src !== 'string') {
+                    // if src is an array(not empty), iterate over it and add files as separate form fields
+                    if (Array.isArray(param.src) && param.src.length) {
+                        param.src.forEach((filePath) => {
+                            addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                        });
+                    }
+                    // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
+                    else {
+                        addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                    }
+                }
+                // if src is string, directly add the param with src as filepath
+                else {
+                    addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                }
+            }
+            // if type is text, directly add it to formdata array
+            else {
+                addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+            }
+        });
+        request.body.update({
+            mode: 'formdata',
+            formdata: formdataArray
+        });
+    }
+    if (request.body && request.body[request.body.mode]) {
+        postData += parseRequest.parseBody(request.body.toJSON(), indentString, options.trimRequestBody, request.headers.get('Content-Type'));
+    }
+    if (request.body && !request.headers.has('Content-Type')) {
+        if (request.body.mode === 'file') {
+            request.addHeader({
+                key: 'Content-Type',
+                value: 'text/plain'
+            });
+        }
+        else if (request.body.mode === 'graphql') {
+            request.addHeader({
+                key: 'Content-Type',
+                value: 'application/json'
+            });
+        }
+    }
+    url = Url.parse(request.url.toString());
+    host = url.host ? url.host.join('.') : '';
+    path = url.path ? '/' + url.path.join('/') : '/';
+    query = url.query ? _.reduce(url.query, (accum, q) => {
+        accum.push(`${q.key}=${q.value}`);
+        return accum;
+    }, []) : [];
+    if (query.length > 0) {
+        query = '?' + query.join('&');
+    }
+    else {
+        query = '';
+    }
+    optionsArray.push(indentString + `'method': '${request.method}'`);
+    optionsArray.push(`${indentString}'hostname': '${sanitize(host)}'`);
+    if (url.port) {
+        optionsArray.push(`${indentString}'port': ${url.port}`);
+    }
+    optionsArray.push(`${indentString}'path': '${sanitize(path)}${sanitize(encodeURI(query))}'`);
+    const headerString = parseRequest.parseHeader(request, indentString);
+    headerString && optionsArray.push(headerString);
+    if (options.followRedirect) {
+        optionsArray.push(indentString + '\'maxRedirects\': 20');
+    }
+    snippet += optionsArray.join(',\n') + '\n';
+    snippet += '};\n\n';
+    if (options.ES6_enabled) {
+        snippet += 'const ';
+    }
+    else {
+        snippet += 'var ';
+    }
+    snippet += `req = ${nativeModule}.request(options, `;
+    if (options.ES6_enabled) {
+        snippet += '(res) => {\n';
+        snippet += indentString + 'const chunks = [];\n\n';
+        snippet += indentString + 'res.on("data", (chunk) => {\n';
+    }
+    else {
+        snippet += 'function (res) {\n';
+        snippet += indentString + 'var chunks = [];\n\n';
+        snippet += indentString + 'res.on("data", function (chunk) {\n';
+    }
+    snippet += indentString.repeat(2) + 'chunks.push(chunk);\n';
+    snippet += indentString + '});\n\n';
+    if (options.ES6_enabled) {
+        snippet += indentString + 'res.on("end", (chunk) => {\n';
+        snippet += indentString.repeat(2) + 'const body = Buffer.concat(chunks);\n';
+    }
+    else {
+        snippet += indentString + 'res.on("end", function (chunk) {\n';
+        snippet += indentString.repeat(2) + 'var body = Buffer.concat(chunks);\n';
+    }
+    snippet += indentString.repeat(2) + 'console.log(body.toString());\n';
+    snippet += indentString + '});\n\n';
+    if (options.ES6_enabled) {
+        snippet += indentString + 'res.on("error", (error) => {\n';
+    }
+    else {
+        snippet += indentString + 'res.on("error", function (error) {\n';
+    }
+    snippet += indentString.repeat(2) + 'console.error(error);\n';
+    snippet += indentString + '});\n';
+    snippet += '});\n\n';
+    if (request.body && !(_.isEmpty(request.body)) && postData.length) {
+        if (options.ES6_enabled) {
+            snippet += 'const ';
+        }
+        else {
+            snippet += 'var ';
+        }
+        snippet += `postData = ${postData};\n\n`;
+        if (request.method === 'DELETE') {
+            snippet += 'req.setHeader(\'Content-Length\', postData.length);\n\n';
+        }
+        if (request.body.mode === 'formdata') {
+            snippet += 'req.setHeader(\'content-type\',' +
+                ' \'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\');\n\n';
+        }
+        snippet += 'req.write(postData);\n\n';
+    }
+    if (options.requestTimeout) {
+        snippet += `req.setTimeout(${options.requestTimeout}, function() {\n`;
+        snippet += indentString + 'req.abort();\n';
+        snippet += '});\n\n';
+    }
+    snippet += 'req.end();';
+    return snippet;
+}
+/**
+ * Converts Postman sdk request object to nodejs native code snippet
+ *
+ * @param {Object} request - postman-SDK request object
+ * @param {Object} options
+ * @param {String} options.indentType - type for indentation eg: Space, Tab
+ * @param {String} options.indentCount - number of spaces or tabs for indentation.
+ * @param {Boolean} options.followRedirect - whether to enable followredirect
+ * @param {Boolean} options.trimRequestBody - whether to trim fields in request body or not
+ * @param {Boolean} options.ES6_enabled - whether to generate snippet with ES6 features
+ * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+ * @param {Function} callback - callback function with parameters (error, snippet)
+ */
+self = module.exports = {
+    /**
+       * Used to return options which are specific to a particular plugin
+       *
+       * @returns {Array}
+       */
+    getOptions: function () {
+        return [{
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                availableOptions: ['Tab', 'Space'],
+                default: 'Space',
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response' +
+                    ' before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            },
+            {
+                name: 'Enable ES6 features',
+                id: 'ES6_enabled',
+                type: 'boolean',
+                default: false,
+                description: 'Modifies code snippet to incorporate ES6 (EcmaScript) features'
+            }];
+    },
+    convert: function (request, options, callback) {
+        if (!_.isFunction(callback)) {
+            throw new Error('NodeJS-Request-Converter: callback is not valid function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        //  String representing value of indentation required
+        var indentString;
+        indentString = options.indentType === 'Tab' ? '\t' : ' ';
+        indentString = indentString.repeat(options.indentCount);
+        return callback(null, makeSnippet(request, indentString, options));
+    }
+};

+ 3 - 0
dist/codegens/nodejs-native/lib/util.d.ts

@@ -0,0 +1,3 @@
+export declare function sanitize(inputString: string, trim?: boolean | undefined): string;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 112 - 0
dist/codegens/nodejs-native/lib/util.js

@@ -0,0 +1,112 @@
+"use strict";
+module.exports = {
+    /**
+       * sanitizes input string by handling escape characters eg: converts '''' to '\'\''
+       * and trim input if required
+       *
+       * @param {String} inputString
+       * @param {Boolean} [trim] - indicates whether to trim string or not
+       * @returns {String}
+       */
+    sanitize: function (inputString, trim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        (trim) && (inputString = inputString.trim());
+        return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').replace(/\n/g, '\\n');
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 11 - 0
dist/codegens/php-curl/index.d.ts

@@ -0,0 +1,11 @@
+declare const _exports: {
+    convert: (request: any, options: {
+        indentType: string;
+        indentCount: number;
+        requestTimeout: number;
+        trimRequestBody: boolean;
+        followRedirect: boolean;
+    }, callback: Function) => any;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/php-curl/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 8 - 0
dist/codegens/php-curl/lib/index.d.ts

@@ -0,0 +1,8 @@
+export declare const convert: (request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    trimRequestBody: boolean;
+    followRedirect: boolean;
+}, callback: Function) => any;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/php-curl/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./php-curl').convert,
+    getOptions: require('./php-curl').getOptions
+};

+ 8 - 0
dist/codegens/php-curl/lib/php-curl.d.ts

@@ -0,0 +1,8 @@
+export declare function getOptions(): any[];
+export declare function convert(request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    trimRequestBody: boolean;
+    followRedirect: boolean;
+}, callback: Function): any;

+ 168 - 0
dist/codegens/php-curl/lib/php-curl.js

@@ -0,0 +1,168 @@
+"use strict";
+var _ = require('../../lodash'), parseBody = require('./util/parseBody'), sanitize = require('./util/sanitize').sanitize, sanitizeOptions = require('./util/sanitize').sanitizeOptions, addFormParam = require('./util/sanitize').addFormParam, self;
+/**
+ * Used to parse the request headers
+ *
+ * @param  {Object} request - postman SDK-request object
+ * @param  {String} indentation - used for indenting snippet's structure
+ * @returns {String} - request headers in the desired format
+ */
+function getHeaders(request, indentation) {
+    var headerArray = request.toJSON().header, headerMap;
+    if (!_.isEmpty(headerArray)) {
+        headerArray = _.reject(headerArray, 'disabled');
+        headerMap = _.map(headerArray, function (header) {
+            return `${indentation.repeat(2)}'${sanitize(header.key, 'header', true)}: ` +
+                `${sanitize(header.value, 'header')}'`;
+        });
+        return `${indentation}CURLOPT_HTTPHEADER => [\n${headerMap.join(',\n')}\n${indentation}],\n`;
+    }
+    return '';
+}
+self = module.exports = {
+    /**
+       * Used to return options which are specific to a particular plugin
+       *
+       * @returns {Array}
+       */
+    getOptions: function () {
+        return [{
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                availableOptions: ['Tab', 'Space'],
+                default: 'Space',
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response' +
+                    ' before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            }];
+    },
+    /**
+      * Used to convert the postman sdk-request object in php-curl request snippet
+      *
+      * @param  {Object} request - postman SDK-request object
+      * @param  {Object} options
+      * @param  {String} options.indentType - type of indentation eg: Space / Tab (default: Space)
+      * @param  {Number} options.indentCount - frequency of indent (default: 4 for indentType: Space,
+                                                                      default: 1 for indentType: Tab)
+      * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+                                                  (default: 0 -> never bail out)
+      * @param {Boolean} options.trimRequestBody : whether to trim request body fields (default: false)
+      * @param {Boolean} options.followRedirect : whether to allow redirects of a request
+      * @param  {Function} callback - function with parameters (error, snippet)
+      */
+    convert: function (request, options, callback) {
+        var snippet = '', indentation = '', identity = '', finalUrl;
+        if (_.isFunction(options)) {
+            callback = options;
+            options = null;
+        }
+        else if (!_.isFunction(callback)) {
+            throw new Error('Php-Curl~convert: Callback is not a function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        identity = options.indentType === 'Tab' ? '\t' : ' ';
+        indentation = identity.repeat(options.indentCount);
+        // concatenation and making up the final string
+        finalUrl = request.url.toString();
+        if (finalUrl !== encodeURI(finalUrl)) {
+            // needs to be encoded
+            finalUrl = encodeURI(finalUrl);
+        }
+        snippet = '<?php\n\n$curl = curl_init();\n\n';
+        snippet += 'curl_setopt_array($curl, [\n';
+        snippet += `${indentation}CURLOPT_URL => '${sanitize(finalUrl, 'url')}',\n`;
+        snippet += `${indentation}CURLOPT_RETURNTRANSFER => true,\n`;
+        // snippet += `${indentation}CURLOPT_ENCODING => '',\n`;
+        // snippet += `${indentation}CURLOPT_MAXREDIRS => 10,\n`;
+        // snippet += `${indentation}CURLOPT_TIMEOUT => ${options.requestTimeout},\n`;
+        // snippet += `${indentation}CURLOPT_FOLLOWLOCATION => ${options.followRedirect},\n`;
+        // snippet += `${indentation}CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n`;
+        snippet += `${indentation}CURLOPT_CUSTOMREQUEST => '${request.method}',\n`;
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        if (request.body && request.body.mode === 'formdata') {
+            let formdata = request.body.formdata, formdataArray = [];
+            formdata.members.forEach((param) => {
+                let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                // check if type is file or text
+                if (type === 'file') {
+                    // if src is not of type string we check for array(multiple files)
+                    if (typeof param.src !== 'string') {
+                        // if src is an array(not empty), iterate over it and add files as separate form fields
+                        if (Array.isArray(param.src) && param.src.length) {
+                            param.src.forEach((filePath) => {
+                                addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                            });
+                        }
+                        // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
+                        else {
+                            addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                        }
+                    }
+                    // if src is string, directly add the param with src as filepath
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                    }
+                }
+                // if type is text, directly add it to formdata array
+                else {
+                    addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                }
+            });
+            request.body.update({
+                mode: 'formdata',
+                formdata: formdataArray
+            });
+        }
+        snippet += `${parseBody(request.toJSON(), options.trimRequestBody, indentation)}`;
+        if (request.body && !request.headers.has('Content-Type')) {
+            if (request.body.mode === 'file') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'text/plain'
+                });
+            }
+            else if (request.body.mode === 'graphql') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'application/json'
+                });
+            }
+        }
+        snippet += `${getHeaders(request, indentation)}`;
+        snippet += ']);\n\n';
+        snippet += '$response = curl_exec($curl);\n\n';
+        snippet += 'curl_close($curl);\n';
+        snippet += 'echo $response;\n';
+        return callback(null, snippet);
+    }
+};

+ 2 - 0
dist/codegens/php-curl/lib/util/parseBody.d.ts

@@ -0,0 +1,2 @@
+declare function _exports(request: any, trimRequestBody: boolean, indentation: string): string;
+export = _exports;

+ 74 - 0
dist/codegens/php-curl/lib/util/parseBody.js

@@ -0,0 +1,74 @@
+"use strict";
+var _ = require('../../../lodash'), sanitize = require('./sanitize').sanitize;
+/**
+ * Used to parse the body of the postman SDK-request and return in the desired format
+ *
+ * @param  {Object} request - postman SDK-request object
+ * @param  {Boolean} trimRequestBody - whether to trim request body fields
+ * @param  {String} indentation - used for indenting snippet's structure
+ * @returns {String} - request body
+ */
+module.exports = function (request, trimRequestBody, indentation) {
+    // used to check whether body is present in the request and return accordingly
+    if (request.body) {
+        var requestBody = '', bodyMap, enabledBodyList;
+        switch (request.body.mode) {
+            case 'raw':
+                if (!_.isEmpty(request.body[request.body.mode])) {
+                    requestBody += `${indentation}CURLOPT_POSTFIELDS =>` +
+                        `'${sanitize(request.body[request.body.mode], request.body.mode, trimRequestBody)}',\n`;
+                }
+                return requestBody;
+            case 'graphql':
+                // eslint-disable-next-line no-case-declarations
+                let query = request.body[request.body.mode].query, graphqlVariables;
+                try {
+                    graphqlVariables = JSON.parse(request.body[request.body.mode].variables);
+                }
+                catch (e) {
+                    graphqlVariables = {};
+                }
+                requestBody += `${indentation}CURLOPT_POSTFIELDS =>` +
+                    `'${sanitize(JSON.stringify({
+                        query: query,
+                        variables: graphqlVariables
+                    }), 'raw', trimRequestBody)}',\n`;
+                return requestBody;
+            case 'urlencoded':
+                enabledBodyList = _.reject(request.body[request.body.mode], 'disabled');
+                if (!_.isEmpty(enabledBodyList)) {
+                    bodyMap = _.map(enabledBodyList, function (value) {
+                        return `${sanitize(value.key, request.body.mode, trimRequestBody)}=` +
+                            `${sanitize(value.value, request.body.mode, trimRequestBody)}`;
+                    });
+                    requestBody = `${indentation}CURLOPT_POSTFIELDS => '${bodyMap.join('&')}',\n`;
+                }
+                return requestBody;
+            case 'formdata':
+                enabledBodyList = _.reject(request.body[request.body.mode], 'disabled');
+                if (!_.isEmpty(enabledBodyList)) {
+                    bodyMap = _.map(enabledBodyList, function (value) {
+                        if (value.type === 'text') {
+                            return (`'${sanitize(value.key, request.body.mode, trimRequestBody)}' => '` +
+                                `${sanitize(value.value, request.body.mode, trimRequestBody)}'`);
+                        }
+                        else if (value.type === 'file') {
+                            return `'${sanitize(value.key, request.body.mode, trimRequestBody)}'=> ` +
+                                `new CURLFILE('${sanitize(value.src, request.body.mode, trimRequestBody)}')`;
+                        }
+                    });
+                    requestBody = `${indentation}CURLOPT_POSTFIELDS => [${bodyMap.join(',')}],\n`;
+                }
+                return requestBody;
+            case 'file':
+                // requestBody = `${indentation}CURLOPT_POSTFIELDS => array('file' => '@'`;
+                // requestBody += `${sanitize(request.body[request.body.mode].src,
+                //   request.body.mode, trimRequestBody)}'),\n`;
+                requestBody = `${indentation}CURLOPT_POSTFIELDS => "<file contents here>",\n`;
+                return requestBody;
+            default:
+                return requestBody;
+        }
+    }
+    return '';
+};

+ 3 - 0
dist/codegens/php-curl/lib/util/sanitize.d.ts

@@ -0,0 +1,3 @@
+export declare function sanitize(inputString: string, escapeCharFor: string, inputTrim?: boolean | undefined): string;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 120 - 0
dist/codegens/php-curl/lib/util/sanitize.js

@@ -0,0 +1,120 @@
+"use strict";
+module.exports = {
+    /**
+    * sanitization of values : trim, escape characters
+    *
+    * @param {String} inputString - input
+    * @param {String} escapeCharFor - escape for headers, body: raw, formdata etc
+    * @param {Boolean} [inputTrim] - whether to trim the input
+    * @returns {String}
+    */
+    sanitize: function (inputString, escapeCharFor, inputTrim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        inputString = inputTrim && typeof inputTrim === 'boolean' ? inputString.trim() : inputString;
+        if (escapeCharFor && typeof escapeCharFor === 'string') {
+            switch (escapeCharFor) {
+                case 'urlencoded':
+                    return encodeURIComponent(inputString).replace(/'/g, '\\\'');
+                default:
+                    return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
+            }
+        }
+        return inputString;
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 13 - 0
dist/codegens/postman-collection-lite/collection/form-param.d.ts

@@ -0,0 +1,13 @@
+export var FormParam: any;
+export namespace FormParam {
+    export type definition = {
+        /**
+         * The name ("key") of the form data parameter.
+         */
+        key: string;
+        /**
+         * The value of the parameter.
+         */
+        value: string;
+    };
+}

+ 85 - 0
dist/codegens/postman-collection-lite/collection/form-param.js

@@ -0,0 +1,85 @@
+"use strict";
+var _ = require('../../lodash'), Property = require('./property').Property, PropertyBase = require('./property-base').PropertyBase, FormParam;
+/**
+ * @typedef FormParam.definition
+ * @property {String} key The name ("key") of the form data parameter.
+ * @property {String} value The value of the parameter.
+ */
+_.inherit((
+/**
+ * Represents a Form Data parameter, which can exist in request body.
+ *
+ * @constructor
+ * @param {FormParam.definition} options Pass the initial definition of the form data parameter.
+ */
+FormParam = function PostmanFormParam(options) {
+    FormParam.super_.apply(this, arguments);
+    // @todo avoid using _.get
+    this.key = _.get(options, 'key') || '';
+    this.value = _.get(options, 'value') || '';
+    this.type = _.get(options, 'type');
+    this.src = _.get(options, 'src');
+    this.contentType = _.get(options, 'contentType');
+}), Property);
+_.assign(FormParam.prototype, /** @lends FormParam.prototype */ {
+    /**
+     * Converts the FormParameter to a single param string.
+     *
+     * @returns {String}
+     */
+    toString: function () {
+        return this.key + '=' + this.value;
+    },
+    /**
+     * Returns the value of the form parameter (if any).
+     *
+     * @returns {*|string}
+     */
+    valueOf: function () {
+        return this.value; // can be multiple types, so just return whatever we have instead of being too clever
+    },
+    /**
+     * Convert the form-param to JSON compatible plain object.
+     *
+     * @returns {Object}
+     */
+    toJSON: function () {
+        var obj = PropertyBase.toJSON(this);
+        // remove value from file param because it is non-serializable ReadStream
+        if (obj.type === 'file') {
+            _.unset(obj, 'value');
+        }
+        return obj;
+    }
+});
+_.assign(FormParam, /** @lends FormParam */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'FormParam',
+    /**
+     * Declare the list index key, so that property lists of form parameters work correctly
+     *
+     * @type {String}
+     */
+    _postman_propertyIndexKey: 'key',
+    /**
+     * Form params can have multiple values, so set this to true.
+     *
+     * @type {Boolean}
+     */
+    _postman_propertyAllowsMultipleValues: true,
+    /**
+     * Parse a form data string into an array of objects, where each object contains a key and a value.
+     * @todo implement this, not implemented yet.
+     * @param formdata {String}
+     * @returns {Array}
+     */
+    parse: _.noop
+});
+module.exports = {
+    FormParam: FormParam
+};

+ 1 - 0
dist/codegens/postman-collection-lite/collection/header-list.d.ts

@@ -0,0 +1 @@
+export var HeaderList: any;

+ 58 - 0
dist/codegens/postman-collection-lite/collection/header-list.js

@@ -0,0 +1,58 @@
+"use strict";
+var _ = require('../../lodash'), PropertyList = require('./property-list').PropertyList, Header = require('./header').Header, E = '', CRLF = '\r\n', PROP_NAME = '_postman_propertyName', HeaderList;
+_.inherit((
+/**
+* Contains a list of header elements
+*
+* @constructor
+* @param {Object} parent
+* @param {Header[]} headers
+* @extends {PropertyList}
+*/
+HeaderList = function (parent, headers) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    HeaderList.super_.call(this, Header, parent, headers);
+}), PropertyList);
+_.assign(HeaderList.prototype, /** @lends HeaderList.prototype */ {
+    /**
+     * Gets size of a list of headers excluding standard header prefix.
+     *
+     * @returns {Number}
+     */
+    contentSize: function () {
+        if (!this.count()) {
+            return 0;
+        }
+        var raw = this.reduce(function (acc, header) {
+            // unparse header only if it has a valid key and is not disabled
+            if (header && !header.disabled) {
+                // *( header-field CRLF )
+                acc += Header.unparseSingle(header) + CRLF;
+            }
+            return acc;
+        }, E);
+        return raw.length;
+    }
+});
+_.assign(HeaderList, /** @lends HeaderList */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'HeaderList',
+    /**
+     * Checks if the given object is a HeaderList
+     *
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isHeaderList: function (obj) {
+        return Boolean(obj) && ((obj instanceof HeaderList) ||
+            _.inSuperChain(obj.constructor, PROP_NAME, HeaderList._postman_propertyName));
+    }
+});
+module.exports = {
+    HeaderList: HeaderList
+};

+ 13 - 0
dist/codegens/postman-collection-lite/collection/header.d.ts

@@ -0,0 +1,13 @@
+export var Header: any;
+export namespace Header {
+    export type definition = {
+        /**
+         * The Header name (e.g: 'Content-Type')
+         */
+        key: string;
+        /**
+         * The value of the header.
+         */
+        value: string;
+    };
+}

+ 239 - 0
dist/codegens/postman-collection-lite/collection/header.js

@@ -0,0 +1,239 @@
+"use strict";
+var _ = require('../../lodash'), E = '', SPC = ' ', HEADER_KV_SEPARATOR = ':', Property = require('./property').Property, PropertyList = require('./property-list').PropertyList, Header;
+/**
+ * @typedef Header.definition
+ * @property {String} key The Header name (e.g: 'Content-Type')
+ * @property {String} value The value of the header.
+ *
+ * @example <caption>Create a header</caption>
+ * var Header = require('postman-collection').Header,
+ *     header = new Header({
+ *         key: 'Content-Type',
+ *         value: 'application/xml'
+ *     });
+ *
+ * console.log(header.toString()) // prints the string representation of the Header.
+ */
+_.inherit((
+/**
+ * Represents an HTTP header, for requests or for responses.
+ *
+ * @constructor
+ * @extends {Property}
+ *
+ * @param {Header.definition|String} options - Pass the header definition as an object or the value of the header.
+ * If the value is passed as a string, it should either be in `name:value` format or the second "name" parameter
+ * should be used to pass the name as string
+ * @param {String} [name] - optional override the header name or use when the first parameter is the header value as
+ * string.
+ *
+ * @example <caption>Parse a string of headers into an array of Header objects</caption>
+ * var Header = require('postman-collection').Header,
+ *     headerString = 'Content-Type: application/json\nUser-Agent: MyClientLibrary/2.0\n';
+ *
+ * var rawHeaders = Header.parse(headerString);
+ * console.log(rawHeaders); // [{ 'Content-Type': 'application/json', 'User-Agent': 'MyClientLibrary/2.0' }]
+ *
+ * var headers = rawHeaders.map(function (h) {
+ *     return new Header(h);
+ * });
+ *
+ * function assert(condition, message) {
+ *       if (!condition) {
+ *           message = message || "Assertion failed";
+ *           if (typeof Error !== "undefined") {
+ *               throw new Error(message);
+ *           }
+ *           throw message; //fallback
+ *       }
+ *       else {
+ *           console.log("Assertion passed");
+ *       }
+ *   }
+ *
+ * assert(headerString.trim() === Header.unparse(headers).trim());
+ */
+Header = function PostmanHeader(options, name) {
+    if (_.isString(options)) {
+        options = _.isString(name) ? { key: name, value: options } : Header.parseSingle(options);
+    }
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    Header.super_.apply(this, arguments);
+    this.update(options);
+}), Property);
+_.assign(Header.prototype, /** @lends Header.prototype */ {
+    /**
+     * Converts the header to a single header string.
+     *
+     * @returns {String}
+     */
+    toString: function () {
+        return this.key + ': ' + this.value;
+    },
+    /**
+     * Return the value of this header.
+     *
+     * @return {String}
+     */
+    valueOf: function () {
+        return this.value;
+    },
+    /**
+     * Assigns the given properties to the Header
+     *
+     * @param {Object} options
+     * @todo check for allowed characters in header key-value or store encoded.
+     */
+    update: function (options) {
+        /**
+         * The header Key
+         * @type {String}
+         * @todo avoid headers with falsy key.
+         */
+        this.key = _.get(options, 'key') || E;
+        /**
+         * The header value
+         * @type {String}
+         */
+        this.value = _.get(options, 'value', E);
+        /**
+         * Indicates whether the header was added by internal SDK operations, such as authorizing a request.
+         * @type {*|boolean}
+         */
+        _.has(options, 'system') && (this.system = options.system);
+        /**
+         * Indicates whether the header should be .
+         * @type {*|boolean}
+         * @todo figure out whether this should be in property.js
+         */
+        _.has(options, 'disabled') && (this.disabled = options.disabled);
+    }
+});
+_.assign(Header, /** @lends Header */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'Header',
+    /**
+     * Specify the key to be used while indexing this object
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyIndexKey: 'key',
+    /**
+     * Specifies whether the index lookup of this property, when in a list is case insensitive or not
+     * @private
+     * @readOnly
+     * @type {boolean}
+     */
+    _postman_propertyIndexCaseInsensitive: true,
+    /**
+     * Since each header may have multiple possible values, this is set to true.
+     *
+     * @private
+     * @readOnly
+     * @type {Boolean}
+     */
+    _postman_propertyAllowsMultipleValues: true,
+    /**
+     * Parses a multi line header string into an array of {@link Header.definition}.
+     *
+     * @param {String} headerString
+     * @returns {Array}
+     */
+    parse: function (headerString) {
+        var headers = [], regexes = {
+            header: /^(\S+):(.*)$/gm,
+            fold: /\r\n([ \t])/g,
+            trim: /^\s*(.*\S)?\s*$/
+        }, match = regexes.header.exec(headerString);
+        headerString = headerString.toString().replace(regexes.fold, '$1');
+        while (match) {
+            headers.push({
+                key: match[1],
+                value: match[2].replace(regexes.trim, '$1')
+            });
+            match = regexes.header.exec(headerString);
+        }
+        return headers;
+    },
+    /**
+     * Parses a single Header.
+     *
+     * @param {String} header
+     * @returns {{key: string, value: string}}
+     */
+    parseSingle: function (header) {
+        if (!_.isString(header)) {
+            return { key: E, value: E };
+        }
+        var index = header.indexOf(HEADER_KV_SEPARATOR), key, value;
+        (index < 0) && (index = header.length);
+        key = header.substr(0, index);
+        value = header.substr(index + 1);
+        return {
+            key: _.trim(key),
+            value: _.trim(value)
+        };
+    },
+    /**
+     * Stringifies an Array or {@link PropertyList} of Headers into a single string.
+     *
+     * @param {Array|PropertyList<Header>} headers
+     * @param {String=} separator - Specify a string for separating each header, by default, '\n', but sometimes,
+     * it might be more useful to use a carriage return ('\r\n')
+     * @returns {string}
+     */
+    unparse: function (headers, separator) {
+        if (!_.isArray(headers) && !PropertyList.isPropertyList(headers)) {
+            return E;
+        }
+        return headers.map(Header.unparseSingle).join(separator ? separator : '\n');
+    },
+    /**
+     * Unparses a single Header.
+     *
+     * @param {String} header
+     * @returns {String}
+     */
+    unparseSingle: function (header) {
+        if (!_.isObject(header)) {
+            return E;
+        }
+        return header.key + HEADER_KV_SEPARATOR + SPC + header.value;
+    },
+    /**
+     * Check whether an object is an instance of PostmanHeader.
+     *
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isHeader: function (obj) {
+        return Boolean(obj) && ((obj instanceof Header) ||
+            _.inSuperChain(obj.constructor, '_postman_propertyName', Header._postman_propertyName));
+    },
+    /* eslint-disable jsdoc/check-param-names */
+    /**
+     * Create a new header instance
+     *
+     * @param {Header.definition|String} [value] - Pass the header definition as an object or the value of the header.
+     * If the value is passed as a string, it should either be in `name:value` format or the second "name" parameter
+     * should be used to pass the name as string
+     * @param {String} [name] - optional override the header name or use when the first parameter is the header value as
+     * string.
+     * @returns {Header}
+     */
+    create: function () {
+        var args = Array.prototype.slice.call(arguments);
+        args.unshift(Header);
+        return new (Header.bind.apply(Header, args))(); // eslint-disable-line prefer-spread
+    }
+    /* eslint-enable jsdoc/check-param-names */
+});
+module.exports = {
+    Header: Header
+};

+ 6 - 0
dist/codegens/postman-collection-lite/collection/property-base.d.ts

@@ -0,0 +1,6 @@
+export var PropertyBase: any;
+export namespace PropertyBase {
+    export type definition = {
+        description?: any;
+    };
+}

+ 199 - 0
dist/codegens/postman-collection-lite/collection/property-base.js

@@ -0,0 +1,199 @@
+"use strict";
+var _ = require('../../lodash'), __PARENT = '__parent', PropertyBase; // constructor
+/**
+ * @typedef PropertyBase.definition
+ * @property {String|Description} [description]
+ */
+/**
+ * Base of all properties in Postman Collection. It defines the root for all standalone properties for postman
+ * collection.
+ *
+ * @constructor
+ * @param {PropertyBase.definition} definition
+ */
+PropertyBase = function PropertyBase(definition) {
+    // In case definition object is missing, there is no point moving forward. Also if the definition is basic string
+    // we do not need to do anything with it.
+    if (!definition || typeof definition === 'string') {
+        return;
+    }
+    // call the meta extraction functions to create the object where all keys that are prefixed with underscore can be
+    // stored. more details on that can be retrieved from the propertyExtractMeta function itself.
+    // @todo: make this a closed function to do getter and setter which is non enumerable
+    var src = definition && definition.info || definition, 
+    // meta = _(src).pickBy(PropertyBase.propertyIsMeta).mapKeys(PropertyBase.propertyUnprefixMeta).value();
+    meta = _.value(_.mapKeys(_.pickBy(src, PropertyBase.propertyIsMeta, PropertyBase.propertyUnprefixMeta)));
+    if (_.keys(meta).length) {
+        this._ = _.isObject(this._) ? _.mergeDefined(this._, meta) : meta;
+    }
+};
+_.assign(PropertyBase.prototype, /** @lends PropertyBase.prototype */ {
+    /**
+     * Invokes the given iterator for every parent in the parent chain of the given element.
+     *
+     * @param {Object} options - A set of options for the parent chain traversal.
+     * @param {?Boolean} [options.withRoot=false] - Set to true to include the collection object as well.
+     * @param {Function} iterator - The function to call for every parent in the ancestry chain.
+     * @todo Cache the results
+     */
+    forEachParent: function (options, iterator) {
+        _.isFunction(options) && (iterator = options, options = {});
+        if (!_.isFunction(iterator) || !_.isObject(options)) {
+            return;
+        }
+        var parent = this.parent(), grandparent = parent && _.isFunction(parent.parent) && parent.parent();
+        while (parent && (grandparent || options.withRoot)) {
+            iterator(parent);
+            parent = grandparent;
+            grandparent = grandparent && _.isFunction(grandparent.parent) && grandparent.parent();
+        }
+    },
+    /**
+     * Tries to find the given property locally, and then proceeds to lookup in each parent,
+     * going up the chain as necessary. Lookup will continue until `customizer` returns a truthy value. If used
+     * without a customizer, the lookup will stop at the first parent that contains the property.
+     *
+     * @param {String} property
+     * @param {Function} [customizer]
+     *
+     * @returns {*|undefined}
+     */
+    findInParents: function (property, customizer) {
+        var owner = this.findParentContaining(property, customizer);
+        return owner ? owner[property] : undefined;
+    },
+    /**
+     * Looks up the closest parent which has a truthy value for the given property. Lookup will continue
+     * until `customizer` returns a truthy value. If used without a customizer,
+     * the lookup will stop at the first parent that contains the property.
+     *
+     * @param {String} property
+     * @param {Function} [customizer]
+     *
+     * @returns {PropertyBase|undefined}
+     * @private
+     */
+    findParentContaining: function (property, customizer) {
+        var parent = this;
+        // if customizer is present test with it
+        if (customizer) {
+            customizer = customizer.bind(this);
+            do {
+                // else check for existence
+                if (customizer(parent)) {
+                    return parent;
+                }
+                parent = parent.__parent;
+            } while (parent);
+        }
+        // else check for existence
+        else {
+            do {
+                if (parent[property]) {
+                    return parent;
+                }
+                parent = parent.__parent;
+            } while (parent);
+        }
+    },
+    /**
+     * Returns the JSON representation of a property, which conforms to the way it is defined in a collection.
+     * You can use this method to get the instantaneous representation of any property, including a {@link Collection}.
+     */
+    toJSON: function () {
+        return _.reduce(this, function (accumulator, value, key) {
+            if (value === undefined) { // true/false/null need to be preserved.
+                return accumulator;
+            }
+            // Handle plurality of PropertyLists in the SDK vs the exported JSON.
+            // Basically, removes the trailing "s" from key if the value is a property list.
+            // eslint-disable-next-line max-len
+            if (value && value._postman_propertyIsList && !value._postman_proprtyIsSerialisedAsPlural && _.endsWith(key, 's')) {
+                key = key.slice(0, -1);
+            }
+            // Handle 'PropertyBase's
+            if (value && _.isFunction(value.toJSON)) {
+                accumulator[key] = value.toJSON();
+                return accumulator;
+            }
+            // Handle Strings
+            if (_.isString(value)) {
+                accumulator[key] = value;
+                return accumulator;
+            }
+            // Everything else
+            accumulator[key] = _.cloneElement(value);
+            return accumulator;
+        }, {});
+    },
+    /**
+     * Returns the meta keys associated with the property
+     *
+     * @returns {*}
+     */
+    meta: function () {
+        return arguments.length ? _.pick(this._, Array.prototype.slice.apply(arguments)) : _.cloneDeep(this._);
+    },
+    /**
+     * Returns the parent of item
+     *
+     * @returns {*|undefined}
+     */
+    parent: function () {
+        // @todo return grandparent only if it is a list
+        return this && this.__parent && (this.__parent.__parent || this.__parent) || undefined;
+    },
+    /**
+     * Accepts an object and sets it as the parent of the current property.
+     *
+     * @param {Object} parent The object to set as parent.
+     * @private
+     */
+    setParent: function (parent) {
+        _.assignHidden(this, __PARENT, parent);
+    }
+});
+_.assign(PropertyBase, /** @lends PropertyBase */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'PropertyBase',
+    /**
+     * Filter function to check whether a key starts with underscore or not. These usually are the meta properties. It
+     * returns `true` if the criteria is matched.
+     *
+     * @param {*} value
+     * @param {String} key
+     *
+     * @returns {boolean}
+     */
+    propertyIsMeta: function (value, key) {
+        return _.startsWith(key, '_') && (key !== '_');
+    },
+    /**
+     * Map function that removes the underscore prefix from an object key.
+     *
+     * @param {*} value
+     * @param {String} key
+     *
+     * @returns {String}
+     */
+    propertyUnprefixMeta: function (value, key) {
+        return _.trimStart(key, '_');
+    },
+    /**
+     * Static function which allows calling toJSON() on any object.
+     *
+     * @param {Object} obj
+     * @returns {*}
+     */
+    toJSON: function (obj) {
+        return PropertyBase.prototype.toJSON.call(obj);
+    }
+});
+module.exports = {
+    PropertyBase: PropertyBase
+};

+ 7 - 0
dist/codegens/postman-collection-lite/collection/property-list.d.ts

@@ -0,0 +1,7 @@
+export var PropertyList: any;
+export namespace PropertyList {
+    /**
+     * An item constructed of PropertyList.Type.
+     */
+    export type Type = any;
+}

+ 592 - 0
dist/codegens/postman-collection-lite/collection/property-list.js

@@ -0,0 +1,592 @@
+"use strict";
+var _ = require('../../lodash'), PropertyBase = require('./property-base').PropertyBase, __PARENT = '__parent', DEFAULT_INDEX_ATTR = 'id', DEFAULT_INDEXCASE_ATTR = false, DEFAULT_INDEXMULTI_ATTR = false, PropertyList;
+/**
+ * An item constructed of PropertyList.Type.
+ * @typedef {Object} PropertyList.Type
+ */
+_.inherit((
+/**
+ * @constructor
+ * @param {Function} type
+ * @param {Object} parent
+ * @param {Array} populate
+ */
+PropertyList = function PostmanPropertyList(type, parent, populate) {
+    // @todo add this test sometime later
+    // if (!type) {
+    //     throw new Error('postman-collection: cannot initialise a list without a type parameter');
+    // }
+    PropertyList.super_.call(this); // call super with appropriate options
+    this.setParent(parent); // save reference to parent
+    _.assign(this, /** @lends PropertyList.prototype */ {
+        /**
+         * @private
+         * @type {Array}
+         */
+        members: this.members || [],
+        /**
+         * @private
+         * @type {Object}
+         * @note This should not be used, and it's not guaranteed to be in sync with the actual list of members.
+         */
+        reference: this.reference || {},
+        /**
+         * @private
+         * @type {Function}
+         */
+        Type: type
+    });
+    // if the type this list holds has its own index key, then use the same
+    _.getOwn(type, '_postman_propertyIndexKey') && (this._postman_listIndexKey = type._postman_propertyIndexKey);
+    // if the type has case sensitivity flags, set the same
+    _.getOwn(type, '_postman_propertyIndexCaseInsensitive') && (this._postman_listIndexCaseInsensitive =
+        type._postman_propertyIndexCaseInsensitive);
+    // if the type allows multiple values, set the flag
+    _.getOwn(type, '_postman_propertyAllowsMultipleValues') && (this._postman_listAllowsMultipleValues =
+        type._postman_propertyAllowsMultipleValues);
+    // prepopulate
+    populate && this.populate(populate);
+}), PropertyBase);
+_.assign(PropertyList.prototype, /** @lends PropertyList.prototype */ {
+    /**
+     * Indicates that this element contains a number of other elements.
+     * @private
+     */
+    _postman_propertyIsList: true,
+    /**
+     * Holds the attribute to index this PropertyList by. Default: 'id'
+     *
+     * @private
+     * @type {String}
+     */
+    _postman_listIndexKey: DEFAULT_INDEX_ATTR,
+    /**
+     * Holds the attribute whether indexing of this list is case sensitive or not
+     *
+     * @private
+     * @type {String}
+     */
+    _postman_listIndexCaseInsensitive: DEFAULT_INDEXCASE_ATTR,
+    /**
+     * Holds the attribute whether exporting the index retains duplicate index items
+     *
+     * @private
+     * @type {String}
+     */
+    _postman_listAllowsMultipleValues: DEFAULT_INDEXMULTI_ATTR,
+    /**
+     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
+     * member is inserted at an index before the reference member.
+     *
+     * @param {PropertyList.Type} item
+     * @param {PropertyList.Type|String} [before]
+     */
+    insert: function (item, before) {
+        if (!_.isObject(item)) {
+            return;
+        } // do not proceed on empty param
+        var duplicate = this.indexOf(item), index;
+        // remove from previous list
+        PropertyList.isPropertyList(item[__PARENT]) && (item[__PARENT] !== this) && item[__PARENT].remove(item);
+        // inject the parent reference
+        _.assignHidden(item, __PARENT, this);
+        // ensure that we do not double insert things into member array
+        (duplicate > -1) && this.members.splice(duplicate, 1);
+        // find the position of the reference element
+        before && (before = this.indexOf(before));
+        // inject to the members array ata position or at the end in case no item is there for reference
+        (before > -1) ? this.members.splice(before, 0, item) : this.members.push(item);
+        // store reference by id, so create the index string. we first ensure that the index value is truthy and then
+        // recheck that the string conversion of the same is truthy as well.
+        if ((index = item[this._postman_listIndexKey]) && (index = String(index))) {
+            // desensitise case, if the property needs it to be
+            this._postman_listIndexCaseInsensitive && (index = index.toLowerCase());
+            // if multiple values are allowed, the reference may contain an array of items, mapped to an index.
+            if (this._postman_listAllowsMultipleValues && Object.hasOwnProperty.call(this.reference, index)) {
+                // if the value is not an array, convert it to an array.
+                !_.isArray(this.reference[index]) && (this.reference[index] = [this.reference[index]]);
+                // add the item to the array of items corresponding to this index
+                this.reference[index].push(item);
+            }
+            else {
+                this.reference[index] = item;
+            }
+        }
+    },
+    /**
+     * Insert an element at the end of this list. When a reference member specified via second parameter is found, the
+     * member is inserted at an index after the reference member.
+     *
+     * @param {PropertyList.Type} item
+     * @param {PropertyList.Type|String} [after]
+     */
+    insertAfter: function (item, after) {
+        // convert item to positional reference
+        return this.insert(item, this.idx(this.indexOf(after) + 1));
+    },
+    /**
+     * Adds or moves an item to the end of this list.
+     *
+     * @param {PropertyList.Type} item
+     */
+    append: function (item) {
+        return this.insert(item);
+    },
+    /**
+     * Adds or moves an item to the beginning of this list.
+     *
+     * @param {PropertyList.Type} item
+     */
+    prepend: function (item) {
+        return this.insert(item, this.idx(0));
+    },
+    /**
+     * Add an item or item definition to this list.
+     *
+     * @param {Object|PropertyList.Type} item
+     * @todo
+     * - remove item from original parent if already it has a parent
+     * - validate that the original parent's constructor matches this parent's constructor
+     */
+    add: function (item) {
+        // do not proceed on empty param, but empty strings are in fact valid.
+        // eslint-disable-next-line lodash/prefer-is-nil
+        if (_.isNull(item) || _.isUndefined(item) || _.isNaN(item)) {
+            return;
+        }
+        // create new instance of the item based on the type specified if it is not already
+        this.insert((item.constructor === this.Type) ? item :
+            // if the property has a create static function, use it.
+            // eslint-disable-next-line prefer-spread
+            (_.has(this.Type, 'create') ? this.Type.create.apply(this.Type, arguments) : new this.Type(item)));
+    },
+    /**
+     * Add an item or update an existing item
+     *
+     * @param {PropertyList.Type} item
+     *
+     * @returns {?Boolean}
+     */
+    upsert: function (item) {
+        // do not proceed on empty param, but empty strings are in fact valid.
+        if (_.isNil(item) || _.isNaN(item)) {
+            return null;
+        }
+        var indexer = this._postman_listIndexKey, existing = this.one(item[indexer]);
+        if (existing) {
+            if (!_.isFunction(existing.update)) {
+                throw new Error('collection: unable to upsert into a list of Type that does not support .update()');
+            }
+            existing.update(item);
+            return false;
+        }
+        // since there is no existing item, just add a new one
+        this.add(item);
+        return true; // indicate added
+    },
+    /**
+     * Removes all elements from the PropertyList for which the predicate returns truthy.
+     *
+     * @param {Function|String|PropertyList.Type} predicate
+     * @param {Object} context Optional context to bind the predicate to.
+     */
+    remove: function (predicate, context) {
+        var match; // to be used if predicate is an ID
+        !context && (context = this);
+        if (_.isString(predicate)) {
+            // if predicate is id, then create a function to remove that
+            // need to take care of case sensitivity as well :/
+            match = this._postman_listIndexCaseInsensitive ? predicate.toLowerCase() : predicate;
+            predicate = function (item) {
+                var id = item[this._postman_listIndexKey];
+                this._postman_listIndexCaseInsensitive && (id = id.toLowerCase());
+                return id === match;
+            }.bind(this);
+        }
+        else if (predicate instanceof this.Type) {
+            // in case an object reference is sent, prepare it for removal using direct reference comparison
+            match = predicate;
+            predicate = function (item) {
+                return (item === match);
+            };
+        }
+        _.isFunction(predicate) && _.remove(this.members, function (item) {
+            var index;
+            if (predicate.apply(context, arguments)) {
+                if ((index = item[this._postman_listIndexKey]) && (index = String(index))) {
+                    this._postman_listIndexCaseInsensitive && (index = index.toLowerCase());
+                    if (this._postman_listAllowsMultipleValues && _.isArray(this.reference[index])) {
+                        // since we have an array of multiple values, remove only the value for which the
+                        // predicate returned truthy. If the array becomes empty, just delete it.
+                        _.remove(this.reference[index], function (each) {
+                            return each === item;
+                        });
+                        // If the array becomes empty, remove it
+                        (this.reference[index].length === 0) && (delete this.reference[index]);
+                        // If the array contains only one element, remove the array, and assign the element
+                        // as the reference value
+                        (this.reference[index].length === 1) && (this.reference[index] = this.reference[index][0]);
+                    }
+                    else {
+                        delete this.reference[index];
+                    }
+                }
+                delete item[__PARENT]; // unlink from its parent
+                return true;
+            }
+        }.bind(this));
+    },
+    /**
+     * Removes all items in the list
+     */
+    clear: function () {
+        // we unlink every member from it's parent (assuming this is their parent)
+        this.all().forEach(PropertyList._unlinkItemFromParent);
+        this.members.length = 0; // remove all items from list
+        // now we remove all items from index reference
+        Object.keys(this.reference).forEach(function (key) {
+            delete this.reference[key];
+        }.bind(this));
+    },
+    /**
+     * Load one or more items
+     *
+     * @param {Object|Array} items
+     */
+    populate: function (items) {
+        // if Type supports parsing of string headers then do it before adding it.
+        _.isString(items) && _.isFunction(this.Type.parse) && (items = this.Type.parse(items));
+        // add a single item or an array of items.
+        _.forEach(_.isArray(items) ? items :
+            // if population is not an array, we send this as single item in an array or send each property separately
+            // if the core Type supports Type.create
+            ((_.isPlainObject(items) && _.has(this.Type, 'create')) ? items : [items]), this.add.bind(this));
+    },
+    /**
+     * Clears the list and adds new items.
+     *
+     * @param {Object|Array} items
+     */
+    repopulate: function (items) {
+        this.clear();
+        this.populate(items);
+    },
+    /**
+     * Add or update values from a source list.
+     *
+     * @param {PropertyList|Array} source
+     * @param {Boolean} [prune=false] Setting this to `true` will cause the extra items from the list to be deleted
+     */
+    assimilate: function (source, prune) {
+        var members = PropertyList.isPropertyList(source) ? source.members : source, list = this, indexer = list._postman_listIndexKey, sourceKeys = {}; // keeps track of added / updated keys for later exclusion
+        if (!_.isArray(members)) {
+            return;
+        }
+        members.forEach(function (item) {
+            if (!(item && item.hasOwnProperty(indexer))) {
+                return;
+            }
+            list.upsert(item);
+            sourceKeys[item[indexer]] = true;
+        });
+        // now remove any variable that is not in source object
+        // @note - using direct `this.reference` list of keys here so that we can mutate the list while iterating
+        // on it
+        if (prune) {
+            _.forEach(list.reference, function (value, key) {
+                if (sourceKeys.hasOwnProperty(key)) {
+                    return;
+                } // de not delete if source obj has this variable
+                list.remove(key); // use PropertyList functions to remove so that the .members array is cleared too
+            });
+        }
+    },
+    /**
+     * Returns a map of all items.
+     *
+     * @returns {Object}
+     */
+    all: function () {
+        return _.clone(this.members);
+    },
+    /**
+     * Get Item in this list by `ID` reference. If multiple values are allowed, the last value is returned.
+     *
+     * @param {String} id
+     * @returns {PropertyList.Type}
+     */
+    one: function (id) {
+        var val = this.reference[this._postman_listIndexCaseInsensitive ? String(id).toLowerCase() : id];
+        if (this._postman_listAllowsMultipleValues && Array.isArray(val)) {
+            return val.length ? val[val.length - 1] : undefined;
+        }
+        return val;
+    },
+    /**
+     * Get the value of an item in this list. This is similar to {@link PropertyList.one} barring the fact that it
+     * returns the value of the underlying type of the list content instead of the item itself.
+     *
+     * @param {String|Function} key
+     * @returns {PropertyList.Type|*}
+     */
+    get: function (key) {
+        var member = this.one(key);
+        if (!member) {
+            return;
+        } // eslint-disable-line getter-return
+        return member.valueOf();
+    },
+    /**
+     * Iterate on each item of this list.
+     *
+     * @param {Function} iterator
+     * @param {Object} context
+     */
+    each: function (iterator, context) {
+        _.forEach(this.members, _.isFunction(iterator) ? iterator.bind(context || this.__parent) : iterator);
+    },
+    /**
+     * @param {Function} rule
+     * @param {Object} context
+     */
+    filter: function (rule, context) {
+        return _.filter(this.members, _.isFunction(rule) && _.isObject(context) ? rule.bind(context) : rule);
+    },
+    /**
+     * Find an item within the item group
+     *
+     * @param {Function} rule
+     * @param {Object} [context]
+     * @returns {Item|ItemGroup}
+     */
+    find: function (rule, context) {
+        return _.find(this.members, _.isFunction(rule) && _.isObject(context) ? rule.bind(context) : rule);
+    },
+    /**
+     * Iterates over the property list.
+     *
+     * @param {Function} iterator Function to call on each item.
+     * @param {Object} context Optional context, defaults to the PropertyList itself.
+     */
+    map: function (iterator, context) {
+        return _.map(this.members, _.isFunction(iterator) ? iterator.bind(context || this) : iterator);
+    },
+    /**
+     * Iterates over the property list and accumulates the result.
+     *
+     * @param {Function} iterator Function to call on each item.
+     * @param {*} accumulator Accumulator initial value
+     * @param {Object} context Optional context, defaults to the PropertyList itself.
+     */
+    reduce: function (iterator, accumulator, context) {
+        return _.reduce(this.members, _.isFunction(iterator) ? iterator.bind(context || this) : iterator, accumulator);
+    },
+    /**
+     * Returns the length of the PropertyList
+     *
+     * @returns {Number}
+     */
+    count: function () {
+        return this.members.length;
+    },
+    /**
+     * Get a member of this list by it's index
+     *
+     * @param {Number} index
+     * @returns {PropertyList.Type}
+     */
+    idx: function (index) {
+        return this.members[index];
+    },
+    /**
+     * Find the index of an item in this list
+     *
+     * @param {String|Object} item
+     * @returns {Number}
+     */
+    indexOf: function (item) {
+        return this.members.indexOf(_.isString(item) ? (item = this.one(item)) : item);
+    },
+    /**
+     * Check whether an item exists in this list
+     *
+     * @param {String|PropertyList.Type} item
+     * @param {*=} value
+     * @returns {Boolean}
+     */
+    has: function (item, value) {
+        var match, val, i;
+        match = _.isString(item) ?
+            this.reference[this._postman_listIndexCaseInsensitive ? item.toLowerCase() : item] :
+            this.filter(function (member) {
+                return member === item;
+            });
+        // If we don't have a match, there's nothing to do
+        if (!match) {
+            return false;
+        }
+        // if no value is provided, just check if item exists
+        if (arguments.length === 1) {
+            return Boolean(_.isArray(match) ? match.length : match);
+        }
+        // If this property allows multiple values and we get an array, we need to iterate through it and see
+        // if any element matches.
+        if (this._postman_listAllowsMultipleValues && _.isArray(match)) {
+            for (i = 0; i < match.length; i++) {
+                // use the value of the current element
+                val = _.isFunction(match[i].valueOf) ? match[i].valueOf() : match[i];
+                if (val === value) {
+                    return true;
+                }
+            }
+            // no matches were found, so return false here.
+            return false;
+        }
+        // We didn't have an array, so just check if the matched value equals the provided value.
+        _.isFunction(match.valueOf) && (match = match.valueOf());
+        return match === value;
+    },
+    /**
+     * Iterates over all parents of the property list
+     *
+     * @param {Function} iterator
+     * @param {Object=} [context]
+     */
+    eachParent: function (iterator, context) {
+        // validate parameters
+        if (!_.isFunction(iterator)) {
+            return;
+        }
+        !context && (context = this);
+        var parent = this.__parent, prev;
+        // iterate till there is no parent
+        while (parent) {
+            // call iterator with the parent and previous parent
+            iterator.call(context, parent, prev);
+            // update references
+            prev = parent;
+            parent = parent.__parent;
+        }
+    },
+    /**
+     * Converts a list of Properties into an object where key is `_postman_propertyIndexKey` and value is determined
+     * by the `valueOf` function
+     *
+     * @param {?Boolean} [excludeDisabled=false] - When set to true, disabled properties are excluded from the resultant
+     * object.
+     * @param {?Boolean} [caseSensitive] - When set to true, properties are treated strictly as per their original
+     * case. The default value for this property also depends on the case insensitivity definition of the current
+     * property.
+     * @param {?Boolean} [multiValue=false] - When set to true, only the first value of a multi valued property is
+     * returned.
+     * @param {Boolean} [sanitizeKeys=false] - When set to true, properties with falsy keys are removed.
+     * @todo Change the function signature to an object of options instead of the current structure.
+     * @return {Object}
+     */
+    toObject: function (excludeDisabled, caseSensitive, multiValue, sanitizeKeys) {
+        var obj = {}, // create transformation data accumulator
+        // gather all the switches of the list
+        key = this._postman_listIndexKey, sanitiseKeys = this._postman_sanitizeKeys || sanitizeKeys, sensitive = !this._postman_listIndexCaseInsensitive || caseSensitive, multivalue = this._postman_listAllowsMultipleValues || multiValue;
+        // iterate on each member to create the transformation object
+        this.each(function (member) {
+            // Bail out for the current member if ANY of the conditions below is true:
+            // 1. The member is falsy.
+            // 2. The member does not have the specified property list index key.
+            // 3. The member is disabled and disabled properties have to be ignored.
+            // 4. The member has a falsy key, and sanitize is true.
+            if (!member || !member.hasOwnProperty(key) || (excludeDisabled && member.disabled) ||
+                (sanitiseKeys && !member[key])) {
+                return;
+            }
+            // based on case sensitivity settings, we get the property name of the item
+            var prop = sensitive ? member[key] : String(member[key]).toLowerCase();
+            // now, if transformation object already has a member with same property name, we either overwrite it or
+            // append to an array of values based on multi-value support
+            if (multivalue && obj.hasOwnProperty(prop)) {
+                (!Array.isArray(obj[prop])) && (obj[prop] = [obj[prop]]);
+                obj[prop].push(member.valueOf());
+            }
+            else {
+                obj[prop] = member.valueOf();
+            }
+        });
+        return obj;
+    },
+    /**
+     * Adds ability to convert a list to a string provided it's underlying format has unparse function defined.
+     *
+     * @return {String}
+     */
+    toString: function () {
+        if (this.Type.unparse) {
+            return this.Type.unparse(this.members);
+        }
+        return this.constructor ? this.constructor.prototype.toString.call(this) : '';
+    },
+    toJSON: function () {
+        if (!this.count()) {
+            return [];
+        }
+        return _.map(this.members, function (member) {
+            // use member.toJSON if it exists
+            if (!_.isEmpty(member) && _.isFunction(member.toJSON)) {
+                return member.toJSON();
+            }
+            return _.reduce(member, function (accumulator, value, key) {
+                if (value === undefined) { // true/false/null need to be preserved.
+                    return accumulator;
+                }
+                // Handle plurality of PropertyLists in the SDK vs the exported JSON.
+                // Basically, removes the trailing "s" from key if the value is a property list.
+                if (value && value._postman_propertyIsList && !value._postman_proprtyIsSerialisedAsPlural &&
+                    _.endsWith(key, 's')) {
+                    key = key.slice(0, -1);
+                }
+                // Handle 'PropertyBase's
+                if (value && _.isFunction(value.toJSON)) {
+                    accumulator[key] = value.toJSON();
+                    return accumulator;
+                }
+                // Handle Strings
+                if (_.isString(value)) {
+                    accumulator[key] = value;
+                    return accumulator;
+                }
+                // Everything else
+                accumulator[key] = _.cloneElement(value);
+                return accumulator;
+            }, {});
+        });
+    }
+});
+_.assign(PropertyList, /** @lends PropertyList */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'PropertyList',
+    /**
+     * Removes child-parent links for the provided PropertyList member.
+     *
+     * @param {Property} item - The property for which to perform parent de-linking.
+     * @private
+     */
+    _unlinkItemFromParent: function (item) {
+        item.__parent && (delete item.__parent); // prevents V8 from making unnecessary look-ups if there is no __parent
+    },
+    /**
+     * Checks whether an object is a PropertyList
+     *
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isPropertyList: function (obj) {
+        return Boolean(obj) && ((obj instanceof PropertyList) ||
+            _.inSuperChain(obj.constructor, '_postman_propertyName', PropertyList._postman_propertyName));
+    }
+});
+module.exports = {
+    PropertyList: PropertyList
+};

+ 21 - 0
dist/codegens/postman-collection-lite/collection/property.d.ts

@@ -0,0 +1,21 @@
+export var Property: any;
+export namespace Property {
+    export type definition = {
+        /**
+         * A unique string that identifies the property.
+         */
+        id?: string | undefined;
+        /**
+         * A distinctive and human-readable name of the property.
+         */
+        name?: string | undefined;
+        /**
+         * Denotes whether the property is disabled or not.
+         */
+        disabled?: boolean | undefined;
+        /**
+         * The meta information regarding the Property is provided as the `info` object.
+         */
+        info?: any;
+    };
+}

+ 135 - 0
dist/codegens/postman-collection-lite/collection/property.js

@@ -0,0 +1,135 @@
+"use strict";
+var _ = require('../../lodash'), PropertyBase = require('./property-base').PropertyBase, DISABLED = 'disabled', DESCRIPTION = 'description', Property; // constructor
+/**
+ * @typedef Property.definition
+ * @property {String=} [id] A unique string that identifies the property.
+ * @property {String=} [name] A distinctive and human-readable name of the property.
+ * @property {Boolean=} [disabled] Denotes whether the property is disabled or not.
+ * @property {Object=} [info] The meta information regarding the Property is provided as the `info` object.
+ * @property {String=} [info.id] If set, this is used instead of the definition root's id.
+ * @property {String=} [info.name] If set, this is used instead of the definition root's name.
+ */
+_.inherit((
+/**
+ * The Property class forms the base of all postman collection SDK elements. This is to be used only for SDK
+ * development or to extend the SDK with additional functionalities. All SDK classes (constructors) that are
+ * supposed to be identifyable (i.e. ones that can have a `name` and `id`) are derived from this class.
+ *
+ * For more information on what is the structure of the `definition` the function parameter, have a look at
+ * {@link Property.definition}.
+ *
+ * > This is intended to be a private class except for those who want to extend the SDK itself and add more
+ * > functionalities.
+ *
+ * @constructor
+ * @extends {PropertyBase}
+ *
+ * @param {Property.definition=} [definition] Every constructor inherited from `Property` is required to call the
+ * super constructor function. This implies that construction parameters of every inherited member is propagated
+ * to be sent up to this point.
+ *
+ * @see Property.definition
+ */
+Property = function PostmanProperty(definition) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    Property.super_.apply(this, arguments);
+    // The definition can have an `info` object that stores the identification of this property. If that is present,
+    // we use it instead of the definition root.
+    var src = definition && definition.info || definition, id;
+    // first we extract id from all possible sources
+    // we also check if this property is marked to require an ID, we generate one if not found.
+    id = (src && src.id) || this.id || (this._ && this._.postman_id) || (this._postman_propertyRequiresId &&
+        Math.random().toString(16).substr(2) /* uuid.v4() */);
+    /**
+     * The `id` of the property is a unique string that identifies this property and can be used to refer to
+     * this property from relevant other places. It is a good practice to define the id or let the system
+     * auto generate a UUID if one is not defined for properties that require an `id`.
+     * @name id
+     * @type {String}
+     * @memberOf Property.prototype
+     *
+     * @note The property can also be present in the `postman_id` meta in case it is not specified in the
+     * object. An auto-generated property is used wherever one is not specified
+     */
+    id && (this.id = id);
+    /**
+     * A property can have a distinctive and human-readable name. This is to be used to display the name of the
+     * property within Postman, Newman or other runtimes that consume collection. In certain cases, the absence
+     * of name might cause the runtime to use the `id` as a fallback.
+     * @name name
+     * @memberOf Property.prototype
+     * @type {String}
+     */
+    src && src.name && (this.name = src.name);
+    /**
+     * This (optional) flag denotes whether this property is disabled or not. Usually, this is helpful when a
+     * property is part of a {@link PropertyList}. For example, in a PropertyList of {@link Header}s, the ones
+     * that are disabled can be filtered out and not processed.
+     * @type {Boolean}
+     * @optional
+     * @name disabled
+     *
+     * @memberOf Property.prototype
+     */
+    definition && _.has(definition, DISABLED) && (this.disabled = Boolean(definition.disabled));
+}), PropertyBase);
+_.assign(Property.prototype, /** @lends Property.prototype */ {
+    /**
+     * Returns an object representation of the Property with its variable references substituted.
+     *
+     * @example <caption>Resolve an object using variable definitions from itself and its parents</caption>
+     * property.toObjectResolved();
+     *
+     * @example <caption>Resolve an object using variable definitions on a different object</caption>
+     * property.toObjectResolved(item);
+     *
+     * @example <caption>Resolve an object using variables definitions as a flat list of variables</caption>
+     * property.toObjectResolved(null, [variablesDefinition1, variablesDefinition1], {ignoreOwnVariables: true});
+     *
+     * @private
+     * @draft
+     * @param {?Item|ItemGroup=} [scope] - One can specifically provide an item or group with `.variables`. In
+     * the event one is not provided, the variables are taken from this object or one from the parent tree.
+     * @param {Array<Object>} overrides - additional objects to lookup for variable values
+     * @param {Object} [options]
+     * @param {Boolean} [options.ignoreOwnVariables] - if set to true, `.variables` on self(or scope)
+     * will not be used for variable resolution. Only variables in `overrides` will be used for resolution.
+     * @returns {Object|undefined}
+     * @throws {Error} If `variables` cannot be resolved up the parent chain.
+     */
+    toObjectResolved: function (scope, overrides, options) {
+        var ignoreOwnVariables = options && options.ignoreOwnVariables, variableSourceObj, variables, reference;
+        // ensure you do not substitute variables itself!
+        reference = this.toJSON();
+        _.isArray(reference.variable) && (delete reference.variable);
+        // if `ignoreScopeVariables` is turned on, ignore `.variables` and resolve with only `overrides`
+        // otherwise find `.variables` on current object or `scope`
+        if (ignoreOwnVariables) {
+            return Property.replaceSubstitutionsIn(reference, overrides);
+        }
+        // 1. if variables is passed as params, use it or fall back to oneself
+        // 2. for a source from point (1), and look for `.variables`
+        // 3. if `.variables` is not found, then rise up the parent to find first .variables
+        variableSourceObj = scope || this;
+        do {
+            variables = variableSourceObj.variables;
+            variableSourceObj = variableSourceObj.__parent;
+        } while (!variables && variableSourceObj);
+        if (!variables) { // worst case = no variable param and none detected in tree or object
+            throw Error('Unable to resolve variables. Require a List type property for variable auto resolution.');
+        }
+        return variables.substitute(reference, overrides);
+    }
+});
+_.assign(Property, /** @lends Property */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'Property',
+});
+module.exports = {
+    Property: Property
+};

+ 13 - 0
dist/codegens/postman-collection-lite/collection/query-param.d.ts

@@ -0,0 +1,13 @@
+export var QueryParam: any;
+export namespace QueryParam {
+    export type definition = {
+        /**
+         * The name ("key") of the query parameter.
+         */
+        key: string;
+        /**
+         * The value of the parameter.
+         */
+        value: string;
+    };
+}

+ 244 - 0
dist/codegens/postman-collection-lite/collection/query-param.js

@@ -0,0 +1,244 @@
+"use strict";
+var _ = require('../../lodash'), 
+// @todo discontinue in v4
+encodeQueryParam = require('postman-url-encoder/encoder').encodeQueryParam, Property = require('./property').Property, PropertyList = require('./property-list').PropertyList, E = '', AMPERSAND = '&', STRING = 'string', EQUALS = '=', EMPTY = '', HASH = '#', BRACE_START = '{{', BRACE_END = '}}', REGEX_HASH = /#/g, REGEX_EQUALS = /=/g, // eslint-disable-line no-div-regex
+REGEX_AMPERSAND = /&/g, REGEX_BRACE_START = /%7B%7B/g, REGEX_BRACE_END = /%7D%7D/g, REGEX_EXTRACT_VARS = /{{[^{}]*[&#=][^{}]*}}/g, QueryParam, 
+/**
+ * Percent encode reserved chars (&, = and #) in the given string.
+ *
+ * @private
+ * @param {String} str
+ * @param {Boolean} encodeEquals
+ * @returns {String}
+ */
+encodeReservedChars = function (str, encodeEquals) {
+    if (!str) {
+        return str;
+    }
+    // eslint-disable-next-line lodash/prefer-includes
+    str.indexOf(AMPERSAND) !== -1 && (str = str.replace(REGEX_AMPERSAND, '%26'));
+    // eslint-disable-next-line lodash/prefer-includes
+    str.indexOf(HASH) !== -1 && (str = str.replace(REGEX_HASH, '%23'));
+    // eslint-disable-next-line lodash/prefer-includes
+    encodeEquals && str.indexOf(EQUALS) !== -1 && (str = str.replace(REGEX_EQUALS, '%3D'));
+    return str;
+}, 
+/**
+ * Normalize the given param string by percent-encoding the reserved chars
+ * such that it won't affect the re-parsing.
+ *
+ * @note `&`, `=` and `#` needs to be percent-encoded otherwise re-parsing
+ * the same URL string will generate different output
+ *
+ * @private
+ * @param {String} str
+ * @param {Boolean} encodeEquals
+ * @returns {String}
+ */
+normalizeParam = function (str, encodeEquals) {
+    // bail out if the given sting is null or empty
+    if (!(str && typeof str === STRING)) {
+        return str;
+    }
+    // bail out if the given string does not include reserved chars
+    // eslint-disable-next-line lodash/prefer-includes
+    if (str.indexOf(AMPERSAND) === -1 && str.indexOf(HASH) === -1) {
+        // eslint-disable-next-line lodash/prefer-includes
+        if (!(encodeEquals && str.indexOf(EQUALS) !== -1)) {
+            return str;
+        }
+    }
+    var normalizedString = '', pointer = 0, variable, match, index;
+    // find all the instances of {{<variable>}} which includes reserved chars
+    while ((match = REGEX_EXTRACT_VARS.exec(str)) !== null) {
+        variable = match[0];
+        index = match.index;
+        // [pointer, index) string is normalized + the matched variable
+        normalizedString += encodeReservedChars(str.slice(pointer, index), encodeEquals) + variable;
+        // update the pointer
+        pointer = index + variable.length;
+    }
+    // whatever left in the string is normalized as well
+    if (pointer < str.length) {
+        normalizedString += encodeReservedChars(str.slice(pointer), encodeEquals);
+    }
+    return normalizedString;
+};
+/**
+ * @typedef QueryParam.definition
+ * @property {String} key The name ("key") of the query parameter.
+ * @property {String} value The value of the parameter.
+ */
+_.inherit((
+/**
+ * Represents a URL query parameter, which can exist in request URL or POST data.
+ *
+ * @constructor
+ * @extends {Property}
+ * @param {FormParam.definition|String} options Pass the initial definition of the query parameter. In case of
+ * string, the query parameter is parsed using {@link QueryParam.parseSingle}.
+ */
+QueryParam = function PostmanQueryParam(options) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    QueryParam.super_.apply(this, arguments);
+    this.update(options);
+}), Property);
+_.assign(QueryParam.prototype, /** @lends QueryParam.prototype */ {
+    /**
+     * Converts the QueryParameter to a single param string.
+     *
+     * @returns {String}
+     */
+    toString: function () {
+        return QueryParam.unparseSingle(this);
+    },
+    /**
+     * Updates the key and value of the query parameter
+     *
+     * @param {String|Object} param
+     * @param {String} param.key
+     * @param {String=} [param.value]
+     */
+    update: function (param) {
+        _.assign(this, /** @lends QueryParam.prototype */ _.isString(param) ? QueryParam.parseSingle(param) : {
+            key: _.get(param, 'key'),
+            value: _.get(param, 'value')
+        });
+        _.has(param, 'system') && (this.system = param.system);
+    },
+    valueOf: function () {
+        return _.isString(this.value) ? this.value : EMPTY;
+    }
+});
+_.assign(QueryParam, /** @lends QueryParam */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'QueryParam',
+    /**
+     * Declare the list index key, so that property lists of query parameters work correctly
+     *
+     * @type {String}
+     */
+    _postman_propertyIndexKey: 'key',
+    /**
+     * Query params can have multiple values, so set this to true.
+     *
+     * @type {Boolean}
+     */
+    _postman_propertyAllowsMultipleValues: true,
+    /**
+     * Parse a query string into an array of objects, where each object contains a key and a value.
+     *
+     * @param {String} query
+     * @returns {Array}
+     */
+    parse: function (query) {
+        return _.isString(query) ? query.split(AMPERSAND).map(QueryParam.parseSingle) : [];
+    },
+    /**
+     * Parses a single query parameter.
+     *
+     * @param {String} param
+     * @param {Number} idx
+     * @param {String[]} all - array of all params, in case this is being called while parsing multiple params.
+     * @returns {{key: string|null, value: string|null}}
+     */
+    parseSingle: function (param, idx, all) {
+        // helps handle weird edge cases such as "/get?a=b&&"
+        if (param === EMPTY && // if param is empty
+            _.isNumber(idx) && // this and the next condition ensures that this is part of a map call
+            _.isArray(all) &&
+            idx !== (all && (all.length - 1))) { // not last parameter in the array
+            return { key: null, value: null };
+        }
+        var index = (typeof param === STRING) ? param.indexOf(EQUALS) : -1, paramObj = {};
+        // this means that there was no value for this key (not even blank, so we store this info) and the value is set
+        // to null
+        if (index < 0) {
+            paramObj.key = param.substr(0, param.length);
+            paramObj.value = null;
+        }
+        else {
+            paramObj.key = param.substr(0, index);
+            paramObj.value = param.substr(index + 1);
+        }
+        return paramObj;
+    },
+    /**
+     * Create a query string from array of parameters (or object of key-values). This function ensures that
+     * the double braces "{{" and "}}" are not URL-encoded on unparsing, which allows for variable-substitution.
+     *
+     * @param {Array|Object} params
+     * @param {Object=} options
+     * @param {?Boolean} [options.encode=false] - Enables URL encoding of the parameters
+     * @param {?Boolean} [options.ignoreDisabled=false] - Removes disabled query parameters when set to true.
+     * @returns {string}
+     *
+     * @deprecated since v3.4.6, drop support for `options.encode`
+     *
+     * @todo - remove disabled arg and flatten params (retain back compat)
+     */
+    unparse: function (params, options) {
+        if (!params) {
+            return EMPTY;
+        }
+        var str, firstEnabledParam = true, encode = options && options.encode, ignoreDisabled = options && options.ignoreDisabled;
+        // Convert hash maps to an array of params
+        if (!_.isArray(params) && !PropertyList.isPropertyList(params)) {
+            return _.reduce(params, function (result, value, key) {
+                result && (result += AMPERSAND);
+                return result + QueryParam.unparseSingle({ key: key, value: value }, encode);
+            }, EMPTY);
+        }
+        // construct a query parameter string from the list, with considerations for disabled values
+        str = params.reduce(function (result, param) {
+            // If disabled parameters are to be ignored, bail out here
+            if (ignoreDisabled && (param.disabled === true)) {
+                return result;
+            }
+            // don't add '&' for the very first enabled param
+            if (firstEnabledParam) {
+                firstEnabledParam = false;
+            }
+            // add '&' before concatenating param
+            else {
+                result += AMPERSAND;
+            }
+            return result + QueryParam.unparseSingle(param, encode);
+        }, EMPTY);
+        encode && (str = str.replace(REGEX_BRACE_START, BRACE_START).replace(REGEX_BRACE_END, BRACE_END));
+        return str;
+    },
+    /**
+     * Takes a query param and converts to string
+     *
+     * @param {Object} obj
+     * @param {Boolean} encode
+     * @returns {String}
+     *
+     * @deprecated since v3.4.6, drop support for `encode`
+     */
+    unparseSingle: function (obj, encode) {
+        if (!obj) {
+            return EMPTY;
+        }
+        var key = obj.key, value = obj.value, result;
+        if (typeof key === STRING) {
+            result = encode ? encodeQueryParam(key) : normalizeParam(key, true);
+        }
+        else {
+            result = E;
+        }
+        if (typeof value === STRING) {
+            result += EQUALS + (encode ? encodeQueryParam(value) : normalizeParam(value));
+        }
+        return result;
+    }
+});
+module.exports = {
+    QueryParam: QueryParam
+};

+ 11 - 0
dist/codegens/postman-collection-lite/collection/request-body.d.ts

@@ -0,0 +1,11 @@
+export var RequestBody: any;
+export namespace RequestBody {
+    export type definition = {
+        mode: string;
+        raw: string;
+        file: string;
+        graphql: any;
+        formdata: any[];
+        urlencoded: string | any[];
+    };
+}

+ 206 - 0
dist/codegens/postman-collection-lite/collection/request-body.js

@@ -0,0 +1,206 @@
+"use strict";
+var _ = require('../../lodash'), PropertyBase = require('./property-base').PropertyBase, PropertyList = require('./property-list').PropertyList, QueryParam = require('./query-param').QueryParam, FormParam = require('./form-param').FormParam, EMPTY = '', RequestBody;
+/**
+ * @typedef RequestBody.definition
+ * @property {String} mode
+ * @property {String} raw
+ * @property {String} file
+ * @property {Object} graphql
+ * @property {Object[]} formdata
+ * @property {Object[]|String} urlencoded
+ */
+_.inherit((
+/**
+ * RequestBody holds data related to the request body. By default, it provides a nice wrapper for url-encoded,
+ * form-data, and raw types of request bodies.
+ *
+ * @constructor
+ * @extends {PropertyBase}
+ *
+ * @param {Object} options
+ */
+RequestBody = function PostmanRequestBody(options) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    RequestBody.super_.apply(this, arguments);
+    if (!options) {
+        return;
+    } // in case definition object is missing, there is no point moving forward
+    this.update(options);
+}), PropertyBase);
+_.assign(RequestBody.prototype, /** @lends RequestBody.prototype */ {
+    /**
+     * Set the content of this request data
+     *
+     * @param {Object} options
+     */
+    update: function (options) {
+        _.isString(options) && (options = { mode: 'raw', raw: options });
+        if (!options.mode) {
+            return;
+        } // need a valid mode @todo raise error?
+        var mode = RequestBody.MODES[options.mode.toString().toLowerCase()] || RequestBody.MODES.raw, urlencoded = options.urlencoded, formdata = options.formdata, graphql = options.graphql, file = options.file, raw = options.raw;
+        // Handle URL Encoded data
+        if (options.urlencoded) {
+            _.isString(options.urlencoded) && (urlencoded = QueryParam.parse(options.urlencoded));
+            // @todo: The fallback in the ternary expression will never be hit, as urlencoded points to
+            // @todo: options.urlencoded
+            urlencoded = urlencoded ? new PropertyList(QueryParam, this, urlencoded) :
+                new PropertyList(QueryParam, this, []);
+        }
+        // Handle Form data
+        if (options.formdata) {
+            // @todo: The fallback in the ternary expression will never be hit, as formdata points to
+            // @todo: options.formdata
+            formdata = formdata ? new PropertyList(FormParam, this, options.formdata) :
+                new PropertyList(FormParam, this, []);
+        }
+        // Handle GraphQL data
+        if (options.graphql) {
+            graphql = {
+                query: graphql.query,
+                operationName: graphql.operationName,
+                variables: graphql.variables
+            };
+        }
+        _.isString(options.file) && (file = { src: file });
+        // If mode is raw but options does not give raw content, set it to empty string
+        (mode === RequestBody.MODES.raw && !raw) && (raw = '');
+        // If mode is urlencoded but options does not provide any content, set it to an empty property list
+        (mode === RequestBody.MODES.urlencoded && !urlencoded) && (urlencoded = new PropertyList(QueryParam, this, []));
+        // If mode is formdata but options does not provide any content, set it to an empty property list
+        (mode === RequestBody.MODES.formdata && !formdata) && (formdata = new PropertyList(FormParam, this, []));
+        // If mode is graphql but options does not provide any content, set empty query
+        (mode === RequestBody.MODES.graphql && !graphql) && (graphql = {});
+        _.assign(this, /** @lends RequestBody.prototype */ {
+            /**
+             * Indicates the type of request data to use.
+             *
+             * @type {String}
+             */
+            mode: mode,
+            /**
+             * If the request has raw body data associated with it, the data is held in this field.
+             *
+             * @type {String}
+             */
+            raw: raw,
+            /**
+             * Any URL encoded body params go here.
+             *
+             * @type {PropertyList<QueryParam>}
+             */
+            urlencoded: urlencoded,
+            /**
+             * Form data parameters for this request are held in this field.
+             *
+             * @type {PropertyList<FormParam>}
+             */
+            formdata: formdata,
+            /**
+             * Holds a reference to a file which should be read as the RequestBody. It can be a file path (when used
+             * with Node) or a unique ID (when used with the browser).
+             *
+             * @note The reference stored here should be resolved by a resolver function (which should be provided to
+             * the Postman Runtime).
+             */
+            file: file,
+            /**
+             * If the request has raw graphql data associated with it, the data is held in this field.
+             *
+             * @type {Object}
+             */
+            graphql: graphql,
+            /**
+             * If the request has body Options associated with it, the data is held in this field.
+             *
+             * @type {Object}
+             */
+            options: _.isObject(options.options) ? options.options : undefined,
+            /**
+             * Indicates whether to include body in request or not.
+             *
+             * @type {Boolean}
+             */
+            disabled: options.disabled
+        });
+    },
+    /**
+     * Stringifies and returns the request body.
+     *
+     * @note FormData is not supported yet.
+     * @returns {*}
+     */
+    toString: function () {
+        // Formdata. Goodluck.
+        if (this.mode === RequestBody.MODES.formdata || this.mode === RequestBody.MODES.file) {
+            // @todo: implement this, check if we need to return undefined or something.
+            return EMPTY;
+        }
+        if (this.mode === RequestBody.MODES.urlencoded) {
+            return PropertyList.isPropertyList(this.urlencoded) ? QueryParam.unparse(this.urlencoded.all()) :
+                ((this.urlencoded && _.isFunction(this.urlencoded.toString)) ? this.urlencoded.toString() : EMPTY);
+        }
+        if (this.mode === RequestBody.MODES.raw) {
+            return (this.raw && _.isFunction(this.raw.toString)) ? this.raw.toString() : EMPTY;
+        }
+        return EMPTY;
+    },
+    /**
+     * If the request body is set to a mode, but does not contain data, then we should not be sending it.
+     *
+     * @returns {Boolean}
+     */
+    isEmpty: function () {
+        var mode = this.mode, data = mode && this[mode];
+        // bail out if there's no data for the selected mode
+        if (!data) {
+            return true;
+        }
+        // Handle file mode
+        // @note this is a legacy exception. ideally every individual data mode
+        // in future would declare its "empty state".
+        if (mode === RequestBody.MODES.file) {
+            return !(data.src || data.content);
+        }
+        if (_.isString(data)) {
+            return (data.length === 0);
+        }
+        if (_.isFunction(data.count)) { // handle for property lists
+            return (data.count() === 0);
+        }
+        return _.isEmpty(data); // catch all for remaining data modes
+    },
+    /**
+     * Convert the request body to JSON compatible plain object
+     *
+     * @returns {Object}
+     */
+    toJSON: function () {
+        var obj = PropertyBase.toJSON(this);
+        // make sure that file content is removed because it is non-serializable ReadStream
+        _.unset(obj, 'file.content');
+        return obj;
+    }
+});
+_.assign(RequestBody, /** @lends RequestBody **/ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'RequestBody',
+    /**
+     * @enum {string} MODES
+     */
+    MODES: {
+        file: 'file',
+        formdata: 'formdata',
+        graphql: 'graphql',
+        raw: 'raw',
+        urlencoded: 'urlencoded'
+    }
+});
+module.exports = {
+    RequestBody: RequestBody
+};

+ 33 - 0
dist/codegens/postman-collection-lite/collection/request.d.ts

@@ -0,0 +1,33 @@
+export var Request: any;
+export namespace Request {
+    export type definition = {
+        /**
+         * The URL of the request. This can be a {@link Url.definition} or a string.
+         */
+        url: string | ((options: any, ...args: any[]) => void);
+        /**
+         * The request method, e.g: "GET" or "POST".
+         */
+        method: string;
+        /**
+         * The headers that should be sent as a part of this request.
+         */
+        header: any[];
+        /**
+         * The request body definition.
+         */
+        body: any;
+        /**
+         * The authentication/signing information for this request.
+         */
+        auth: any;
+        /**
+         * The proxy information for this request.
+         */
+        proxy: any;
+        /**
+         * The certificate information for this request.
+         */
+        certificate: any;
+    };
+}

+ 317 - 0
dist/codegens/postman-collection-lite/collection/request.js

@@ -0,0 +1,317 @@
+"use strict";
+var _ = require('../../lodash'), PropertyBase = require('./property-base').PropertyBase, Property = require('./property').Property, Url = require('./url').Url, 
+// ProxyConfig = require('./proxy-config').ProxyConfig,
+// Certificate = require('./certificate').Certificate,
+HeaderList = require('./header-list').HeaderList, RequestBody = require('./request-body').RequestBody, 
+// RequestAuth = require('./request-auth').RequestAuth,
+Request, 
+/**
+ * Default request method
+ *
+ * @private
+ * @const
+ * @type {String}
+ */
+DEFAULT_REQ_METHOD = 'GET', 
+/**
+ * Content length header name
+ *
+ * @private
+ * @const
+ * @type {String}
+ */
+CONTENT_LENGTH = 'Content-Length', 
+/**
+ * Single space
+ *
+ * @private
+ * @const
+ * @type {String}
+ */
+SP = ' ', 
+/**
+ * Carriage return + line feed
+ *
+ * @private
+ * @const
+ * @type {String}
+ */
+CRLF = '\r\n', 
+/**
+ * HTTP version
+ *
+ * @private
+ * @const
+ * @type {String}
+ */
+HTTP_X_X = 'HTTP/X.X', 
+/**
+ * @private
+ * @type {Boolean}
+ */
+supportsBuffer = (typeof Buffer !== undefined) && _.isFunction(Buffer.byteLength), 
+/**
+ * Source of request body size calculation.
+ * Either computed from body or used Content-Length header value.
+ *
+ * @private
+ * @const
+ * @type {Object}
+ */
+SIZE_SOURCE = {
+    computed: 'COMPUTED',
+    contentLength: 'CONTENT-LENGTH'
+};
+/**
+ * @typedef Request.definition
+ * @property {String|Url} url The URL of the request. This can be a {@link Url.definition} or a string.
+ * @property {String} method The request method, e.g: "GET" or "POST".
+ * @property {Array<Header.definition>} header The headers that should be sent as a part of this request.
+ * @property {RequestBody.definition} body The request body definition.
+ * @property {RequestAuth.definition} auth The authentication/signing information for this request.
+ * @property {ProxyConfig.definition} proxy The proxy information for this request.
+ * @property {Certificate.definition} certificate The certificate information for this request.
+ */
+_.inherit((
+/**
+ * A Postman HTTP request object.
+ *
+ * @constructor
+ * @extends {Property}
+ * @param {Request.definition} options
+ */
+Request = function PostmanRequest(options) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    Request.super_.apply(this, arguments);
+    // if the definition is a string, it implies that this is a get of URL
+    (typeof options === 'string') && (options = {
+        url: options
+    });
+    // Create the default properties
+    _.assign(this, /** @lends Request.prototype */ {
+        /**
+         * @type {Url}
+         */
+        url: new Url(),
+        /**
+         * @type {HeaderList}
+         */
+        headers: new HeaderList(this, options && options.header),
+        // Although a similar check is being done in the .update call below, this handles falsy options as well.
+        /**
+         * @type {String}
+         * @todo: Clean this up
+         */
+        // the negated condition is required to keep DEFAULT_REQ_METHOD as a fallback
+        method: _.has(options, 'method') && !_.isNil(options.method) ?
+            String(options.method).toUpperCase() : DEFAULT_REQ_METHOD
+    });
+    this.update(options);
+}), Property);
+_.assign(Request.prototype, /** @lends Request.prototype */ {
+    /**
+     * Updates the different properties of the request.
+     *
+     * @param {Request.definition} options
+     */
+    update: function (options) {
+        // Nothing to do
+        if (!options) {
+            return;
+        }
+        // The existing url is updated.
+        _.has(options, 'url') && this.url.update(options.url);
+        // The existing list of headers must be cleared before adding the given headers to it.
+        options.header && this.headers.repopulate(options.header);
+        // Only update the method if one is provided.
+        _.has(options, 'method') && (this.method = _.isNil(options.method) ?
+            DEFAULT_REQ_METHOD : String(options.method).toUpperCase());
+        // The rest of the properties are not assumed to exist so we merge in the defined ones.
+        _.mergeDefined(this, /** @lends Request.prototype */ {
+            /**
+             * @type {RequestBody|undefined}
+             */
+            body: _.createDefined(options, 'body', RequestBody),
+        });
+    },
+    /**
+     * Returns an object where the key is a header name and value is the header value.
+     *
+     * @param {Object=} options
+     * @param {Boolean} options.ignoreCase When set to "true", will ensure that all the header keys are lower case.
+     * @param {Boolean} options.enabled Only get the enabled headers
+     * @param {Boolean} options.multiValue When set to "true", duplicate header values will be stored in an array
+     * @param {Boolean} options.sanitizeKeys When set to "true", headers with falsy keys are removed
+     * @returns {Object}
+     * @note If multiple headers are present in the same collection with same name, but different case
+     * (E.g "x-forward-port" and "X-Forward-Port", and `options.ignoreCase` is set to true,
+     * the values will be stored in an array.
+     */
+    getHeaders: function getHeaders(options) {
+        !options && (options = {});
+        // @note: options.multiValue will not be respected since, Header._postman_propertyAllowsMultipleValues
+        // gets higher precedence in PropertyLists.toObject.
+        // @todo: sanitizeKeys for headers by default.
+        return this.headers.toObject(options.enabled, !options.ignoreCase, options.multiValue, options.sanitizeKeys);
+    },
+    /**
+     * Calls the given callback on each Header object contained within the request.
+     *
+     * @param {Function} callback
+     */
+    forEachHeader: function forEachHeader(callback) {
+        this.headers.all().forEach(function (header) {
+            return callback(header, this);
+        }, this);
+    },
+    /**
+     * Adds a header to the PropertyList of headers.
+     *
+     * @param {Header| {key: String, value: String}} header Can be a {Header} object, or a raw header object.
+     */
+    addHeader: function (header) {
+        this.headers.add(header);
+    },
+    /**
+     * Removes a header from the request.
+     *
+     * @param {String|Header} toRemove A header object to remove, or a string containing the header key.
+     * @param {Object} options
+     * @param {Boolean} options.ignoreCase If set to true, ignores case while removing the header.
+     */
+    removeHeader: function (toRemove, options) {
+        toRemove = _.isString(toRemove) ? toRemove : toRemove.key;
+        options = options || {};
+        if (!toRemove) { // Nothing to remove :(
+            return;
+        }
+        options.ignoreCase && (toRemove = toRemove.toLowerCase());
+        this.headers.remove(function (header) {
+            var key = options.ignoreCase ? header.key.toLowerCase() : header.key;
+            return key === toRemove;
+        });
+    },
+    /**
+     * Updates or inserts the given header.
+     *
+     * @param {Object} header
+     */
+    upsertHeader: function (header) {
+        if (!(header && header.key)) {
+            return;
+        } // if no valid header is provided, do nothing
+        var existing = this.headers.find({ key: header.key });
+        if (!existing) {
+            return this.headers.add(header);
+        }
+        existing.value = header.value;
+    },
+    /**
+     * Add query parameters to the request.
+     *
+     * @todo: Rename this?
+     * @param {Array<QueryParam>|String} params
+     */
+    addQueryParams: function (params) {
+        this.url.addQueryParams(params);
+    },
+    /**
+     * Removes parameters passed in params.
+     *
+     * @param {String|Array} params
+     */
+    removeQueryParams: function (params) {
+        this.url.removeQueryParams(params);
+    },
+    /**
+     * Get the request size by computing the headers and body or using the
+     * actual content length header once the request is sent.
+     *
+     * @returns {Object}
+     */
+    size: function () {
+        var contentLength = this.headers.get(CONTENT_LENGTH), requestTarget = this.url.getPathWithQuery(), bodyString, sizeInfo = {
+            body: 0,
+            header: 0,
+            total: 0,
+            source: SIZE_SOURCE.computed
+        };
+        // if 'Content-Length' header is present, we take body as declared by
+        // the client(postman-request or user-defined). else we need to compute the same.
+        if (contentLength && _.isNumeric(contentLength)) {
+            sizeInfo.body = parseInt(contentLength, 10);
+            sizeInfo.source = SIZE_SOURCE.contentLength;
+        }
+        // otherwise, if body is defined, we calculate the length of the body
+        else if (this.body) {
+            // @note body.toString() returns E for formdata or file mode
+            bodyString = this.body.toString();
+            sizeInfo.body = supportsBuffer ? Buffer.byteLength(bodyString) : bodyString.length;
+        }
+        // https://tools.ietf.org/html/rfc7230#section-3
+        // HTTP-message   = start-line (request-line / status-line)
+        //                  *( header-field CRLF )
+        //                  CRLF
+        //                  [ message-body ]
+        // request-line = method SP request-target SP HTTP-version CRLF
+        sizeInfo.header = (this.method + SP + requestTarget + SP + HTTP_X_X + CRLF + CRLF).length +
+            this.headers.contentSize();
+        // compute the approximate total body size by adding size of header and body
+        sizeInfo.total = (sizeInfo.body || 0) + (sizeInfo.header || 0);
+        return sizeInfo;
+    },
+    /**
+     * Converts the Request to a plain JavaScript object, which is also how the request is
+     * represented in a collection file.
+     *
+     * @returns {{url: (*|string), method: *, header: (undefined|*), body: *, auth: *, certificate: *}}
+     */
+    toJSON: function () {
+        var obj = PropertyBase.toJSON(this);
+        // remove header array if blank
+        if (_.isArray(obj.header) && !obj.header.length) {
+            delete obj.header;
+        }
+        return obj;
+    },
+    /**
+     * Creates a clone of this request
+     *
+     * @returns {Request}
+     */
+    clone: function () {
+        return new Request(this.toJSON());
+    },
+    /**
+     * Creates a copy of this request, with the appropriate auth headers or parameters added.
+     *
+     * @deprecated discontinued in v3.x
+     * @note This function does not take care of resolving variables.
+     * @returns {Request}
+     */
+    authorize: function () {
+        throw new Error('collection request.authorize() has been discontinued');
+    }
+});
+_.assign(Request, /** @lends Request */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'Request',
+    /**
+     * Check whether an object is an instance of {@link ItemGroup}.
+     *
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isRequest: function (obj) {
+        return Boolean(obj) && ((obj instanceof Request) ||
+            _.inSuperChain(obj.constructor, '_postman_propertyName', Request._postman_propertyName));
+    }
+});
+module.exports = {
+    Request: Request
+};

+ 1 - 0
dist/codegens/postman-collection-lite/collection/url.d.ts

@@ -0,0 +1 @@
+export var Url: any;

File diff suppressed because it is too large
+ 363 - 0
dist/codegens/postman-collection-lite/collection/url.js


+ 1 - 0
dist/codegens/postman-collection-lite/collection/variable-list.d.ts

@@ -0,0 +1 @@
+export var VariableList: any;

+ 166 - 0
dist/codegens/postman-collection-lite/collection/variable-list.js

@@ -0,0 +1,166 @@
+"use strict";
+var _ = require('../../lodash'), PropertyList = require('./property-list').PropertyList, Property = require('./property').Property, Variable = require('./variable').Variable, VariableList;
+_.inherit((
+/**
+ * @constructor
+ * @extends {PropertyList}
+ *
+ * @param {Property} parent
+ * @param {Object|Array} populate
+ */
+VariableList = function PostmanVariableList(parent, populate) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    VariableList.super_.call(this, Variable, parent, populate);
+}), PropertyList);
+_.assign(VariableList.prototype, /** @lends VariableList.prototype */ {
+    /**
+     * Replaces the variable tokens inside a string with its actual values.
+     *
+     * @param {String} str
+     * @param {Object} [overrides] - additional objects to lookup for variable values
+     * @returns {String}
+     */
+    replace: function (str, overrides) {
+        return Property.replaceSubstitutions(str, this, overrides);
+    },
+    /**
+     * Recursively replace strings in an object with instances of variables. Note that it clones the original object. If
+     * the `mutate` param is set to true, then it replaces the same object instead of creating a new one.
+     *
+     * @param {Array|Object} obj
+     * @param {?Array<Object>=} [overrides] - additional objects to lookup for variable values
+     * @param {Boolean=} [mutate=false]
+     * @returns {Array|Object}
+     */
+    substitute: function (obj, overrides, mutate) {
+        var resolutionQueue = [], // we use this to store the queue of variable hierarchy
+        // this is an intermediate object to stimulate a property (makes the do-while loop easier)
+        variableSource = {
+            variables: this,
+            __parent: this.__parent
+        };
+        do { // iterate and accumulate as long as you find `.variables` in parent tree
+            variableSource.variables && resolutionQueue.push(variableSource.variables);
+            variableSource = variableSource.__parent;
+        } while (variableSource);
+        variableSource = null; // cautious cleanup
+        return Property.replaceSubstitutionsIn(obj, _.union(resolutionQueue, overrides), mutate);
+    },
+    /**
+     * Using this function, one can sync the values of this variable list from a reference object.
+     *
+     * @param {Object} obj
+     * @param {Boolean=} track
+     * @param {Boolean} [prune=true]
+     *
+     * @returns {Object}
+     */
+    syncFromObject: function (obj, track, prune) {
+        var list = this, ops = track && {
+            created: [],
+            updated: [],
+            deleted: []
+        }, indexer = list._postman_listIndexKey, tmp;
+        if (!_.isObject(obj)) {
+            return ops;
+        }
+        // ensure that all properties in the object is updated in this list
+        _.forOwn(obj, function (value, key) {
+            // we need to create new variable if exists or update existing
+            if (list.has(key)) {
+                list.one(key).set(value);
+                ops && ops.updated.push(key);
+            }
+            else {
+                tmp = { value: value };
+                tmp[indexer] = key;
+                list.add(tmp);
+                tmp = null;
+                ops && ops.created.push(key);
+            }
+        });
+        // now remove any variable that is not in source object
+        // @note - using direct `this.reference` list of keys here so that we can mutate the list while iterating
+        // on it
+        if (prune !== false) {
+            _.forEach(list.reference, function (value, key) {
+                if (obj.hasOwnProperty(key)) {
+                    return;
+                } // de not delete if source obj has this variable
+                list.remove(key); // use PropertyList functions to remove so that the .members array is cleared too
+                ops && ops.deleted.push(key);
+            });
+        }
+        return ops;
+    },
+    /**
+     * Transfer all variables from this list to an object
+     *
+     * @param {Object=} [obj]
+     * @returns {Object}
+     */
+    syncToObject: function (obj) {
+        var list = this;
+        // in case user did not provide an object to mutate, create a new one
+        !_.isObject(obj) && (obj = {});
+        // delete extra variables from object that are not present in list
+        _.forEach(obj, function (value, key) {
+            !_.has(list.reference, key) && (delete obj[key]);
+        });
+        // we first sync all variables in this list to the object
+        list.each(function (variable) {
+            obj[variable.key] = variable.valueOf();
+        });
+        return obj;
+    },
+    /**
+     * Fetches a variable and normalize its reference if disabled.
+     * This updates the disabled variable `reference` in VariableList with its
+     * last enabled duplicate(if found) in the `members` list.
+     *
+     * @private
+     * @param {String} variableName - The name of the variable to get
+     * @returns {Variable} - In case of duplicates, returns last enabled
+     */
+    oneNormalizedVariable: function (variableName) {
+        var indexKey = this._postman_listIndexKey, // `key` for Variable
+        variable = this.reference[variableName], i;
+        if (variable && !variable.disabled) {
+            return variable;
+        }
+        // traverse the members list in reverse direction in order to find the last enabled
+        for (i = this.members.length - 1; i >= 0; i--) {
+            variable = this.members[i];
+            if (variable[indexKey] === variableName && !variable.disabled) {
+                // update the input variable reference if comparison is not disabled
+                this.reference[variableName] = variable;
+                break; // return updated reference variable
+            }
+        }
+        return this.reference[variableName];
+    }
+});
+_.assign(VariableList, /** @lends VariableList */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     *
+     * @note that this is directly accessed only in case of VariableList from _.findValue lodash util mixin
+     */
+    _postman_propertyName: 'VariableList',
+    /**
+     * Checks whether an object is a VariableList
+     *
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isVariableList: function (obj) {
+        return Boolean(obj) && ((obj instanceof VariableList) ||
+            _.inSuperChain(obj.constructor, '_postman_propertyName', VariableList._postman_propertyName));
+    }
+});
+module.exports = {
+    VariableList: VariableList
+};

+ 19 - 0
dist/codegens/postman-collection-lite/collection/variable.d.ts

@@ -0,0 +1,19 @@
+export var Variable: any;
+export namespace Variable {
+    /**
+     * The object representation of a Variable consists the variable value and type. It also optionally includes the `id`
+     * and a friendly `name` of the variable. The `id` and the `name` of a variable is usually managed and used when a
+     * variable is made part of a {@link VariableList} instance.
+     */
+    export type definition = {
+        /**
+         * - The value of the variable that will be stored and will be typecast to the `type`
+         * set in the variable or passed along in this parameter.
+         */
+        value?: any;
+        /**
+         * - The type of this variable from the list of types defined at {@link Variable.types}.
+         */
+        type?: string | undefined;
+    };
+}

+ 358 - 0
dist/codegens/postman-collection-lite/collection/variable.js

@@ -0,0 +1,358 @@
+"use strict";
+var _ = require('../../lodash'), Property = require('./property').Property, E = '', ANY = 'any', NULL = 'null', STRING = 'string', Variable;
+/**
+ * The object representation of a Variable consists the variable value and type. It also optionally includes the `id`
+ * and a friendly `name` of the variable. The `id` and the `name` of a variable is usually managed and used when a
+ * variable is made part of a {@link VariableList} instance.
+ *
+ * @typedef {Object} Variable.definition
+ * @property {*=} [value] - The value of the variable that will be stored and will be typecast to the `type`
+ * set in the variable or passed along in this parameter.
+ * @property {String=} [type] - The type of this variable from the list of types defined at {@link Variable.types}.
+ *
+ * @example
+ * {
+ *     "id": "my-var-1",
+ *     "name": "MyFirstVariable",
+ *     "value": "Hello World",
+ *     "type": "string"
+ * }
+ */
+_.inherit((
+/**
+ * A variable inside a collection is similar to variables in any programming construct. The variable has an
+ * identifier name (provided by its id) and a value. A variable is optionally accompanied by a variable type. One
+ * or more variables can be associated with a collection and can be referred from anywhere else in the collection
+ * using the double-brace {{variable-id}} format. Properties can then use the `.toObjectResolved` function to
+ * procure an object representation of the property with all variable references replaced by corresponding values.
+ *
+ * @constructor
+ * @extends {Property}
+ * @param {Variable.definition=} [definition] - Specify the initial value and type of the variable.
+ */
+Variable = function PostmanVariable(definition) {
+    // this constructor is intended to inherit and as such the super constructor is required to be executed
+    Variable.super_.apply(this, arguments);
+    // check what is the property name for indexing this variable
+    var indexer = this.constructor._postman_propertyIndexKey;
+    _.assign(this, /** @lends Variable.prototype */ {
+        /**
+         * @type {Variable.types}
+         */
+        type: ANY,
+        /**
+         * @type {*}
+         */
+        value: undefined
+    });
+    if (!_.isNil(definition)) {
+        /**
+         * The name of the variable. This is used for referencing this variable from other locations and scripts
+         * @type {String}
+         * @name key
+         * @memberOf Variable.prototype
+         */
+        _.has(definition, indexer) && (this[indexer] = definition[indexer]);
+        this.update(definition);
+    }
+}), Property);
+_.assign(Variable.prototype, /** @lends Variable.prototype */ {
+    /**
+     * Gets the value of the variable.
+     *
+     * @returns {Variable.types}
+     */
+    get: function () {
+        return _.isFunction(this.value) ? this.castOut(this.value()) : this.castOut(this.value);
+    },
+    /**
+     * Sets the value of the variable.
+     *
+     * @param {*} value
+     */
+    set: function (value) {
+        // @todo - figure out how secure is this!
+        this.value = _.isFunction(value) ? value : this.castIn(value);
+    },
+    /**
+     * An alias of this.get and this.set.
+     *
+     * @param {*=} [value]
+     * @returns {*}
+     */
+    valueOf: function (value) {
+        arguments.length && this.set(value);
+        return this.get();
+    },
+    /**
+     * Returns the stringified value of the variable.
+     *
+     * @returns {String}
+     */
+    toString: function () {
+        var value = this.valueOf();
+        // returns String representation of null as it's a valid JSON type
+        // refer: https://github.com/postmanlabs/postman-app-support/issues/8493
+        if (value === null) {
+            return NULL;
+        }
+        // returns empty string if the value is undefined or does not implement
+        // the toString method
+        return (!_.isNil(value) && _.isFunction(value.toString)) ? value.toString() : E;
+    },
+    /**
+     * Typecasts a value to the {@link Variable.types} of this {@link Variable}. Returns the value of the variable
+     * converted to the type specified in {@link Variable#type}.
+     *
+     * @param {*} value
+     * @returns {*}
+     */
+    cast: function (value) {
+        return this.castOut(value);
+    },
+    /**
+     * Typecasts a value to the {@link Variable.types} of this {@link Variable}. Returns the value of the variable
+     * converted to the type specified in {@link Variable#type}.
+     *
+     * @private
+     * @param {*} value
+     * @returns {*}
+     */
+    castIn: function (value) {
+        var handler = Variable.types[this.type] || Variable.types.any;
+        return _.isFunction(handler) ? handler(value) : handler.in(value);
+    },
+    /**
+     * Typecasts a value from the {@link Variable.types} of this {@link Variable}. Returns the value of the variable
+     * converted to the type specified in {@link Variable#type}.
+     *
+     * @private
+     * @param {*} value
+     * @returns {*}
+     */
+    castOut: function (value) {
+        var handler = Variable.types[this.type] || Variable.types.any;
+        return _.isFunction(handler) ? handler(value) : handler.out(value);
+    },
+    /**
+     * Sets or gets the type of the value.
+     *
+     * @param {String} typeName
+     * @param {Boolean} _noCast
+     * @returns {String} - returns the current type of the variable from the list of {@link Variable.types}
+     */
+    valueType: function (typeName, _noCast) {
+        !_.isNil(typeName) && (typeName = typeName.toString().toLowerCase()); // sanitize
+        if (!Variable.types[typeName]) {
+            return this.type || ANY; // @todo: throw new Error('Invalid variable type.');
+        }
+        // set type if it is valid
+        this.type = typeName;
+        // 1. get the current value
+        // 2. set the new type if it is valid and cast the stored value
+        // 3. then set the interstitial value
+        var interstitialCastValue;
+        // do not touch value functions
+        if (!(_noCast || _.isFunction(this.value))) {
+            interstitialCastValue = this.get();
+            this.set(interstitialCastValue);
+            interstitialCastValue = null; // just a precaution
+        }
+        return this.type;
+    },
+    /**
+     * Updates the type and value of a variable from an object or JSON definition of the variable.
+     *
+     * @param {Variable.definition} options
+     */
+    update: function (options) {
+        if (!_.isObject(options)) {
+            return;
+        }
+        // set type and value.
+        // @note that we cannot update the key, once created during construction
+        options.hasOwnProperty('type') && this.valueType(options.type, options.hasOwnProperty('value'));
+        options.hasOwnProperty('value') && this.set(options.value);
+        options.hasOwnProperty('system') && (this.system = options.system);
+        options.hasOwnProperty('disabled') && (this.disabled = options.disabled);
+    }
+});
+_.assign(Variable, /** @lends Variable */ {
+    /**
+     * Defines the name of this property for internal use.
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyName: 'Variable',
+    /**
+     * Specify the key to be used while indexing this object
+     * @private
+     * @readOnly
+     * @type {String}
+     */
+    _postman_propertyIndexKey: 'key',
+    /**
+     * The possible supported types of a variable is defined here. The keys defined here are the possible values of
+     * {@link Variable#type}.
+     *
+     * Additional variable types can be supported by adding the type-casting function to this enumeration.
+     * @enum {Function}
+     * @readonly
+     */
+    types: {
+        /**
+         * When a variable's `type` is set to "string", it ensures that {@link Variable#get} converts the value of the
+         * variable to a string before returning the data.
+         */
+        string: String,
+        /**
+         * A boolean type of variable can either be set to `true` or `false`. Any other value set is converted to
+         * Boolean when procured from {@link Variable#get}.
+         */
+        boolean: Boolean,
+        /**
+         * A "number" type variable ensures that the value is always represented as a number. A non-number type value
+         * is returned as `NaN`.
+         */
+        number: Number,
+        /**
+         * A "json" type value stores JSON data format
+         * @deprecated Use "object" or "array" type instead. To be removed in 4.0.
+         */
+        json: {
+            /**
+             * @param {Object|Array} val
+             * @returns {String}
+             */
+            in: function (val) {
+                try {
+                    // @todo: should we check if `val` is a valid JSON string?
+                    val = typeof val === STRING ? val : JSON.stringify(val);
+                }
+                catch (e) {
+                    val = NULL;
+                }
+                return val;
+            },
+            /**
+             * A "json" type value stores JSON data format
+             *
+             * @param {String} val
+             * @returns {Object}
+             */
+            out: function (val) {
+                try {
+                    val = JSON.parse(val);
+                }
+                catch (e) {
+                    val = null;
+                }
+                return val;
+            }
+        },
+        /**
+         * A "array" type value stores Array data format
+         */
+        array: {
+            /**
+             * @param {Array} val
+             * @returns {String}
+             */
+            in: function (val) {
+                var value;
+                try {
+                    // @todo: should we check if `val` is a valid Array or Array string?
+                    value = typeof val === STRING ? val : JSON.stringify(val);
+                }
+                catch (e) {
+                    value = NULL;
+                }
+                return value;
+            },
+            /**
+             * A "array" type value stores Array data format
+             *
+             * @param {String} val
+             * @returns {Object}
+             */
+            out: function (val) {
+                var value;
+                try {
+                    value = JSON.parse(val);
+                }
+                catch (e) {
+                    value = undefined;
+                }
+                return Array.isArray(value) ? value : undefined;
+            }
+        },
+        /**
+         * A "object" type value stores Object data format
+         */
+        object: {
+            /**
+             * @param {Object} val
+             * @returns {String}
+             */
+            in: function (val) {
+                var value;
+                try {
+                    // @todo: should we check if `val` is a valid JSON string?
+                    value = typeof val === STRING ? val : JSON.stringify(val);
+                }
+                catch (e) {
+                    value = NULL;
+                }
+                return value;
+            },
+            /**
+             * A "object" type value stores Object data format
+             *
+             * @param {String} val
+             * @returns {Object}
+             */
+            out: function (val) {
+                var value;
+                try {
+                    value = JSON.parse(val);
+                }
+                catch (e) {
+                    value = undefined;
+                }
+                return (value instanceof Object && !Array.isArray(value)) ? value : undefined;
+            }
+        },
+        /**
+         * Free-form type of a value. This is the default for any variable, unless specified otherwise. It ensures that
+         * the variable can store data in any type and no conversion is done while using {@link Variable#get}.
+         */
+        any: {
+            /**
+             * @param {*} val
+             * @returns {*}
+             */
+            in: function (val) {
+                return val; // pass through
+            },
+            /**
+             * @param {*} val
+             * @returns {*}
+             */
+            out: function (val) {
+                return val; // pass through
+            }
+        }
+    },
+    /**
+     * @param {*} obj
+     * @returns {Boolean}
+     */
+    isVariable: function (obj) {
+        return Boolean(obj) && ((obj instanceof Variable) ||
+            _.inSuperChain(obj.constructor, '_postman_propertyName', Variable._postman_propertyName));
+    }
+});
+module.exports = {
+    Variable: Variable
+};

+ 2 - 0
dist/codegens/postman-collection-lite/index.d.ts

@@ -0,0 +1,2 @@
+export declare const Request: (options: any, ...args: any[]) => void;
+export declare const Url: (options: any, ...args: any[]) => void;

+ 5 - 0
dist/codegens/postman-collection-lite/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    Request: require('./collection/request').Request,
+    Url: require('./collection/url').Url
+};

+ 11 - 0
dist/codegens/python-http.client/index.d.ts

@@ -0,0 +1,11 @@
+declare const _exports: {
+    convert: (request: any, options: {
+        indentType: string;
+        indentCount: number;
+        requestTimeout: number;
+        requestBodyTrim: boolean;
+        followRedirect: boolean;
+    }, callback: Function) => any;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/python-http.client/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 8 - 0
dist/codegens/python-http.client/lib/index.d.ts

@@ -0,0 +1,8 @@
+export declare const convert: (request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    requestBodyTrim: boolean;
+    followRedirect: boolean;
+}, callback: Function) => any;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/python-http.client/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./python-httpclient').convert,
+    getOptions: require('./python-httpclient').getOptions
+};

+ 8 - 0
dist/codegens/python-http.client/lib/python-httpclient.d.ts

@@ -0,0 +1,8 @@
+export declare function getOptions(): any[];
+export declare function convert(request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    requestBodyTrim: boolean;
+    followRedirect: boolean;
+}, callback: Function): any;

+ 183 - 0
dist/codegens/python-http.client/lib/python-httpclient.js

@@ -0,0 +1,183 @@
+"use strict";
+var _ = require('../../lodash'), { Url } = require('../../postman-collection-lite'), sanitize = require('./util/sanitize').sanitize, sanitizeOptions = require('./util/sanitize').sanitizeOptions, addFormParam = require('./util/sanitize').addFormParam, parseBody = require('./util/parseBody'), self;
+/**
+ * Used to parse the request headers
+ *
+ * @param  {Object} request - postman SDK-request object
+ * @param  {String} indentation - used for indenting snippet's structure
+ * @returns {String} - request headers in the desired format
+ */
+function getheaders(request, indentation) {
+    var headerArray = request.toJSON().header, requestBodyMode = (request.body ? request.body.mode : 'raw'), headerMap;
+    if (!_.isEmpty(headerArray)) {
+        headerArray = _.reject(headerArray, 'disabled');
+        headerMap = _.map(headerArray, function (header) {
+            return `${indentation}'${sanitize(header.key, 'header', true)}': ` +
+                `'${sanitize(header.value, 'header')}'`;
+        });
+        if (requestBodyMode === 'formdata') {
+            headerMap.push(`${indentation}'Content-type': 'multipart/form-data; boundary={}'.format(boundary)`);
+        }
+        return `headers = {\n${headerMap.join(',\n')}\n}\n`;
+    }
+    if (requestBodyMode === 'formdata') {
+        return `headers = {\n${indentation} 'Content-type': ` +
+            '\'multipart/form-data; boundary={}\'.format(boundary) \n}\n';
+    }
+    return '';
+}
+self = module.exports = {
+    /**
+       * Used to return options which are specific to a particular plugin
+       *
+       * @module getOptions
+       *
+       * @returns {Array}
+       */
+    getOptions: function () {
+        return [
+            {
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                default: 'Space',
+                availableOptions: ['Tab', 'Space'],
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response' +
+                    ' before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            }
+        ];
+    },
+    /**
+      * Used to convert the postman sdk-request object in python-httpclient reuqest snippet
+      *
+      * @module convert
+      *
+      * @param  {Object} request - postman SDK-request object
+      * @param  {Object} options - Options to tweak code snippet generated in Python
+      * @param  {String} options.indentType - type of indentation eg: Space / Tab (default: Space)
+      * @param  {Number} options.indentCount - frequency of indent (default: 4 for indentType: Space,
+                                                                      default: 1 for indentType: Tab)
+      * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+                                                  (default: 0 -> never bail out)
+      * @param {Boolean} options.requestBodyTrim : whether to trim request body fields (default: false)
+      * @param {Boolean} options.followRedirect : whether to allow redirects of a request
+      * @param  {Function} callback - function with parameters (error, snippet)
+      */
+    convert: function (request, options, callback) {
+        var snippet = '', indentation = '', identity = '', url, host, path, query;
+        if (_.isFunction(options)) {
+            callback = options;
+            options = {};
+        }
+        else if (!_.isFunction(callback)) {
+            throw new Error('Python-Http.Client~convert: Callback is not a function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        identity = options.indentType === 'Tab' ? '\t' : ' ';
+        indentation = identity.repeat(options.indentCount);
+        url = Url.parse(request.url.toString());
+        host = url.host ? url.host.join('.') : '';
+        path = url.path ? '/' + url.path.join('/') : '/';
+        query = url.query ? _.reduce(url.query, (accum, q) => {
+            accum.push(`${q.key}=${q.value}`);
+            return accum;
+        }, []) : [];
+        if (query.length > 0) {
+            query = '?' + query.join('&');
+        }
+        else {
+            query = '';
+        }
+        snippet += 'import http.client\n';
+        if (request.body && request.body.mode === 'formdata') {
+            snippet += 'import mimetypes\n';
+            snippet += 'from codecs import encode\n';
+        }
+        snippet += '\n';
+        snippet += `conn = http.client.HTTPSConnection("${sanitize(host)}"`;
+        snippet += url.port ? `, ${request.url.port}` : '';
+        snippet += options.requestTimeout !== 0 ? `, timeout = ${options.requestTimeout})\n` : ')\n';
+        // The following code handles multiple files in the same formdata param.
+        // It removes the form data params where the src property is an array of filepath strings
+        // Splits that array into different form data params with src set as a single filepath string
+        if (request.body && request.body.mode === 'formdata') {
+            let formdata = request.body.formdata, formdataArray = [];
+            formdata.members.forEach((param) => {
+                let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                // check if type is file or text
+                if (type === 'file') {
+                    // if src is not of type string we check for array(multiple files)
+                    if (typeof param.src !== 'string') {
+                        // if src is an array(not empty), iterate over it and add files as separate form fields
+                        if (Array.isArray(param.src) && param.src.length) {
+                            param.src.forEach((filePath) => {
+                                addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                            });
+                        }
+                        // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
+                        else {
+                            addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                        }
+                    }
+                    // if src is string, directly add the param with src as filepath
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                    }
+                }
+                // if type is text, directly add it to formdata array
+                else {
+                    addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                }
+            });
+            request.body.update({
+                mode: 'formdata',
+                formdata: formdataArray
+            });
+        }
+        const payload = parseBody(request.toJSON(), indentation, options.requestBodyTrim);
+        snippet += payload;
+        if (request.body && !request.headers.has('Content-Type')) {
+            if (request.body.mode === 'file') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'text/plain'
+                });
+            }
+            else if (request.body.mode === 'graphql') {
+                request.addHeader({
+                    key: 'Content-Type',
+                    value: 'application/json'
+                });
+            }
+        }
+        const headers = getheaders(request, indentation);
+        snippet += headers;
+        snippet += `conn.request("${request.method}",` +
+            ` "${sanitize(path)}${sanitize(encodeURI(query))}"${headers && (payload ? ', payload' : ', ""')}${headers && ', headers'})\n`;
+        snippet += 'res = conn.getresponse()\n';
+        snippet += 'data = res.read()\n';
+        snippet += 'print(data.decode("utf-8"))';
+        return callback(null, snippet);
+    }
+};

+ 2 - 0
dist/codegens/python-http.client/lib/util/parseBody.d.ts

@@ -0,0 +1,2 @@
+declare function _exports(request: any, indentation: string, bodyTrim: boolean): string;
+export = _exports;

+ 92 - 0
dist/codegens/python-http.client/lib/util/parseBody.js

@@ -0,0 +1,92 @@
+"use strict";
+var _ = require('../../../lodash'), sanitize = require('./sanitize').sanitize, path = require('path');
+/**
+ * Used to parse the body of the postman SDK-request and return in the desired format
+ *
+ * @param  {Object} request - postman SDK-request object
+ * @param  {String} indentation - used for indenting snippet's structure
+ * @param  {Boolean} bodyTrim - whether to trim request body fields
+ * @returns {String} - request body
+ */
+module.exports = function (request, indentation, bodyTrim) {
+    // used to check whether body is present in the request or not
+    if (!_.isEmpty(request.body)) {
+        var requestBody = '', bodyDataMap, enabledBodyList;
+        switch (request.body.mode) {
+            case 'raw':
+                if (!_.isEmpty(request.body[request.body.mode])) {
+                    requestBody += `payload = ${sanitize(request.body[request.body.mode], request.body.mode, bodyTrim)}\n`;
+                }
+                else {
+                    requestBody = 'payload = \'\'\n';
+                }
+                return requestBody;
+            case 'graphql':
+                // eslint-disable-next-line no-case-declarations
+                let query = request.body[request.body.mode].query, graphqlVariables;
+                try {
+                    graphqlVariables = JSON.parse(request.body[request.body.mode].variables);
+                }
+                catch (e) {
+                    graphqlVariables = {};
+                }
+                requestBody += `payload = ${sanitize(JSON.stringify({
+                    query: query,
+                    variables: graphqlVariables
+                }), 'raw', bodyTrim)}\n`;
+                return requestBody;
+            case 'urlencoded':
+                enabledBodyList = _.reject(request.body[request.body.mode], 'disabled');
+                if (!_.isEmpty(enabledBodyList)) {
+                    bodyDataMap = _.map(enabledBodyList, function (value) {
+                        return `${sanitize(value.key, request.body.mode, bodyTrim)}=` +
+                            `${sanitize(value.value, request.body.mode, bodyTrim)}`;
+                    });
+                    requestBody += `payload = '${bodyDataMap.join('&')}'\n`;
+                }
+                else {
+                    requestBody = 'payload = \'\'\n';
+                }
+                return requestBody;
+            case 'formdata':
+                enabledBodyList = _.reject(request.body[request.body.mode], 'disabled');
+                if (!_.isEmpty(enabledBodyList)) {
+                    requestBody += 'dataList = []\n';
+                    requestBody += 'boundary = \'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T\'\n';
+                    enabledBodyList.forEach((data) => {
+                        requestBody += 'dataList.append(encode(\'--\' + boundary))\n';
+                        if (data.type !== 'file') {
+                            requestBody += `dataList.append(encode('Content-Disposition: form-data; name=${sanitize(data.key, 'form-data', true)};'))\n\n`; // eslint-disable-line max-len
+                            requestBody += 'dataList.append(encode(\'Content-Type: {}\'.format(\'' +
+                                (data.contentType ? data.contentType : 'text/plain') + '\')))\n';
+                            requestBody += 'dataList.append(encode(\'\'))\n\n';
+                            requestBody += `dataList.append(encode("${sanitize(data.value, 'form-data', true)}"))\n`;
+                        }
+                        else {
+                            var pathArray = data.src.split(path.sep), fileName = pathArray[pathArray.length - 1];
+                            requestBody += `dataList.append(encode('Content-Disposition: form-data; name=${sanitize(data.key, 'form-data', true)}; filename={0}'.format('${sanitize(fileName, 'formdata', true)}')))\n\n`; // eslint-disable-line max-len
+                            requestBody += `fileType = mimetypes.guess_type('${sanitize(data.src, 'formdata', true)}')[0] or 'application/octet-stream'\n`; // eslint-disable-line max-len
+                            requestBody += 'dataList.append(encode(\'Content-Type: {}\'.format(fileType)))\n';
+                            requestBody += 'dataList.append(encode(\'\'))\n\n';
+                            requestBody += `with open('${data.src}', 'rb') as f:\n`;
+                            requestBody += `${indentation}dataList.append(f.read())\n`;
+                        }
+                    });
+                    requestBody += 'dataList.append(encode(\'--\'+boundary+\'--\'))\n';
+                    requestBody += 'dataList.append(encode(\'\'))\n';
+                    requestBody += 'body = b\'\\r\\n\'.join(dataList)\n';
+                    requestBody += 'payload = body\n';
+                }
+                else {
+                    requestBody = 'boundary = \'\'\n';
+                    requestBody += 'payload = \'\'\n';
+                }
+                return requestBody;
+            case 'file':
+                return 'payload = "<file contents here>"\n';
+            default:
+                return 'payload = \'\'\n';
+        }
+    }
+    return '';
+};

+ 3 - 0
dist/codegens/python-http.client/lib/util/sanitize.d.ts

@@ -0,0 +1,3 @@
+export declare function sanitize(inputString: string, escapeCharFor: string, inputTrim?: boolean | undefined): string;
+export declare function sanitizeOptions(options: any, optionsArray: any[]): any;
+export declare function addFormParam(array: any[], key: string, type: string, val: string, disabled: string, contentType: string): void;

+ 130 - 0
dist/codegens/python-http.client/lib/util/sanitize.js

@@ -0,0 +1,130 @@
+"use strict";
+module.exports = {
+    /**
+    * Sanitizes input string by handling escape characters according to request body type
+    *
+    * @param {String} inputString - Input String to sanitize
+    * @param {String} escapeCharFor - Escape for headers, body: raw, formdata etc
+    * @param {Boolean} [inputTrim] - Whether to trim the input
+    * @returns {String} Sanitized String handling escape characters
+    */
+    sanitize: function (inputString, escapeCharFor, inputTrim) {
+        if (typeof inputString !== 'string') {
+            return '';
+        }
+        inputString = inputTrim && typeof inputTrim === 'boolean' ? inputString.trim() : inputString;
+        if (escapeCharFor && typeof escapeCharFor === 'string') {
+            switch (escapeCharFor) {
+                case 'raw':
+                    return JSON.stringify(inputString);
+                case 'urlencoded':
+                    return encodeURIComponent(inputString).replace(/'/g, '\\\'');
+                /* istanbul ignore next */
+                case 'formdata':
+                    return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
+                /* istanbul ignore next */
+                case 'file':
+                    return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
+                case 'header':
+                    return inputString.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
+                default:
+                    return inputString.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+            }
+        }
+        return inputString.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
+    },
+    /**
+      * sanitizes input options
+      *
+      * @param {Object} options - Options provided by the user
+      * @param {Array} optionsArray - options array received from getOptions function
+      *
+      * @returns {Object} - Sanitized options object
+      */
+    sanitizeOptions: function (options, optionsArray) {
+        var result = {}, defaultOptions = {}, id;
+        optionsArray.forEach((option) => {
+            defaultOptions[option.id] = {
+                default: option.default,
+                type: option.type
+            };
+            if (option.type === 'enum') {
+                defaultOptions[option.id].availableOptions = option.availableOptions;
+            }
+        });
+        for (id in options) {
+            if (options.hasOwnProperty(id)) {
+                if (defaultOptions[id] === undefined) {
+                    continue;
+                }
+                switch (defaultOptions[id].type) {
+                    case 'boolean':
+                        if (typeof options[id] !== 'boolean') {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'positiveInteger':
+                        if (typeof options[id] !== 'number' || options[id] < 0) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    case 'enum':
+                        if (!defaultOptions[id].availableOptions.includes(options[id])) {
+                            result[id] = defaultOptions[id].default;
+                        }
+                        else {
+                            result[id] = options[id];
+                        }
+                        break;
+                    default:
+                        result[id] = options[id];
+                }
+            }
+        }
+        for (id in defaultOptions) {
+            if (defaultOptions.hasOwnProperty(id)) {
+                if (result[id] === undefined) {
+                    result[id] = defaultOptions[id].default;
+                }
+            }
+        }
+        return result;
+    },
+    /**
+   *
+   * @param {Array} array - form data array
+   * @param {String} key - key of form data param
+   * @param {String} type - type of form data param(file/text)
+   * @param {String} val - value/src property of form data param
+   * @param {String} disabled - Boolean denoting whether the param is disabled or not
+   * @param {String} contentType - content type header of the param
+   *
+   * Appends a single param to form data array
+   */
+    addFormParam: function (array, key, type, val, disabled, contentType) {
+        if (type === 'file') {
+            array.push({
+                key: key,
+                type: type,
+                src: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+        else {
+            array.push({
+                key: key,
+                type: type,
+                value: val,
+                disabled: disabled,
+                contentType: contentType
+            });
+        }
+    }
+};

+ 11 - 0
dist/codegens/ruby/index.d.ts

@@ -0,0 +1,11 @@
+declare const _exports: {
+    convert: (request: any, options: {
+        indentType: string;
+        indentCount: number;
+        requestTimeout: number;
+        trimRequestBody: boolean;
+        followRedirect: boolean;
+    }, callback: Function) => any;
+    getOptions: () => any[];
+};
+export = _exports;

+ 2 - 0
dist/codegens/ruby/index.js

@@ -0,0 +1,2 @@
+"use strict";
+module.exports = require('./lib');

+ 8 - 0
dist/codegens/ruby/lib/index.d.ts

@@ -0,0 +1,8 @@
+export declare const convert: (request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    trimRequestBody: boolean;
+    followRedirect: boolean;
+}, callback: Function) => any;
+export declare const getOptions: () => any[];

+ 5 - 0
dist/codegens/ruby/lib/index.js

@@ -0,0 +1,5 @@
+"use strict";
+module.exports = {
+    convert: require('./ruby').convert,
+    getOptions: require('./ruby').getOptions
+};

+ 8 - 0
dist/codegens/ruby/lib/ruby.d.ts

@@ -0,0 +1,8 @@
+export declare function getOptions(): any[];
+export declare function convert(request: any, options: {
+    indentType: string;
+    indentCount: number;
+    requestTimeout: number;
+    trimRequestBody: boolean;
+    followRedirect: boolean;
+}, callback: Function): any;

+ 206 - 0
dist/codegens/ruby/lib/ruby.js

@@ -0,0 +1,206 @@
+"use strict";
+var _ = require('../../lodash'), parseBody = require('./util/parseBody'), sanitize = require('./util/sanitize').sanitize, sanitizeOptions = require('./util/sanitize').sanitizeOptions, addFormParam = require('./util/sanitize').addFormParam, self;
+/**
+ * Used to parse the request headers
+ *
+ * @param  {Object} headers - postman SDK-request object
+ * @returns {String} - request headers in the desired format
+ */
+function parseHeaders(headers) {
+    var headerSnippet = '';
+    if (!_.isEmpty(headers)) {
+        _.forEach(headers, function (value, key) {
+            if (Array.isArray(value)) {
+                var headerValues = [];
+                _.forEach(value, (singleValue) => {
+                    headerValues.push(`"${sanitize(singleValue, 'header')}"`);
+                });
+                headerSnippet += `request["${sanitize(key, 'header', true)}"] = [${headerValues.join(', ')}]\n`;
+            }
+            else {
+                headerSnippet += `request["${sanitize(key, 'header', true)}"] = "${sanitize(value, 'header')}"\n`;
+            }
+        });
+    }
+    return headerSnippet;
+}
+self = module.exports = {
+    /**
+       * Used to return options which are specific to a particular plugin
+       *
+       * @returns {Array}
+       */
+    getOptions: function () {
+        return [{
+                name: 'Set indentation count',
+                id: 'indentCount',
+                type: 'positiveInteger',
+                default: 2,
+                description: 'Set the number of indentation characters to add per code level'
+            },
+            {
+                name: 'Set indentation type',
+                id: 'indentType',
+                type: 'enum',
+                availableOptions: ['Tab', 'Space'],
+                default: 'Space',
+                description: 'Select the character used to indent lines of code'
+            },
+            {
+                name: 'Set request timeout',
+                id: 'requestTimeout',
+                type: 'positiveInteger',
+                default: 0,
+                description: 'Set number of milliseconds the request should wait for a response' +
+                    ' before timing out (use 0 for infinity)'
+            },
+            {
+                name: 'Follow redirects',
+                id: 'followRedirect',
+                type: 'boolean',
+                default: true,
+                description: 'Automatically follow HTTP redirects'
+            },
+            {
+                name: 'Trim request body fields',
+                id: 'trimRequestBody',
+                type: 'boolean',
+                default: false,
+                description: 'Remove white space and additional lines that may affect the server\'s response'
+            }];
+    },
+    /**
+      * Used to convert the postman sdk-request object in ruby request snippet
+      *
+      * @param  {Object} request - postman SDK-request object
+      * @param  {Object} options
+      * @param  {String} options.indentType - type of indentation eg: Space / Tab (default: Space)
+      * @param  {Number} options.indentCount - frequency of indent (default: 4 for indentType: Space,
+                                                                      default: 1 for indentType: Tab)
+      * @param {Number} options.requestTimeout : time in milli-seconds after which request will bail out
+                                                  (default: 0 -> never bail out)
+      * @param {Boolean} options.trimRequestBody : whether to trim request body fields (default: false)
+      * @param {Boolean} options.followRedirect : whether to allow redirects of a request
+      * @param  {Function} callback - function with parameters (error, snippet)
+      */
+    convert: function (request, options, callback) {
+        var snippet = '', indentation = '', identity = '', headerSnippet = '', methods = ['GET', 'POST', 'HEAD', 'DELETE', 'PATCH', 'PROPFIND',
+            'PROPPATCH', 'PUT', 'OPTIONS', 'COPY', 'LOCK', 'UNLOCK', 'MOVE', 'TRACE'];
+        if (_.isFunction(options)) {
+            callback = options;
+            options = null;
+        }
+        else if (!_.isFunction(callback)) {
+            throw new Error('Ruby~convert: Callback is not a function');
+        }
+        options = sanitizeOptions(options, self.getOptions());
+        identity = options.indentType === 'Tab' ? '\t' : ' ';
+        indentation = identity.repeat(options.indentCount);
+        // concatenation and making up the final string
+        snippet = 'require "uri"\n';
+        snippet += 'require "net/http"\n\n';
+        if (!_.includes(methods, request.method)) {
+            snippet += `class Net::HTTP::${_.capitalize(request.method)} < Net::HTTPRequest\n`;
+            snippet += `${indentation}METHOD = "${request.method}"\n`;
+            snippet += `${indentation}REQUEST_HAS_BODY = ${!_.isEmpty(request.body)}\n`;
+            snippet += `${indentation}RESPONSE_HAS_BODY = true\n`;
+            snippet += 'end\n\n';
+        }
+        snippet += `url = URI("${sanitize(request.url.toString(), 'url')}")\n\n`;
+        if (sanitize(request.url.toString(), 'url').startsWith('https')) {
+            snippet += 'https = Net::HTTP.new(url.host, url.port)\n';
+            snippet += 'https.use_ssl = true\n\n';
+            if (options.requestTimeout) {
+                snippet += `https.read_timeout = ${Math.ceil(options.requestTimeout / 1000)}\n`;
+            }
+            snippet += `request = Net::HTTP::${_.capitalize(request.method)}.new(url)\n`;
+            if (request.body && !request.headers.has('Content-Type')) {
+                if (request.body.mode === 'file') {
+                    request.addHeader({
+                        key: 'Content-Type',
+                        value: 'text/plain'
+                    });
+                }
+                else if (request.body.mode === 'graphql') {
+                    request.addHeader({
+                        key: 'Content-Type',
+                        value: 'application/json'
+                    });
+                }
+            }
+            headerSnippet = parseHeaders(request.getHeaders({ enabled: true }));
+            if (headerSnippet !== '') {
+                snippet += headerSnippet;
+            }
+            // The following code handles multiple files in the same formdata param.
+            // It removes the form data params where the src property is an array of filepath strings
+            // Splits that array into different form data params with src set as a single filepath string
+            if (request.body && request.body.mode === 'formdata') {
+                let formdata = request.body.formdata, formdataArray = [];
+                formdata.members.forEach((param) => {
+                    let key = param.key, type = param.type, disabled = param.disabled, contentType = param.contentType;
+                    // check if type is file or text
+                    if (type === 'file') {
+                        // if src is not of type string we check for array(multiple files)
+                        if (typeof param.src !== 'string') {
+                            // if src is an array(not empty), iterate over it and add files as separate form fields
+                            if (Array.isArray(param.src) && param.src.length) {
+                                param.src.forEach((filePath) => {
+                                    addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
+                                });
+                            }
+                            // if src is not an array or string, or is an empty array, add a placeholder for file path(no files case)
+                            else {
+                                addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
+                            }
+                        }
+                        // if src is string, directly add the param with src as filepath
+                        else {
+                            addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
+                        }
+                    }
+                    // if type is text, directly add it to formdata array
+                    else {
+                        addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
+                    }
+                });
+                request.body.update({
+                    mode: 'formdata',
+                    formdata: formdataArray
+                });
+            }
+            snippet += `${parseBody(request.toJSON(), options.trimRequestBody)}\n`;
+            snippet += 'response = https.request(request)\n';
+            snippet += 'puts response.read_body\n';
+        }
+        else {
+            snippet += 'http = Net::HTTP.new(url.host, url.port);\n';
+            if (options.requestTimeout) {
+                snippet += `http.read_timeout = ${Math.ceil(options.requestTimeout / 1000)}\n`;
+            }
+            snippet += `request = Net::HTTP::${_.capitalize(request.method)}.new(url)\n`;
+            if (request.body && !request.headers.has('Content-Type')) {
+                if (request.body.mode === 'file') {
+                    request.addHeader({
+                        key: 'Content-Type',
+                        value: 'text/plain'
+                    });
+                }
+                else if (request.body.mode === 'graphql') {
+                    request.addHeader({
+                        key: 'Content-Type',
+                        value: 'application/json'
+                    });
+                }
+            }
+            headerSnippet = parseHeaders(request.getHeaders({ enabled: true }));
+            if (headerSnippet !== '') {
+                snippet += headerSnippet;
+            }
+            snippet += `${parseBody(request.toJSON(), options.trimRequestBody)}\n`;
+            snippet += 'response = http.request(request)\n';
+            snippet += 'puts response.read_body\n';
+        }
+        return callback(null, snippet);
+    }
+};

+ 2 - 0
dist/codegens/ruby/lib/util/parseBody.d.ts

@@ -0,0 +1,2 @@
+declare function _exports(request: any, trimRequestBody: boolean): string;
+export = _exports;

+ 0 - 0
dist/codegens/ruby/lib/util/parseBody.js


Some files were not shown because too many files changed in this diff