1
+ const optionsRegex = / ( - - [ a - z A - Z \- ] + ' .* ?' ) | ( - - [ a - z A - Z \- ] + ) | ( - [ a - z A - Z \- ] + ? ' .+ ?' ) | ( ' ? [ a - z ] + : \/ \/ .* ?' + ?) | ( " ? [ a - z ] + : \/ \/ .* ?" + ?) / g; // eslint-disable-line
2
+ const urlRegex = / ^ h t t p s ? : \/ \/ ( w w w \. ) ? [ - a - z A - Z 0 - 9 @ : % . _ \+ ~ # = ] { 2 , 256 } \. [ a - z ] { 2 , 6 } \b ( [ - a - z A - Z 0 - 9 @ : % _ \+ . ~ # ? & / / = ] * ) $ / ; // eslint-disable-line
3
+
4
+ const contentTypeHeader = 'content-type' ;
5
+ const jsonMimeType = 'application/json' ;
6
+
7
+ const isMatchingOption = ( headers , str ) => {
8
+ for ( let i = 0 ; i < headers . length ; i += 1 ) {
9
+ if ( str . startsWith ( headers [ i ] ) ) {
10
+ return true ;
11
+ }
12
+ }
13
+ return false ;
14
+ } ;
15
+
16
+ const isAHeaderOption = str => isMatchingOption ( [ '-H ' , '--headers ' , '--header ' ] , str ) ;
17
+ const isDataOption = str => isMatchingOption ( [ '--data ' , '--data-ascii ' , '-d ' , '--data-raw ' , '--data-urlencode ' , '--data-binary ' ] , str ) ;
18
+
19
+ const removeLeadingTrailingQuotes = ( str ) => {
20
+ const quotes = [ '\'' , '"' ] ;
21
+ let newStr = str . trim ( ) ;
22
+ if ( quotes . includes ( newStr [ 0 ] ) ) {
23
+ newStr = newStr . substr ( 1 , newStr . length - 1 )
24
+ }
25
+ if ( quotes . includes ( newStr [ newStr . length - 1 ] ) ) {
26
+ newStr = newStr . substr ( 0 , newStr . length - 1 )
27
+ }
28
+ return newStr ;
29
+ } ;
30
+
31
+ const subStrFrom = ( val , startFromVal ) => {
32
+ const dataPosition = val . indexOf ( startFromVal ) ;
33
+ return val . substr ( dataPosition ) ;
34
+ } ;
35
+
36
+ const isJsonRequest = parsedCommand => ( parsedCommand . headers [ contentTypeHeader ] &&
37
+ parsedCommand . headers [ contentTypeHeader ] . indexOf ( jsonMimeType ) !== - 1 ) ;
38
+
39
+ const parseBodyByContentType = ( parsedCommand ) => {
40
+ const { body, headers } = parsedCommand
41
+ // if (body && isJsonRequest(parsedCommand)) {
42
+ if ( body ) {
43
+ try {
44
+ const cleanedBodyData = body . replace ( '\\"' , '"' ) . replace ( "\\'" , "'" ) ;
45
+ return JSON . parse ( cleanedBodyData ) ;
46
+ } catch ( ex ) {
47
+ // ignore json conversion error..
48
+ console . log ( 'Cannot parse JSON Data ' + ex . message ) ; // eslint-disable-line
49
+ }
50
+ }
51
+ return body ;
52
+ } ;
53
+
54
+ const parseOptionValue = ( val ) => {
55
+ const headerSplit = subStrFrom ( val , ' ' ) . split ( ':' ) ;
56
+ return {
57
+ key : removeLeadingTrailingQuotes ( headerSplit [ 0 ] ) . trim ( ) ,
58
+ value : removeLeadingTrailingQuotes ( headerSplit [ 1 ] ) . trim ( )
59
+ } ;
60
+ } ;
61
+
62
+ const parseQueryStrings = ( url ) => {
63
+ const paramPosition = url . indexOf ( '?' ) ;
64
+ const queryStrings = { } ;
65
+ if ( paramPosition !== - 1 ) {
66
+ // const splitUrl = parsedCommand.url.substr(0, paramPosition);
67
+ const paramsString = url . substr ( paramPosition + 1 ) ;
68
+ const params = paramsString . split ( '&' ) || [ ] ;
69
+
70
+ params . forEach ( ( param ) => {
71
+ const splitParam = param . split ( '=' ) ; // eslint-disable-line
72
+ queryStrings [ splitParam [ 0 ] ] = splitParam [ 1 ] ; // eslint-disable-line
73
+ } ) ;
74
+ }
75
+ return queryStrings ;
76
+ } ;
77
+
78
+ const parseUrlOption = ( val ) => {
79
+ const urlMatches = val . match ( urlRegex ) || [ ] ;
80
+ if ( urlMatches . length ) {
81
+ const url = urlMatches [ 0 ] ; // eslint-disable-line
82
+ return {
83
+ url,
84
+ queryStrings : parseQueryStrings ( url ) ,
85
+ } ;
86
+ }
87
+ return { url : '' , queryStrings : { } } ;
88
+ } ;
89
+
90
+ const parseBody = val => removeLeadingTrailingQuotes ( subStrFrom ( val , ' ' ) ) ;
91
+
92
+ const isACurlCommand = val => val . trim ( ) . startsWith ( 'curl ' ) ;
93
+ const isAUrlOption = ( val ) => {
94
+ const matches = val . match ( urlRegex ) || [ ] ;
95
+ return ! ! matches . length ;
96
+ } ;
97
+
98
+ /*
99
+ * Parse cUrl command to a JSON structure
100
+ * params:
101
+ * command - cUrl command as a string.
102
+ * return JSON object
103
+ */
104
+ export function parse ( command ) {
105
+ if ( ! command ) { return '' ; }
106
+
107
+ const parsedCommand = {
108
+ url : '' ,
109
+ } ;
110
+
111
+ // quit if the command does not starts with curl
112
+ if ( isACurlCommand ( command ) ) {
113
+ // let cleanCommand = command.replace('\\\\n', '');
114
+ let cleanCommand = command ;
115
+ cleanCommand = cleanCommand . replace ( / ( \\ \r \n | \\ \n | \\ \r ) / gm, " " ) ;
116
+ cleanCommand = cleanCommand . replace ( / ( \r \n | \n | \r ) / gm, " " ) ;
117
+
118
+ const matches = cleanCommand . match ( optionsRegex ) ;
119
+ matches . forEach ( ( val ) => {
120
+ // const option = removeLeadingTrailingQuotes(val);
121
+ const option = val ;
122
+ if ( isAUrlOption ( option ) ) {
123
+ const { url, queryStrings } = parseUrlOption ( option ) ;
124
+ parsedCommand . url = url ;
125
+ parsedCommand . queryStrings = queryStrings ;
126
+ } else if ( isAHeaderOption ( option ) ) {
127
+ const { key, value } = parseOptionValue ( option ) ;
128
+ parsedCommand . headers = parsedCommand . headers || { } ;
129
+ parsedCommand . headers [ key ] = value ;
130
+ } else if ( isDataOption ( option ) ) {
131
+ parsedCommand . body = parseBody ( option ) ;
132
+ } else {
133
+ console . log ( `Skipped Header ${ val } ` ) ; // eslint-disable-line
134
+ }
135
+ } ) ; // parse over matches ends
136
+
137
+ // should be checked after all the options are analyzed
138
+ // so that we guarentee that we have content-type header
139
+ parsedCommand . body = parseBodyByContentType ( parsedCommand ) ;
140
+ }
141
+ return parsedCommand ;
142
+ }
143
+
144
+ export default parse ;
0 commit comments