@@ -4,15 +4,23 @@ const commander = require('commander'),
4
4
shellQuote = require ( '../assets/shell-quote' ) ,
5
5
unnecessaryOptions = require ( '../assets/unnecessaryOptions' ) ,
6
6
supportedOptions = require ( '../assets/supportedOptions' ) ,
7
+ UserError = require ( './UserError' ) ,
8
+ { USER_ERRORS } = require ( './constants' ) ,
7
9
formDataOptions = [ '-d' , '--data' , '--data-raw' , '--data-binary' , '--data-ascii' ] ,
8
10
allowedOperators = [ '<' , '>' , '(' , ')' ] ;
9
11
10
12
var program ,
11
13
12
14
curlConverter = {
13
15
requestUrl : '' ,
14
-
15
16
initialize : function ( ) {
17
+ /**
18
+ * Collects values from the command line arguments and adds them to the memo array.
19
+ *
20
+ * @param {string } str - The argument value to collect.
21
+ * @param {Array } memo - The array to add the collected values to.
22
+ * @returns {Array } - The updated memo array.
23
+ */
16
24
function collectValues ( str , memo ) {
17
25
memo . push ( str ) ;
18
26
return memo ;
@@ -111,7 +119,7 @@ var program,
111
119
112
120
if ( validMethods . indexOf ( curlObj . request . toUpperCase ( ) ) === - 1 ) {
113
121
// the method is still not valid
114
- throw new Error ( 'The method ' + curlObj . request + ' is not supported' ) ;
122
+ throw new UserError ( USER_ERRORS . METHOD_NOT_SUPPORTED ` ${ curlObj . request } ` ) ;
115
123
}
116
124
}
117
125
@@ -120,8 +128,7 @@ var program,
120
128
if ( ( curlObj . data . length > 0 || curlObj . dataAscii . length > 0 ||
121
129
curlObj . dataBinary || curlObj . dataUrlencode . length > 0 ) &&
122
130
curlObj . head && ! curlObj . get ) {
123
- throw new Error ( 'Unable to parse: Both (--head/-I) and' +
124
- ' (-d/--data/--data-raw/--data-binary/--data-ascii/--data-urlencode) are not supported' ) ;
131
+ throw new UserError ( USER_ERRORS . UNABLE_TO_PARSE_HEAD_AND_DATA ) ;
125
132
}
126
133
127
134
/**
@@ -130,8 +137,7 @@ var program,
130
137
* once it fails here using convertForCMDFormat()
131
138
*/
132
139
if ( curlObj . args . length > 1 && _ . includes ( curlObj . args , '^' ) ) {
133
- throw new Error ( 'Only the URL can be provided without an option preceding it.' +
134
- ' All other inputs must be specified via options.' ) ;
140
+ throw new UserError ( USER_ERRORS . INPUT_WITHOUT_OPTIONS ) ;
135
141
}
136
142
} ,
137
143
@@ -368,7 +374,7 @@ var program,
368
374
inCorrectlyFormedcURLRegex2 = / ( \w + = \w + & ? ) / g; // checks - foo?bar=1&baz=2
369
375
370
376
if ( string . match ( inCorrectlyFormedcURLRegex1 ) || string . match ( inCorrectlyFormedcURLRegex2 ) ) {
371
- throw Error ( 'Please check your cURL string for malformed URL' ) ;
377
+ throw new UserError ( USER_ERRORS . MALFORMED_URL ) ;
372
378
}
373
379
}
374
380
else if ( _ . isFunction ( arg . startsWith ) && arg . startsWith ( '$' ) && arg . length > 1 ) {
@@ -420,8 +426,8 @@ var program,
420
426
}
421
427
catch ( e ) {
422
428
if ( e . message === 'process.exit is not a function' ) {
423
- // happened because of
424
- e . message = 'Invalid format for cURL.' ;
429
+ // happened because of
430
+ return { error : new UserError ( USER_ERRORS . INVALID_FORMAT ) } ;
425
431
}
426
432
return { error : e } ;
427
433
}
@@ -445,7 +451,7 @@ var program,
445
451
}
446
452
}
447
453
catch ( e ) {
448
- throw new Error ( 'Unable to parse: Could not identify the URL. Please use the --url option.' ) ;
454
+ throw new UserError ( USER_ERRORS . UNABLE_TO_PARSE_NO_URL ) ;
449
455
}
450
456
}
451
457
/* eslint-enable */
@@ -479,7 +485,7 @@ var program,
479
485
this . requestUrl = argStr ;
480
486
}
481
487
else {
482
- throw new Error ( 'Could not detect the URL from cURL. Please make sure it\'s a valid cURL' ) ;
488
+ throw new UserError ( USER_ERRORS . CANNOT_DETECT_URL ) ;
483
489
}
484
490
} ,
485
491
@@ -666,10 +672,79 @@ var program,
666
672
return this . validate ( curlString , false ) ;
667
673
}
668
674
669
- return { result : false , reason : e . message } ;
675
+ return { result : false , reason : e . message , error : e } ;
676
+ }
677
+ } ,
678
+
679
+ /**
680
+ * Escape JSON strings before JSON.parse
681
+ *
682
+ * @param {string } jsonString - Input JSON string
683
+ * @returns {string } - JSON string with escaped characters
684
+ */
685
+ escapeJson : function ( jsonString ) {
686
+ // eslint-disable-next-line no-implicit-globals
687
+ meta = { // table of character substitutions
688
+ '\t' : '\\t' ,
689
+ '\n' : '\\n' ,
690
+ '\f' : '\\f' ,
691
+ '\r' : '\\r'
692
+ } ;
693
+ return jsonString . replace ( / [ \t \n \f \r ] / g, ( char ) => {
694
+ return meta [ char ] ;
695
+ } ) ;
696
+ } ,
697
+
698
+ /**
699
+ * Identifies whether the input data string is a graphql query or not
700
+ *
701
+ * @param {string } dataString - Input data string to check if it is a graphql query
702
+ * @param {string } contentType - Content type header value
703
+ * @returns {Object } - { result: true, graphql: {Object} } if dataString is a graphql query else { result: false }
704
+ */
705
+ identifyGraphqlRequest : function ( dataString , contentType ) {
706
+ try {
707
+ const rawDataObj = _ . attempt ( JSON . parse , this . escapeJson ( dataString ) ) ;
708
+ if ( contentType === 'application/json' && rawDataObj && ! _ . isError ( rawDataObj ) ) {
709
+ if ( ! _ . has ( rawDataObj , 'query' ) || ! _ . isString ( rawDataObj . query ) ) {
710
+ return { result : false } ;
711
+ }
712
+ if ( _ . has ( rawDataObj , 'variables' ) ) {
713
+ if ( ! _ . isObject ( rawDataObj . variables ) ) {
714
+ return { result : false } ;
715
+ }
716
+ }
717
+ else {
718
+ rawDataObj . variables = { } ;
719
+ }
720
+ if ( _ . has ( rawDataObj , 'operationName' ) ) {
721
+ if ( ! _ . isString ( rawDataObj . operationName ) ) {
722
+ return { result : false } ;
723
+ }
724
+ }
725
+ else {
726
+ rawDataObj . operationName = '' ;
727
+ }
728
+ if ( _ . keys ( rawDataObj ) . length === 3 ) {
729
+ const graphqlVariables = JSON . stringify ( rawDataObj . variables , null , 2 ) ;
730
+ return {
731
+ result : true ,
732
+ graphql : {
733
+ query : rawDataObj . query ,
734
+ operationName : rawDataObj . operationName ,
735
+ variables : graphqlVariables === '{}' ? '' : graphqlVariables
736
+ }
737
+ } ;
738
+ }
739
+ }
740
+ return { result : false } ;
741
+ }
742
+ catch ( e ) {
743
+ return { result : false } ;
670
744
}
671
745
} ,
672
746
747
+
673
748
convertCurlToRequest : function ( curlString , shouldRetry = true ) {
674
749
try {
675
750
this . initialize ( ) ;
@@ -741,10 +816,19 @@ var program,
741
816
bodyArr . push ( this . trimQuotesFromString ( dataUrlencode ) ) ;
742
817
bodyArr . push ( this . trimQuotesFromString ( dataAsciiString ) ) ;
743
818
744
- request . body . mode = 'raw' ;
745
- request . body . raw = _ . join ( _ . reject ( bodyArr , ( ele ) => {
746
- return ! ele ;
747
- } ) , '&' ) ;
819
+ const rawDataString = _ . join ( _ . reject ( bodyArr , ( ele ) => {
820
+ return ! ele ;
821
+ } ) , '&' ) ,
822
+ graphqlRequestData = this . identifyGraphqlRequest ( rawDataString , content_type ) ;
823
+
824
+ if ( graphqlRequestData . result ) {
825
+ request . body . mode = 'graphql' ;
826
+ request . body . graphql = graphqlRequestData . graphql ;
827
+ }
828
+ else {
829
+ request . body . mode = 'raw' ;
830
+ request . body . raw = rawDataString ;
831
+ }
748
832
749
833
urlData = request . data ;
750
834
}
@@ -796,7 +880,7 @@ var program,
796
880
}
797
881
}
798
882
if ( e . message === 'process.exit is not a function' ) {
799
- e . message = 'Invalid format for cURL.' ;
883
+ return { error : new UserError ( USER_ERRORS . INVALID_FORMAT ) } ;
800
884
}
801
885
return { error : e } ;
802
886
}
0 commit comments