@ohos-ports/curlconverter 4.12.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +153 -0
  3. package/dist/src/Headers.d.ts +23 -0
  4. package/dist/src/Headers.js +287 -0
  5. package/dist/src/Headers.js.map +1 -0
  6. package/dist/src/Query.d.ts +8 -0
  7. package/dist/src/Query.js +136 -0
  8. package/dist/src/Query.js.map +1 -0
  9. package/dist/src/Request.d.ts +200 -0
  10. package/dist/src/Request.js +1191 -0
  11. package/dist/src/Request.js.map +1 -0
  12. package/dist/src/Warnings.d.ts +15 -0
  13. package/dist/src/Warnings.js +111 -0
  14. package/dist/src/Warnings.js.map +1 -0
  15. package/dist/src/cli.d.ts +2 -0
  16. package/dist/src/cli.js +333 -0
  17. package/dist/src/cli.js.map +1 -0
  18. package/dist/src/curl/auth.d.ts +12 -0
  19. package/dist/src/curl/auth.js +40 -0
  20. package/dist/src/curl/auth.js.map +1 -0
  21. package/dist/src/curl/form.d.ts +28 -0
  22. package/dist/src/curl/form.js +218 -0
  23. package/dist/src/curl/form.js.map +1 -0
  24. package/dist/src/curl/opts.d.ts +2052 -0
  25. package/dist/src/curl/opts.js +1000 -0
  26. package/dist/src/curl/opts.js.map +1 -0
  27. package/dist/src/curl/url.d.ts +14 -0
  28. package/dist/src/curl/url.js +218 -0
  29. package/dist/src/curl/url.js.map +1 -0
  30. package/dist/src/generators/ansible.d.ts +5 -0
  31. package/dist/src/generators/ansible.js +282 -0
  32. package/dist/src/generators/ansible.js.map +1 -0
  33. package/dist/src/generators/c.d.ts +12 -0
  34. package/dist/src/generators/c.js +1230 -0
  35. package/dist/src/generators/c.js.map +1 -0
  36. package/dist/src/generators/cfml.d.ts +5 -0
  37. package/dist/src/generators/cfml.js +134 -0
  38. package/dist/src/generators/cfml.js.map +1 -0
  39. package/dist/src/generators/clojure.d.ts +7 -0
  40. package/dist/src/generators/clojure.js +436 -0
  41. package/dist/src/generators/clojure.js.map +1 -0
  42. package/dist/src/generators/csharp.d.ts +8 -0
  43. package/dist/src/generators/csharp.js +356 -0
  44. package/dist/src/generators/csharp.js.map +1 -0
  45. package/dist/src/generators/dart.d.ts +5 -0
  46. package/dist/src/generators/dart.js +273 -0
  47. package/dist/src/generators/dart.js.map +1 -0
  48. package/dist/src/generators/elixir.d.ts +8 -0
  49. package/dist/src/generators/elixir.js +296 -0
  50. package/dist/src/generators/elixir.js.map +1 -0
  51. package/dist/src/generators/go.d.ts +5 -0
  52. package/dist/src/generators/go.js +228 -0
  53. package/dist/src/generators/go.js.map +1 -0
  54. package/dist/src/generators/har.d.ts +7 -0
  55. package/dist/src/generators/har.js +115 -0
  56. package/dist/src/generators/har.js.map +1 -0
  57. package/dist/src/generators/http.d.ts +7 -0
  58. package/dist/src/generators/http.js +165 -0
  59. package/dist/src/generators/http.js.map +1 -0
  60. package/dist/src/generators/httpie.d.ts +5 -0
  61. package/dist/src/generators/httpie.js +446 -0
  62. package/dist/src/generators/httpie.js.map +1 -0
  63. package/dist/src/generators/java/httpurlconnection.d.ts +5 -0
  64. package/dist/src/generators/java/httpurlconnection.js +123 -0
  65. package/dist/src/generators/java/httpurlconnection.js.map +1 -0
  66. package/dist/src/generators/java/java.d.ts +8 -0
  67. package/dist/src/generators/java/java.js +247 -0
  68. package/dist/src/generators/java/java.js.map +1 -0
  69. package/dist/src/generators/java/jsoup.d.ts +5 -0
  70. package/dist/src/generators/java/jsoup.js +152 -0
  71. package/dist/src/generators/java/jsoup.js.map +1 -0
  72. package/dist/src/generators/java/okhttp.d.ts +5 -0
  73. package/dist/src/generators/java/okhttp.js +232 -0
  74. package/dist/src/generators/java/okhttp.js.map +1 -0
  75. package/dist/src/generators/javascript/axios.d.ts +5 -0
  76. package/dist/src/generators/javascript/axios.js +332 -0
  77. package/dist/src/generators/javascript/axios.js.map +1 -0
  78. package/dist/src/generators/javascript/got.d.ts +5 -0
  79. package/dist/src/generators/javascript/got.js +277 -0
  80. package/dist/src/generators/javascript/got.js.map +1 -0
  81. package/dist/src/generators/javascript/http.d.ts +8 -0
  82. package/dist/src/generators/javascript/http.js +183 -0
  83. package/dist/src/generators/javascript/http.js.map +1 -0
  84. package/dist/src/generators/javascript/javascript.d.ts +37 -0
  85. package/dist/src/generators/javascript/javascript.js +676 -0
  86. package/dist/src/generators/javascript/javascript.js.map +1 -0
  87. package/dist/src/generators/javascript/jquery.d.ts +15 -0
  88. package/dist/src/generators/javascript/jquery.js +297 -0
  89. package/dist/src/generators/javascript/jquery.js.map +1 -0
  90. package/dist/src/generators/javascript/ky.d.ts +7 -0
  91. package/dist/src/generators/javascript/ky.js +245 -0
  92. package/dist/src/generators/javascript/ky.js.map +1 -0
  93. package/dist/src/generators/javascript/request.d.ts +5 -0
  94. package/dist/src/generators/javascript/request.js +113 -0
  95. package/dist/src/generators/javascript/request.js.map +1 -0
  96. package/dist/src/generators/javascript/superagent.d.ts +10 -0
  97. package/dist/src/generators/javascript/superagent.js +301 -0
  98. package/dist/src/generators/javascript/superagent.js.map +1 -0
  99. package/dist/src/generators/javascript/xhr.d.ts +8 -0
  100. package/dist/src/generators/javascript/xhr.js +147 -0
  101. package/dist/src/generators/javascript/xhr.js.map +1 -0
  102. package/dist/src/generators/json.d.ts +45 -0
  103. package/dist/src/generators/json.js +197 -0
  104. package/dist/src/generators/json.js.map +1 -0
  105. package/dist/src/generators/julia.d.ts +8 -0
  106. package/dist/src/generators/julia.js +365 -0
  107. package/dist/src/generators/julia.js.map +1 -0
  108. package/dist/src/generators/kotlin.d.ts +8 -0
  109. package/dist/src/generators/kotlin.js +325 -0
  110. package/dist/src/generators/kotlin.js.map +1 -0
  111. package/dist/src/generators/lua.d.ts +5 -0
  112. package/dist/src/generators/lua.js +192 -0
  113. package/dist/src/generators/lua.js.map +1 -0
  114. package/dist/src/generators/matlab/common.d.ts +16 -0
  115. package/dist/src/generators/matlab/common.js +238 -0
  116. package/dist/src/generators/matlab/common.js.map +1 -0
  117. package/dist/src/generators/matlab/httpinterface.d.ts +2 -0
  118. package/dist/src/generators/matlab/httpinterface.js +211 -0
  119. package/dist/src/generators/matlab/httpinterface.js.map +1 -0
  120. package/dist/src/generators/matlab/matlab.d.ts +5 -0
  121. package/dist/src/generators/matlab/matlab.js +29 -0
  122. package/dist/src/generators/matlab/matlab.js.map +1 -0
  123. package/dist/src/generators/matlab/webservices.d.ts +2 -0
  124. package/dist/src/generators/matlab/webservices.js +191 -0
  125. package/dist/src/generators/matlab/webservices.js.map +1 -0
  126. package/dist/src/generators/objectivec.d.ts +8 -0
  127. package/dist/src/generators/objectivec.js +269 -0
  128. package/dist/src/generators/objectivec.js.map +1 -0
  129. package/dist/src/generators/ocaml.d.ts +8 -0
  130. package/dist/src/generators/ocaml.js +150 -0
  131. package/dist/src/generators/ocaml.js.map +1 -0
  132. package/dist/src/generators/perl.d.ts +9 -0
  133. package/dist/src/generators/perl.js +209 -0
  134. package/dist/src/generators/perl.js.map +1 -0
  135. package/dist/src/generators/php/guzzle.d.ts +5 -0
  136. package/dist/src/generators/php/guzzle.js +328 -0
  137. package/dist/src/generators/php/guzzle.js.map +1 -0
  138. package/dist/src/generators/php/php.d.ts +8 -0
  139. package/dist/src/generators/php/php.js +217 -0
  140. package/dist/src/generators/php/php.js.map +1 -0
  141. package/dist/src/generators/php/requests.d.ts +5 -0
  142. package/dist/src/generators/php/requests.js +89 -0
  143. package/dist/src/generators/php/requests.js.map +1 -0
  144. package/dist/src/generators/powershell.d.ts +11 -0
  145. package/dist/src/generators/powershell.js +377 -0
  146. package/dist/src/generators/powershell.js.map +1 -0
  147. package/dist/src/generators/python/http.d.ts +5 -0
  148. package/dist/src/generators/python/http.js +128 -0
  149. package/dist/src/generators/python/http.js.map +1 -0
  150. package/dist/src/generators/python/python.d.ts +22 -0
  151. package/dist/src/generators/python/python.js +1693 -0
  152. package/dist/src/generators/python/python.js.map +1 -0
  153. package/dist/src/generators/r/httr.d.ts +10 -0
  154. package/dist/src/generators/r/httr.js +298 -0
  155. package/dist/src/generators/r/httr.js.map +1 -0
  156. package/dist/src/generators/r/httr2.d.ts +5 -0
  157. package/dist/src/generators/r/httr2.js +214 -0
  158. package/dist/src/generators/r/httr2.js.map +1 -0
  159. package/dist/src/generators/ruby/httparty.d.ts +6 -0
  160. package/dist/src/generators/ruby/httparty.js +308 -0
  161. package/dist/src/generators/ruby/httparty.js.map +1 -0
  162. package/dist/src/generators/ruby/ruby.d.ts +14 -0
  163. package/dist/src/generators/ruby/ruby.js +515 -0
  164. package/dist/src/generators/ruby/ruby.js.map +1 -0
  165. package/dist/src/generators/rust.d.ts +8 -0
  166. package/dist/src/generators/rust.js +177 -0
  167. package/dist/src/generators/rust.js.map +1 -0
  168. package/dist/src/generators/swift.d.ts +8 -0
  169. package/dist/src/generators/swift.js +219 -0
  170. package/dist/src/generators/swift.js.map +1 -0
  171. package/dist/src/generators/wget.d.ts +8 -0
  172. package/dist/src/generators/wget.js +472 -0
  173. package/dist/src/generators/wget.js.map +1 -0
  174. package/dist/src/index.d.ts +53 -0
  175. package/dist/src/index.js +54 -0
  176. package/dist/src/index.js.map +1 -0
  177. package/dist/src/parse.d.ts +13 -0
  178. package/dist/src/parse.js +43 -0
  179. package/dist/src/parse.js.map +1 -0
  180. package/dist/src/shell/Parser.d.ts +4 -0
  181. package/dist/src/shell/Parser.js +6 -0
  182. package/dist/src/shell/Parser.js.map +1 -0
  183. package/dist/src/shell/Word.d.ts +48 -0
  184. package/dist/src/shell/Word.js +486 -0
  185. package/dist/src/shell/Word.js.map +1 -0
  186. package/dist/src/shell/tokenizer.d.ts +3 -0
  187. package/dist/src/shell/tokenizer.js +610 -0
  188. package/dist/src/shell/tokenizer.js.map +1 -0
  189. package/dist/src/shell/webParser.d.ts +4 -0
  190. package/dist/src/shell/webParser.js +15 -0
  191. package/dist/src/shell/webParser.js.map +1 -0
  192. package/dist/src/utils.d.ts +6 -0
  193. package/dist/src/utils.js +21 -0
  194. package/dist/src/utils.js.map +1 -0
  195. package/dist/tools/compare-requests.d.ts +2 -0
  196. package/dist/tools/compare-requests.js +448 -0
  197. package/dist/tools/compare-requests.js.map +1 -0
  198. package/dist/tools/gen-test.d.ts +2 -0
  199. package/dist/tools/gen-test.js +114 -0
  200. package/dist/tools/gen-test.js.map +1 -0
  201. package/dist/tree-sitter-bash.wasm +0 -0
  202. package/index.d.ts +3 -0
  203. package/package.json +97 -0
  204. package/src/Headers.ts +334 -0
  205. package/src/Query.ts +147 -0
  206. package/src/Request.ts +1649 -0
  207. package/src/Warnings.ts +154 -0
  208. package/src/cli.ts +561 -0
  209. package/src/curl/auth.ts +45 -0
  210. package/src/curl/form.ts +297 -0
  211. package/src/curl/opts.ts +1417 -0
  212. package/src/curl/url.ts +241 -0
  213. package/src/generators/ansible.ts +364 -0
  214. package/src/generators/c.ts +1371 -0
  215. package/src/generators/cfml.ts +155 -0
  216. package/src/generators/clojure.ts +521 -0
  217. package/src/generators/csharp.ts +383 -0
  218. package/src/generators/dart.ts +293 -0
  219. package/src/generators/elixir.ts +349 -0
  220. package/src/generators/go.ts +269 -0
  221. package/src/generators/har.ts +147 -0
  222. package/src/generators/http.ts +194 -0
  223. package/src/generators/httpie.ts +506 -0
  224. package/src/generators/java/httpurlconnection.ts +151 -0
  225. package/src/generators/java/java.ts +280 -0
  226. package/src/generators/java/jsoup.ts +172 -0
  227. package/src/generators/java/okhttp.ts +257 -0
  228. package/src/generators/javascript/axios.ts +395 -0
  229. package/src/generators/javascript/got.ts +362 -0
  230. package/src/generators/javascript/http.ts +232 -0
  231. package/src/generators/javascript/javascript.ts +825 -0
  232. package/src/generators/javascript/jquery.ts +360 -0
  233. package/src/generators/javascript/ky.ts +315 -0
  234. package/src/generators/javascript/request.ts +152 -0
  235. package/src/generators/javascript/superagent.ts +373 -0
  236. package/src/generators/javascript/xhr.ts +192 -0
  237. package/src/generators/json.ts +293 -0
  238. package/src/generators/julia.ts +398 -0
  239. package/src/generators/kotlin.ts +355 -0
  240. package/src/generators/lua.ts +209 -0
  241. package/src/generators/matlab/common.ts +281 -0
  242. package/src/generators/matlab/httpinterface.ts +284 -0
  243. package/src/generators/matlab/matlab.ts +39 -0
  244. package/src/generators/matlab/webservices.ts +263 -0
  245. package/src/generators/objectivec.ts +297 -0
  246. package/src/generators/ocaml.ts +168 -0
  247. package/src/generators/perl.ts +237 -0
  248. package/src/generators/php/guzzle.ts +368 -0
  249. package/src/generators/php/php.ts +239 -0
  250. package/src/generators/php/requests.ts +103 -0
  251. package/src/generators/powershell.ts +430 -0
  252. package/src/generators/python/http.ts +167 -0
  253. package/src/generators/python/python.ts +1934 -0
  254. package/src/generators/r/httr.ts +328 -0
  255. package/src/generators/r/httr2.ts +268 -0
  256. package/src/generators/ruby/httparty.ts +351 -0
  257. package/src/generators/ruby/ruby.ts +564 -0
  258. package/src/generators/rust.ts +243 -0
  259. package/src/generators/swift.ts +235 -0
  260. package/src/generators/wget.ts +533 -0
  261. package/src/index.ts +89 -0
  262. package/src/parse.ts +72 -0
  263. package/src/shell/Parser.ts +8 -0
  264. package/src/shell/Word.ts +531 -0
  265. package/src/shell/tokenizer.ts +736 -0
  266. package/src/shell/webParser.ts +18 -0
  267. package/src/utils.ts +25 -0
  268. package/tools/compare-requests.ts +571 -0
  269. package/tools/extract_curl_args.py +511 -0
  270. package/tools/gen-test.ts +129 -0
@@ -0,0 +1,328 @@
1
+ import { Word, eq } from "../../shell/Word.js";
2
+ import { parse, getFirst, COMMON_SUPPORTED_ARGS } from "../../parse.js";
3
+ import type { Request, Warnings } from "../../parse.js";
4
+ import { wordDecodeURIComponent, parseQueryString } from "../../Query.js";
5
+ import type { QueryList } from "../../Query.js";
6
+
7
+ import { reprStr as pyrepr } from "../python/python.js";
8
+
9
+ export const supportedArgs = new Set([
10
+ ...COMMON_SUPPORTED_ARGS,
11
+ "form",
12
+ "form-string",
13
+ "insecure",
14
+ "no-insecure",
15
+ ]);
16
+
17
+ const RESERVED_WORDS = new Set([
18
+ "if",
19
+ "else",
20
+ "repeat",
21
+ "while",
22
+ "function",
23
+ "for",
24
+ "in",
25
+ "next",
26
+ "break",
27
+ "TRUE",
28
+ "FALSE",
29
+ "NULL",
30
+ "Inf",
31
+ "NaN",
32
+ "NA",
33
+ "NA_integer_",
34
+ "NA_real_",
35
+ "NA_complex_",
36
+ "NA_character_",
37
+ ]);
38
+
39
+ // backtick quote names
40
+ const regexBacktickEscape = /`|\\|\p{C}|[^ \P{Z}]/gu;
41
+ export function reprBacktick(s: Word | string): string {
42
+ if (s instanceof Word) {
43
+ if (!s.isString()) {
44
+ // TODO: warn
45
+ }
46
+
47
+ s = s.toString();
48
+ }
49
+
50
+ if (
51
+ (s.match(/^[a-zA-Z][a-zA-Z0-9._]*$/) ||
52
+ s.match(/^\.[a-zA-Z][a-zA-Z0-9._]*$/)) &&
53
+ !RESERVED_WORDS.has(s)
54
+ ) {
55
+ return s;
56
+ }
57
+
58
+ return (
59
+ "`" +
60
+ s.replace(regexBacktickEscape, (c: string): string => {
61
+ switch (c) {
62
+ case "\x07":
63
+ return "\\a";
64
+ case "\b":
65
+ return "\\b";
66
+ case "\f":
67
+ return "\\f";
68
+ case "\n":
69
+ return "\\n";
70
+ case "\r":
71
+ return "\\r";
72
+ case "\t":
73
+ return "\\t";
74
+ case "\v":
75
+ return "\\v";
76
+ case "\\":
77
+ return "\\\\";
78
+ case "`":
79
+ return "\\`";
80
+ }
81
+ const hex = (c.codePointAt(0) as number).toString(16);
82
+ if (hex.length <= 2) {
83
+ return "\\x" + hex.padStart(2, "0");
84
+ }
85
+ if (hex.length <= 4) {
86
+ return "\\u" + hex.padStart(4, "0");
87
+ }
88
+ return "\\U" + hex.padStart(8, "0");
89
+ }) +
90
+ "`"
91
+ );
92
+ }
93
+
94
+ // https://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html#Literal-constants
95
+ export function reprStr(s: string): string {
96
+ // R prefers double quotes
97
+ const quote = s.includes('"') && !s.includes("'") ? "'" : '"';
98
+ return pyrepr(s, quote);
99
+ }
100
+
101
+ export function repr(w: Word): string {
102
+ const args: string[] = [];
103
+ for (const t of w.tokens) {
104
+ if (typeof t === "string") {
105
+ args.push(reprStr(t));
106
+ } else if (t.type === "variable") {
107
+ args.push("Sys.getenv(" + reprStr(t.value) + ")");
108
+ } else {
109
+ args.push("system(" + reprStr(t.value) + ", intern = TRUE)");
110
+ }
111
+ }
112
+ if (args.length === 1) {
113
+ return args[0];
114
+ }
115
+ return "paste0(" + args.join(", ") + ")";
116
+ }
117
+
118
+ export function toNumeric(w: Word): string {
119
+ if (w.isString()) {
120
+ const s = w.toString();
121
+ // TODO: better check
122
+ if (parseFloat(s).toString() === s) {
123
+ return s;
124
+ }
125
+ }
126
+ return "as.numeric(" + repr(w) + ")";
127
+ }
128
+
129
+ function getCookieDict(request: Request): string | null {
130
+ if (!request.cookies) {
131
+ return null;
132
+ }
133
+ let cookieDict = "cookies = c(\n";
134
+
135
+ const lines: string[] = [];
136
+ for (const [key, value] of request.cookies) {
137
+ try {
138
+ // httr percent-encodes cookie values
139
+ const decoded = wordDecodeURIComponent(value.replace(/\+/g, " "));
140
+ lines.push(" " + reprBacktick(key) + " = " + repr(decoded));
141
+ } catch {
142
+ return null;
143
+ }
144
+ }
145
+ cookieDict += lines.join(",\n");
146
+ cookieDict += "\n)\n";
147
+
148
+ request.headers.delete("Cookie");
149
+ return cookieDict;
150
+ }
151
+
152
+ function getQueryList(request: Request): string | undefined {
153
+ if (request.urls[0].queryList === undefined) {
154
+ return undefined;
155
+ }
156
+
157
+ let queryList = "params = list(\n";
158
+ queryList += request.urls[0].queryList
159
+ .map((param) => {
160
+ const [key, value] = param;
161
+ return " " + reprBacktick(key) + " = " + repr(value);
162
+ })
163
+ .join(",\n");
164
+ queryList += "\n)\n";
165
+ return queryList;
166
+ }
167
+
168
+ function getFilesString(request: Request): string | undefined {
169
+ if (!request.multipartUploads) {
170
+ return undefined;
171
+ }
172
+ // http://docs.rstats-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
173
+ let filesString = "files = list(\n";
174
+ filesString += request.multipartUploads
175
+ .map((m) => {
176
+ let fileParam;
177
+ if ("contentFile" in m) {
178
+ // filesString += " " + reprBacktick(multipartKey) + " (" + repr(fileName) + ", upload_file(" + repr(fileName) + "))";
179
+ fileParam =
180
+ " " +
181
+ reprBacktick(m.name) +
182
+ " = upload_file(" +
183
+ repr(m.contentFile) +
184
+ ")";
185
+ } else {
186
+ fileParam = " " + reprBacktick(m.name) + " = " + repr(m.content) + "";
187
+ }
188
+ return fileParam;
189
+ })
190
+ .join(",\n");
191
+ filesString += "\n)\n";
192
+
193
+ return filesString;
194
+ }
195
+
196
+ export function _toR(requests: Request[], warnings: Warnings = []): string {
197
+ const request = getFirst(requests, warnings);
198
+
199
+ const cookieDict = getCookieDict(request);
200
+
201
+ let headerDict;
202
+ if (request.headers.length) {
203
+ const hels: string[] = [];
204
+ headerDict = "headers = c(\n";
205
+ for (const [headerName, headerValue] of request.headers) {
206
+ if (headerValue !== null) {
207
+ hels.push(" " + reprBacktick(headerName) + " = " + repr(headerValue));
208
+ }
209
+ }
210
+ headerDict += hels.join(",\n");
211
+ headerDict += "\n)\n";
212
+ }
213
+
214
+ const queryList = getQueryList(request);
215
+
216
+ let dataString;
217
+ let dataIsList;
218
+ let filesString;
219
+ if (request.multipartUploads) {
220
+ filesString = getFilesString(request);
221
+ } else if (request.data) {
222
+ if (request.data.startsWith("@") && !request.isDataRaw) {
223
+ const filePath = request.data.slice(1);
224
+ dataString = "data = upload_file(" + repr(filePath) + ")";
225
+ } else {
226
+ const [parsedQueryString] = parseQueryString(request.data);
227
+ // repeat to satisfy type checker
228
+ dataIsList = parsedQueryString && parsedQueryString.length;
229
+ if (dataIsList) {
230
+ dataString = "data = list(\n";
231
+ dataString += (parsedQueryString as QueryList)
232
+ .map((q) => {
233
+ const [key, value] = q;
234
+ return " " + reprBacktick(key) + " = " + repr(value);
235
+ })
236
+ .join(",\n");
237
+ dataString += "\n)\n";
238
+ } else {
239
+ dataString = "data = " + repr(request.data) + "\n";
240
+ }
241
+ }
242
+ }
243
+ const url = request.urls[0].queryList
244
+ ? request.urls[0].urlWithoutQueryList
245
+ : request.urls[0].url;
246
+
247
+ let requestLine = "res <- httr::";
248
+
249
+ // TODO: GET() and HEAD() don't support sending data, detect and use VERB() instead
250
+ if (
251
+ ["GET", "HEAD", "PATCH", "PUT", "DELETE", "POST"].includes(
252
+ request.urls[0].method.toString(),
253
+ )
254
+ ) {
255
+ requestLine += request.urls[0].method.toString() + "(";
256
+ } else {
257
+ requestLine += "VERB(" + repr(request.urls[0].method) + ", ";
258
+ if (!eq(request.urls[0].method, request.urls[0].method.toUpperCase())) {
259
+ warnings.push([
260
+ "non-uppercase-method",
261
+ "httr will uppercase the method: " +
262
+ JSON.stringify(request.urls[0].method.toString()),
263
+ ]);
264
+ }
265
+ }
266
+ requestLine += "url = " + repr(url);
267
+
268
+ let requestLineBody = "";
269
+ if (headerDict) {
270
+ requestLineBody += ", httr::add_headers(.headers=headers)";
271
+ }
272
+ if (request.urls[0].queryList) {
273
+ requestLineBody += ", query = params";
274
+ }
275
+ if (cookieDict) {
276
+ requestLineBody += ", httr::set_cookies(.cookies = cookies)";
277
+ }
278
+ if (request.multipartUploads) {
279
+ requestLineBody += ', body = files, encode = "multipart"';
280
+ } else if (request.data) {
281
+ requestLineBody += ", body = data";
282
+ if (dataIsList) {
283
+ requestLineBody += ', encode = "form"';
284
+ }
285
+ }
286
+ if (request.insecure) {
287
+ requestLineBody += ", config = httr::config(ssl_verifypeer = FALSE)";
288
+ }
289
+ if (request.urls[0].auth) {
290
+ const [user, password] = request.urls[0].auth;
291
+ requestLineBody +=
292
+ ", httr::authenticate(" + repr(user) + ", " + repr(password) + ")";
293
+ }
294
+ requestLineBody += ")";
295
+
296
+ requestLine += requestLineBody;
297
+
298
+ let rstatsCode = "";
299
+ rstatsCode += "library(httr)\n\n";
300
+ if (cookieDict) {
301
+ rstatsCode += cookieDict + "\n";
302
+ }
303
+ if (headerDict) {
304
+ rstatsCode += headerDict + "\n";
305
+ }
306
+ if (queryList !== undefined) {
307
+ rstatsCode += queryList + "\n";
308
+ }
309
+ if (dataString) {
310
+ rstatsCode += dataString + "\n";
311
+ } else if (filesString) {
312
+ rstatsCode += filesString + "\n";
313
+ }
314
+ rstatsCode += requestLine;
315
+
316
+ return rstatsCode + "\n";
317
+ }
318
+ export function toRWarn(
319
+ curlCommand: string | string[],
320
+ warnings: Warnings = [],
321
+ ): [string, Warnings] {
322
+ const requests = parse(curlCommand, supportedArgs, warnings);
323
+ const rHttr = _toR(requests, warnings);
324
+ return [rHttr, warnings];
325
+ }
326
+ export function toR(curlCommand: string | string[]): string {
327
+ return toRWarn(curlCommand)[0];
328
+ }
@@ -0,0 +1,268 @@
1
+ import { Word, eq } from "../../shell/Word.js";
2
+ import { parse, getFirst, COMMON_SUPPORTED_ARGS } from "../../parse.js";
3
+ import type { Request, Warnings } from "../../parse.js";
4
+ import { wordDecodeURIComponent, parseQueryString } from "../../Query.js";
5
+
6
+ import { reprBacktick, reprStr, repr, toNumeric } from "./httr.js";
7
+
8
+ export const supportedArgs = new Set([
9
+ ...COMMON_SUPPORTED_ARGS,
10
+ "form",
11
+ "form-string",
12
+ "insecure",
13
+ "no-insecure",
14
+ "oauth2-bearer",
15
+
16
+ "max-redirs",
17
+
18
+ "max-time",
19
+ "connect-timeout",
20
+
21
+ "retry",
22
+ "retry-max-time",
23
+ ]);
24
+
25
+ type NamedArg = [Word | string, Word | string];
26
+
27
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28
+ function getCookieList(request: Request, warnings: Warnings): Array<NamedArg> {
29
+ if (!request.cookies) {
30
+ return [];
31
+ }
32
+ const cookieList: Array<NamedArg> = [];
33
+ for (const [key, value] of request.cookies) {
34
+ try {
35
+ // httr2 percent-encodes cookie values
36
+ const decoded = wordDecodeURIComponent(value.replace(/\+/g, " "));
37
+ cookieList.push([key, decoded]);
38
+ } catch {
39
+ warnings.push([
40
+ "cookie-decoding error",
41
+ "Cookie could not be decoded\n\n" + value.toString(),
42
+ ]);
43
+ }
44
+ }
45
+
46
+ request.headers.delete("Cookie");
47
+ return cookieList;
48
+ }
49
+
50
+ function getQueryList(request: Request): Array<NamedArg> {
51
+ return request.urls[0].queryList || [];
52
+ }
53
+
54
+ function getHeaderList(request: Request): Array<NamedArg> {
55
+ const headerList: Array<NamedArg> = [];
56
+
57
+ if (request.headers.length) {
58
+ for (const [headerName, headerValue] of request.headers) {
59
+ if (headerValue !== null) {
60
+ headerList.push([headerName, headerValue]);
61
+ }
62
+ }
63
+ }
64
+ return headerList;
65
+ }
66
+
67
+ function getMultipartParams(request: Request): Array<NamedArg> | undefined {
68
+ if (!request.multipartUploads) {
69
+ return undefined;
70
+ }
71
+ const parts = request.multipartUploads.map((m): NamedArg => {
72
+ let content;
73
+ if ("contentFile" in m) {
74
+ content = `curl::form_file(${repr(m.contentFile)})`;
75
+ } else {
76
+ content = repr(m.content);
77
+ }
78
+ return [m.name, content];
79
+ });
80
+
81
+ return parts;
82
+ }
83
+
84
+ function addBodyStep(
85
+ steps: string[],
86
+ request: Request,
87
+ contentType: string | null | undefined,
88
+ ): Array<string> {
89
+ if (request.multipartUploads) {
90
+ const params = getMultipartParams(request);
91
+ return addCurlStep(steps, "req_body_multipart", [], params);
92
+ }
93
+
94
+ if (!request.data) {
95
+ return steps;
96
+ }
97
+
98
+ if (request.data.startsWith("@") && !request.isDataRaw) {
99
+ const filePath = request.data.slice(1);
100
+ steps = addCurlStep(steps, "req_body_file", [repr(filePath)]);
101
+ } else {
102
+ const [parsedQueryString] = parseQueryString(request.data);
103
+ const dataIsList = parsedQueryString && parsedQueryString.length;
104
+ if (dataIsList) {
105
+ steps = addCurlStep(steps, "req_body_form", [], parsedQueryString);
106
+ } else {
107
+ contentType = contentType || "application/x-www-form-urlencoded";
108
+ steps = addCurlStep(
109
+ steps,
110
+ "req_body_raw",
111
+ [repr(request.data)],
112
+ [["type", reprStr(contentType)]],
113
+ );
114
+ }
115
+ }
116
+ // TODO: json
117
+
118
+ return steps;
119
+ }
120
+
121
+ function addCurlStep(
122
+ steps: Array<string>,
123
+ f: string,
124
+ mainArgs: Array<string>,
125
+ dots: Array<NamedArg> = [],
126
+ keepIfEmpty = false,
127
+ ) {
128
+ const dotArgs = dots.map((dot) => {
129
+ let [name, value] = dot;
130
+ if (value instanceof Word) {
131
+ value = repr(value);
132
+ }
133
+ if (name === "" || (name instanceof Word && name.isEmpty())) {
134
+ return value;
135
+ }
136
+
137
+ if (name instanceof Word) {
138
+ name = reprBacktick(name);
139
+ }
140
+ return `${name} = ${value}`;
141
+ });
142
+
143
+ const args = mainArgs.concat(...dotArgs);
144
+ if (args.length === 0 && !keepIfEmpty) {
145
+ return steps;
146
+ }
147
+
148
+ let newStep: string;
149
+ if (dots.length === 0 || args.length === 1) {
150
+ const argsString = args.join(", ");
151
+ newStep = `${f}(${argsString})`;
152
+ } else {
153
+ const indent = " ";
154
+ const argsString = args.join(`,\n${indent}`);
155
+ newStep = `${f}(\n${indent}${argsString}\n )`;
156
+ }
157
+
158
+ return steps.concat(newStep);
159
+ }
160
+
161
+ export function _toRHttr2(
162
+ requests: Request[],
163
+ warnings: Warnings = [],
164
+ ): string {
165
+ const request = getFirst(requests, warnings);
166
+
167
+ // const cookieList = getCookieList(request, warnings);
168
+ const queryList = getQueryList(request);
169
+
170
+ const contentType = request.headers.getContentType();
171
+ request.headers.delete("Content-Type");
172
+ if (request.oauth2Bearer && request.authType === "bearer") {
173
+ request.headers.delete("Authorization");
174
+ }
175
+ const headerList = getHeaderList(request);
176
+
177
+ const url = request.urls[0].queryList
178
+ ? request.urls[0].urlWithoutQueryList
179
+ : request.urls[0].url;
180
+
181
+ const method = request.urls[0].method;
182
+ if (!eq(method, method.toUpperCase())) {
183
+ warnings.push([
184
+ "non-uppercase-method",
185
+ "httr will uppercase the method: " + JSON.stringify(method.toString()),
186
+ ]);
187
+ }
188
+
189
+ let steps = [`request(${repr(url)})`];
190
+ if (method.toString() != "GET") {
191
+ steps = addCurlStep(steps, "req_method", [repr(method)]);
192
+ }
193
+
194
+ steps = addCurlStep(steps, "req_url_query", [], queryList);
195
+ steps = addCurlStep(steps, "req_headers", [], headerList);
196
+ // TODO: use `req_cookie_set()` once it is added
197
+ // https://github.com/r-lib/httr2/issues/369
198
+ // steps = addCurlStep(steps, "req_headers", [], cookieList);
199
+ // TODO: support cookies from file?
200
+
201
+ steps = addBodyStep(steps, request, contentType);
202
+
203
+ if (request.urls[0].auth && request.authType === "basic") {
204
+ const [user, password] = request.urls[0].auth;
205
+ steps = addCurlStep(steps, "req_auth_basic", [repr(user), repr(password)]);
206
+ } else if (request.oauth2Bearer && request.authType === "bearer") {
207
+ steps = addCurlStep(steps, "req_auth_bearer_token", [
208
+ repr(request.oauth2Bearer),
209
+ ]);
210
+ }
211
+ // TODO: req_oauth_auth_code
212
+
213
+ if (request.proxy) {
214
+ const url = request.proxy.toString();
215
+ addCurlStep(steps, "req_proxy", [url]);
216
+ }
217
+
218
+ if (request.timeout) {
219
+ // TODO: parse float/int
220
+ steps = addCurlStep(steps, "req_timeout", [toNumeric(request.timeout)]);
221
+ }
222
+
223
+ // TODO: all curl options could be supported here, like in the C generator
224
+ const curlOptions: Array<NamedArg> = [];
225
+ if (request.insecure) {
226
+ curlOptions.push(["ssl_verifypeer", "0"]);
227
+ }
228
+ if (request.maxRedirects !== undefined) {
229
+ curlOptions.push(["maxredirs", toNumeric(request.maxRedirects)]);
230
+ }
231
+ if (request.connectTimeout) {
232
+ // TODO: parse float/int
233
+ curlOptions.push(["connecttimeout", toNumeric(request.connectTimeout)]);
234
+ }
235
+ steps = addCurlStep(steps, "req_options", [], curlOptions);
236
+
237
+ const retryOptions: Array<NamedArg> = [];
238
+ if (request.retry) {
239
+ retryOptions.push(["max_tries", toNumeric(request.retry)]);
240
+ }
241
+ if (request.retryMaxTime) {
242
+ retryOptions.push(["max_seconds", toNumeric(request.retryMaxTime)]);
243
+ }
244
+ steps = addCurlStep(steps, "req_retry", [], retryOptions);
245
+
246
+ const performArgs: Array<[string, string]> = [];
247
+ // TODO: add test
248
+ if (request.verbose) {
249
+ performArgs.push(["verbosity", "1"]);
250
+ }
251
+ steps = addCurlStep(steps, "req_perform", [], performArgs, true);
252
+
253
+ let rstatsCode = "library(httr2)\n\n";
254
+ rstatsCode += steps.join(" |>\n ");
255
+
256
+ return rstatsCode + "\n";
257
+ }
258
+ export function toRHttr2Warn(
259
+ curlCommand: string | string[],
260
+ warnings: Warnings = [],
261
+ ): [string, Warnings] {
262
+ const requests = parse(curlCommand, supportedArgs, warnings);
263
+ const rHttr = _toRHttr2(requests, warnings);
264
+ return [rHttr, warnings];
265
+ }
266
+ export function toRHttr2(curlCommand: string | string[]): string {
267
+ return toRHttr2Warn(curlCommand)[0];
268
+ }