Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 63 additions & 98 deletions codegens/curl/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,37 @@ const {
addFormParam,
form,
shouldAddHttpMethod
} = require('./util'),
_ = require('./lodash');
} = require('./util'),
_ = require('./lodash');

var self;

self = module.exports = {
convert: function (request, options, callback) {

// HELPER FUNCTION FOR AUTH
_addAuth: function (request, snippet, format, quoteType) {
const auth = request && request.auth;

if (!auth || !auth.type) return snippet;

// BASIC AUTH
if (auth.type === 'basic' && auth.username && auth.password) {
snippet += ` ${form('-u', format)} "${auth.username}:${auth.password}"`;
}

// BEARER AUTH
else if (auth.type === 'bearer' && auth.token) {
snippet += ` ${form('-H', format)} ${quoteType}Authorization: Bearer ${auth.token}${quoteType}`;
}

return snippet;
},

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,
Expand All @@ -34,9 +54,14 @@ self = module.exports = {

snippet = 'curl';

// NTLM auth first
if (ntlmAuth) {
snippet += ntlmAuth;
}

// NEW: Basic & Bearer Auth
snippet = self._addAuth(request, snippet, format, quoteType);

if (silent) {
snippet += ` ${form('-s', format)}`;
}
Expand All @@ -49,11 +74,11 @@ self = module.exports = {
if ((url.match(/[{[}\]]/g) || []).length > 0) {
snippet += ` ${form('-g', format)}`;
}

if (multiLine) {
indent = options.indentType === 'Tab' ? '\t' : ' ';
indent = ' ' + options.lineContinuationCharacter + '\n' + indent.repeat(options.indentCount); // eslint-disable-line max-len
}
else {
indent = ' ' + options.lineContinuationCharacter + '\n' + indent.repeat(options.indentCount);
} else {
indent = ' ';
}

Expand All @@ -65,42 +90,30 @@ self = module.exports = {
}
snippet += ` ${quoteType + url + quoteType}`;

// HEADERS
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'
});
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;
}
if (!header.key) return;
snippet += indent + `${form('-H', format)} ${quoteType}${sanitize(header.key, true, quoteType)}`;
// 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, false, quoteType)}${quoteType}`;
}
else {
} else {
snippet += ';' + quoteType;
}
});
}

// 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
// FORM DATA HANDLING
if (request.body && request.body.mode === 'formdata') {
let formdata = request.body.formdata,
formdataArray = [];
Expand All @@ -115,16 +128,13 @@ self = module.exports = {
param.src.forEach((filePath) => {
addFormParam(formdataArray, key, param.type, filePath, disabled, contentType);
});
}
else {
} else {
addFormParam(formdataArray, key, param.type, '/path/to/file', disabled, contentType);
}
}
else {
} else {
addFormParam(formdataArray, key, param.type, param.src, disabled, contentType);
}
}
else {
} else {
addFormParam(formdataArray, key, param.type, param.value, disabled, contentType);
}
});
Expand All @@ -133,9 +143,10 @@ self = module.exports = {
formdata: formdataArray
});
}

// BODY HANDLING
if (request.body) {
body = request.body.toJSON();

if (!_.isEmpty(body)) {
switch (body.mode) {
case 'urlencoded':
Expand All @@ -150,42 +161,25 @@ self = module.exports = {
case 'raw': {
let rawBody = body.raw.toString(),
isAsperandPresent = _.includes(rawBody, '@'),
// Use the long option if `@` is present in the request body otherwise follow user setting
optionName = isAsperandPresent ? '--data-raw' : form('-d', format),
sanitizedBody = sanitize(rawBody, trim, quoteType);

if (!multiLine) {
try {
sanitizedBody = JSON.stringify(JSON.parse(sanitizedBody));
}
catch (e) {
// Do nothing
}
try { sanitizedBody = JSON.stringify(JSON.parse(sanitizedBody)); }
catch (e) { /* do nothing */ }
}

snippet += indent + `${optionName} ${quoteType}${sanitizedBody}${quoteType}`;

break;
}

case 'graphql': {
// eslint-disable-next-line no-case-declarations
let query = body.graphql ? body.graphql.query : '',
graphqlVariables, requestBody, isAsperandPresent, optionName;
try {
graphqlVariables = JSON.parse(body.graphql.variables);
}
catch (e) {
graphqlVariables = {};
}

requestBody = JSON.stringify({
query: query,
variables: graphqlVariables
});
try { graphqlVariables = JSON.parse(body.graphql.variables); }
catch (e) { graphqlVariables = {}; }

requestBody = JSON.stringify({ query: query, variables: graphqlVariables });
isAsperandPresent = _.includes(requestBody, '@');
// Use the long option if `@` is present in the request body otherwise follow user setting
optionName = isAsperandPresent ? '--data-raw' : form('-d', format);
snippet += indent + `${optionName} ${quoteType}${sanitize(requestBody, trim, quoteType)}${quoteType}`;
break;
Expand All @@ -194,18 +188,12 @@ self = module.exports = {
_.forEach(body.formdata, function (data) {
if (!(data.disabled)) {
if (data.type === 'file') {
snippet += indent + `${form('-F', format)}`;
snippet += ` ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
`${sanitize(`@"${sanitize(data.src, trim, '"', true)}"`, trim, quoteType, quoteType === '"')}`;
snippet += quoteType;
}
else {
snippet += indent + `${form('-F', format)}`;
snippet += ` ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
snippet += indent + `${form('-F', format)} ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
`${sanitize(`@"${sanitize(data.src, trim, '"', true)}"`, trim, quoteType, quoteType === '"')}${quoteType}`;
} else {
snippet += indent + `${form('-F', format)} ${quoteType}${sanitize(data.key, trim, quoteType)}=` +
sanitize(`"${sanitize(data.value, trim, '"', true)}"`, trim, quoteType, quoteType === '"');
if (data.contentType) {
snippet += `;type=${data.contentType}`;
}
if (data.contentType) snippet += `;type=${data.contentType}`;
snippet += quoteType;
}
}
Expand All @@ -223,76 +211,53 @@ self = module.exports = {

callback(null, snippet);
},

getOptions: function () {
return [
{
name: 'Generate multiline snippet',
id: 'multiLine',
type: 'boolean',
default: true,
description: 'Split cURL command across multiple lines'
default: true
},
{
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)'
default: true
},
{
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)'
default: 'single'
},
{
name: 'Set request timeout (in seconds)',
id: 'requestTimeoutInSeconds',
type: 'positiveInteger',
default: 0,
description: 'Set number of seconds the request should wait for a response before ' +
'timing out (use 0 for infinity)'
default: 0
},
{
name: 'Follow redirects',
id: 'followRedirect',
type: 'boolean',
default: true,
description: 'Automatically follow HTTP redirects'
},
{
name: 'Follow original HTTP method',
id: 'followOriginalHttpMethod',
type: 'boolean',
default: false,
description: 'Redirect with the original HTTP method instead of the default behavior of redirecting with GET'
default: true
},
{
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'
default: false
},
{
name: 'Use Silent Mode',
id: 'silent',
type: 'boolean',
default: false,
description: 'Display the requested data without showing the cURL progress meter or error messages'
default: false
}
];
}

};