@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,243 @@
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
+
5
+ export const supportedArgs = new Set([
6
+ ...COMMON_SUPPORTED_ARGS,
7
+ "form",
8
+ "form-string",
9
+ "max-redirs",
10
+ "location",
11
+ "no-location",
12
+ // "location-trusted",
13
+ // "no-location-trusted",
14
+ ]);
15
+
16
+ const INDENTATION = " ".repeat(4);
17
+ function indent(line: string, level = 1): string {
18
+ return INDENTATION.repeat(level) + line;
19
+ }
20
+
21
+ // https://doc.rust-lang.org/reference/tokens.html
22
+ const regexEscape = /"|\\|\p{C}|[^ \P{Z}]/gu;
23
+ export function reprStr(s: string): string {
24
+ return (
25
+ '"' +
26
+ s.replace(regexEscape, (c: string): string => {
27
+ switch (c) {
28
+ case "\n":
29
+ return "\\n";
30
+ case "\r":
31
+ return "\\r";
32
+ case "\t":
33
+ return "\\t";
34
+ case "\0":
35
+ return "\\0";
36
+ case "\\":
37
+ return "\\\\";
38
+ case '"':
39
+ return '\\"';
40
+ }
41
+ const hex = (c.codePointAt(0) as number).toString(16);
42
+ if (hex.length <= 2) {
43
+ return "\\x" + hex.padStart(2, "0");
44
+ }
45
+ return "\\u{" + hex + "}";
46
+ }) +
47
+ '"'
48
+ );
49
+ }
50
+
51
+ export function repr(w: Word, imports: Set<string>): string {
52
+ const ret: string[] = [];
53
+ for (const t of w.tokens) {
54
+ if (typeof t === "string") {
55
+ ret.push(reprStr(t));
56
+ } else if (t.type === "variable") {
57
+ ret.push("env::var(" + reprStr(t.value) + ').unwrap_or("")');
58
+ imports.add("std::env");
59
+ } else {
60
+ // TODO: tokenize subcommand
61
+ // .new() is only passed the command name, args are given with .arg().arg() or .args([])
62
+ ret.push("Command::new(" + reprStr(t.value) + ").output().stdout");
63
+ imports.add("std::process::Command");
64
+ }
65
+ }
66
+ if (ret.length === 1) {
67
+ return ret[0];
68
+ }
69
+ return "[" + ret.join(", ") + "].concat()";
70
+ }
71
+
72
+ export function _toRust(requests: Request[], warnings: Warnings = []): string {
73
+ const request = getFirst(requests, warnings);
74
+
75
+ const imports = new Set<string>();
76
+ const lines: string[] = [];
77
+ lines.push("", "fn main() -> Result<(), Box<dyn std::error::Error>> {");
78
+
79
+ if (request.headers.length) {
80
+ lines.push(indent("let mut headers = header::HeaderMap::new();"));
81
+ const headerEnum: { [key: string]: string } = {
82
+ cookie: "header::COOKIE",
83
+ };
84
+ for (const [headerName, headerValue] of request.headers) {
85
+ const enumValue = headerEnum[headerName.toLowerCase().toString()];
86
+ const name = enumValue || `"${headerName}"`;
87
+ if (headerValue !== null) {
88
+ lines.push(
89
+ indent(
90
+ `headers.insert(${name}, ${repr(
91
+ headerValue,
92
+ imports,
93
+ )}.parse().unwrap());`,
94
+ ),
95
+ );
96
+ }
97
+ }
98
+ lines.push("");
99
+ }
100
+
101
+ if (request.multipartUploads) {
102
+ lines.push(indent("let form = multipart::Form::new()"));
103
+ const parts = request.multipartUploads.map((m) => {
104
+ if ("contentFile" in m) {
105
+ return indent(
106
+ `.file(${repr(m.name, imports)}, ${repr(m.contentFile, imports)})?`,
107
+ 2,
108
+ );
109
+ }
110
+ return indent(
111
+ `.text(${repr(m.name, imports)}, ${repr(m.content, imports)})`,
112
+ 2,
113
+ );
114
+ });
115
+ parts[parts.length - 1] += ";";
116
+ lines.push(...parts, "");
117
+ }
118
+
119
+ if (!request.followRedirects) {
120
+ lines.push(indent("let client = reqwest::blocking::Client::builder()"));
121
+ lines.push(indent(".redirect(reqwest::redirect::Policy::none())", 2));
122
+ lines.push(indent(".build()", 2));
123
+ lines.push(indent(".unwrap();", 2));
124
+ } else if (typeof request.maxRedirects === "undefined") {
125
+ // Curl's default is following 50 redirects, reqwest's is 10
126
+ lines.push(indent("let client = reqwest::blocking::Client::new();"));
127
+ } else {
128
+ lines.push(indent("let client = reqwest::blocking::Client::builder()"));
129
+ if (eq(request.maxRedirects, "-1")) {
130
+ lines.push(
131
+ indent(
132
+ ".redirect(reqwest::redirect::Policy::custom(|attempt| { attempt.follow() }))",
133
+ 2,
134
+ ),
135
+ );
136
+ } else {
137
+ // Insert the --max-redirs value as-is, hoping it's a valid integer
138
+ lines.push(
139
+ indent(
140
+ ".redirect(reqwest::redirect::Policy::limited(" +
141
+ request.maxRedirects.trim().toString() +
142
+ "))",
143
+ 2,
144
+ ),
145
+ );
146
+ }
147
+ lines.push(indent(".build()", 2));
148
+ lines.push(indent(".unwrap();", 2));
149
+ }
150
+
151
+ const reqwestMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"];
152
+ if (reqwestMethods.includes(request.urls[0].method.toString())) {
153
+ lines.push(
154
+ indent(
155
+ `let res = client.${request.urls[0].method.toLowerCase()}(${repr(
156
+ request.urls[0].url,
157
+ imports,
158
+ )})`,
159
+ ),
160
+ );
161
+ } else {
162
+ lines.push(
163
+ indent(
164
+ `let res = client.request(${repr(
165
+ request.urls[0].method,
166
+ imports,
167
+ )}, ${repr(request.urls[0].url, imports)})`,
168
+ ),
169
+ );
170
+ }
171
+
172
+ if (request.urls[0].auth) {
173
+ const [user, password] = request.urls[0].auth;
174
+ lines.push(
175
+ indent(
176
+ `.basic_auth(${repr(user, imports)}, Some(${repr(password, imports)}))`,
177
+ 2,
178
+ ),
179
+ );
180
+ }
181
+
182
+ if (request.headers.length) {
183
+ lines.push(indent(".headers(headers)", 2));
184
+ }
185
+
186
+ if (request.multipartUploads) {
187
+ lines.push(indent(".multipart(form)", 2));
188
+ } else if (request.data) {
189
+ if (request.data && request.data.indexOf("\n") !== -1) {
190
+ // Use raw strings for multiline content
191
+ lines.push(
192
+ indent('.body(r#"', 2),
193
+ request.data.toString(), // TODO: this is wrong
194
+ '"#',
195
+ indent(")", 2),
196
+ );
197
+ } else {
198
+ lines.push(indent(`.body(${repr(request.data, imports)})`, 2));
199
+ }
200
+ }
201
+
202
+ lines.push(
203
+ indent(".send()?", 2),
204
+ indent(".text()?;", 2),
205
+ indent('println!("{}", res);'),
206
+ "",
207
+ indent("Ok(())"),
208
+ "}",
209
+ );
210
+
211
+ const preambleLines = ["extern crate reqwest;"];
212
+ {
213
+ // Generate imports.
214
+ const imports = [
215
+ { want: "header", condition: !!request.headers.length },
216
+ { want: "blocking::multipart", condition: !!request.multipartUploads },
217
+ ]
218
+ .filter((i) => i.condition)
219
+ .map((i) => i.want);
220
+
221
+ if (imports.length > 1) {
222
+ preambleLines.push(`use reqwest::{${imports.join(", ")}};`);
223
+ } else if (imports.length) {
224
+ preambleLines.push(`use reqwest::${imports[0]};`);
225
+ }
226
+ }
227
+ for (const imp of Array.from(imports).sort()) {
228
+ preambleLines.push("use " + imp + ";");
229
+ }
230
+
231
+ return [...preambleLines, ...lines].join("\n") + "\n";
232
+ }
233
+ export function toRustWarn(
234
+ curlCommand: string | string[],
235
+ warnings: Warnings = [],
236
+ ): [string, Warnings] {
237
+ const requests = parse(curlCommand, supportedArgs, warnings);
238
+ const rust = _toRust(requests, warnings);
239
+ return [rust, warnings];
240
+ }
241
+ export function toRust(curlCommand: string | string[]): string {
242
+ return toRustWarn(curlCommand)[0];
243
+ }
@@ -0,0 +1,235 @@
1
+ import { Word, eq, mergeWords } from "../shell/Word.js";
2
+ import { parse, getFirst, COMMON_SUPPORTED_ARGS } from "../parse.js";
3
+ import type { Request, Warnings } from "../parse.js";
4
+
5
+ export const supportedArgs = new Set([...COMMON_SUPPORTED_ARGS, "max-time"]);
6
+
7
+ // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/stringsandcharacters/
8
+ const regexEscape = /"|\\|\p{C}|[^ \P{Z}]/gu;
9
+ export function reprStr(s: string): string {
10
+ return (
11
+ '"' +
12
+ s.replace(regexEscape, (c: string): string => {
13
+ switch (c) {
14
+ case "\x00":
15
+ return "\\0";
16
+ case "\\":
17
+ return "\\\\";
18
+ case "\t":
19
+ return "\\t";
20
+ case "\n":
21
+ return "\\n";
22
+ case "\r":
23
+ return "\\r";
24
+ case '"':
25
+ return '\\"';
26
+ }
27
+ const hex = (c.codePointAt(0) as number).toString(16);
28
+ return "\\u{" + hex + "}";
29
+ }) +
30
+ '"'
31
+ );
32
+ }
33
+
34
+ export function repr(w: Word): string {
35
+ const args: string[] = [];
36
+ for (const t of w.tokens) {
37
+ if (typeof t === "string") {
38
+ args.push(reprStr(t));
39
+ } else if (t.type === "variable") {
40
+ args.push(
41
+ "(ProcessInfo.processInfo.environment[" + reprStr(t.value) + '] ?? "")',
42
+ );
43
+ } else {
44
+ args.push("exec(" + reprStr(t.value) + ")");
45
+ // TODO: add exec()
46
+ }
47
+ }
48
+ return args.join(" + ");
49
+ }
50
+
51
+ function reprJson(data: any, indent = 0): string {
52
+ if (typeof data === "string") {
53
+ return reprStr(data);
54
+ } else if (typeof data === "number") {
55
+ return data.toString();
56
+ } else if (typeof data === "boolean") {
57
+ return data ? "true" : "false";
58
+ } else if (data === null) {
59
+ return "nil";
60
+ } else if (Array.isArray(data)) {
61
+ if (data.length === 0) {
62
+ return "[]";
63
+ }
64
+ let code = "[\n";
65
+ for (const item of data) {
66
+ code += " ".repeat(indent + 1) + reprJson(item, indent + 1) + ",\n";
67
+ }
68
+ if (code.endsWith(",\n")) {
69
+ code = code.slice(0, -2) + "\n";
70
+ }
71
+ code += " ".repeat(indent) + "]";
72
+ return code;
73
+ } else if (typeof data === "object") {
74
+ const entries = Object.entries(data);
75
+ if (entries.length === 0) {
76
+ return "[:]";
77
+ }
78
+ let code = "[\n";
79
+ for (const [key, value] of entries) {
80
+ code +=
81
+ " ".repeat(indent + 1) +
82
+ reprStr(key) +
83
+ ": " +
84
+ reprJson(value, indent + 1) +
85
+ ",\n";
86
+ }
87
+ if (code.endsWith(",\n")) {
88
+ code = code.slice(0, -2) + "\n";
89
+ }
90
+ code += " ".repeat(indent) + "]";
91
+ return code;
92
+ } else {
93
+ throw new Error("Unsupported JSON type: " + typeof data);
94
+ }
95
+ }
96
+
97
+ function formatData(request: Request, data: Word): [string, string] {
98
+ const contentType = request.headers.getContentType();
99
+ if (contentType === "application/x-www-form-urlencoded" && data.isString()) {
100
+ const [first, ...rest] = data.split("&");
101
+ let code =
102
+ "let data = NSMutableData(data: " +
103
+ repr(first) +
104
+ ".data(using: .utf8)!)\n";
105
+ for (const part of rest) {
106
+ code +=
107
+ "data.append(" +
108
+ repr(mergeWords("&", part)) +
109
+ ".data(using: .utf8)!)\n";
110
+ }
111
+ return [code, "request.httpBody = data as Data\n"];
112
+ } else if (contentType === "application/json" && data.isString()) {
113
+ const dataStr = data.toString();
114
+ let parsed;
115
+ try {
116
+ parsed = JSON.parse(dataStr);
117
+ const roundtrips = JSON.stringify(parsed) === dataStr;
118
+ // Only convert arrays and {} to Swift types
119
+ if (
120
+ Array.isArray(parsed) ||
121
+ (typeof parsed === "object" && parsed !== null)
122
+ ) {
123
+ let code = "";
124
+ code += "let jsonData = " + reprJson(parsed);
125
+ if (Array.isArray(parsed)) {
126
+ // TODO: narrow type
127
+ code += " as [Any]\n";
128
+ } else {
129
+ code += " as [String : Any]\n";
130
+ }
131
+
132
+ code +=
133
+ "let data = try! JSONSerialization.data(withJSONObject: jsonData, options: [])\n";
134
+ if (!roundtrips) {
135
+ code += "// let data = " + repr(data) + ".data(using: .utf8)\n";
136
+ }
137
+ return [code, "request.httpBody = data as Data\n"];
138
+ }
139
+ } catch {}
140
+ }
141
+ return ["", "request.httpBody = " + repr(data) + ".data(using: .utf8)\n"];
142
+ }
143
+
144
+ export function _toSwift(requests: Request[], warnings: Warnings = []): string {
145
+ const request = getFirst(requests, warnings);
146
+
147
+ let code = "import Foundation\n\n";
148
+
149
+ let dataCode, dataArgCode;
150
+ if (request.data) {
151
+ [dataCode, dataArgCode] = formatData(request, request.data);
152
+ if (dataCode) {
153
+ code += dataCode + "\n";
154
+ }
155
+ }
156
+
157
+ code += "let url = URL(string: " + repr(request.urls[0].url) + ")!\n";
158
+ if (request.urls[0].auth) {
159
+ const [username, password] = request.urls[0].auth;
160
+ code += "\n";
161
+ code += "let username = " + repr(username) + "\n";
162
+ code += "let password = " + repr(password) + "\n";
163
+ code +=
164
+ 'let loginString = String(format: "\\(username):\\(password)", username, password)\n';
165
+ code += "let loginData = loginString.data(using: String.Encoding.utf8)!\n";
166
+ code += "let base64LoginString = loginData.base64EncodedString()\n";
167
+ code += "\n";
168
+ }
169
+ if (request.headers.length || request.urls[0].auth) {
170
+ code += "let headers = [\n";
171
+ for (const [headerName, headerValue] of request.headers) {
172
+ if (headerValue === null) {
173
+ continue;
174
+ }
175
+ code += " " + repr(headerName) + ": " + repr(headerValue) + ",\n";
176
+ }
177
+ if (request.urls[0].auth) {
178
+ const authHeader = request.headers.lowercase
179
+ ? "authorization"
180
+ : "Authorization";
181
+ code += ' "' + authHeader + '": "Basic \\(base64LoginString)",\n';
182
+ }
183
+ if (code.endsWith(",\n")) {
184
+ code = code.slice(0, -2) + "\n";
185
+ }
186
+ code += "]\n";
187
+ }
188
+ code += "\n";
189
+
190
+ code += "var request = URLRequest(url: url";
191
+ if (request.timeout && !eq(request.timeout, "60.0")) {
192
+ // TODO: must be double?
193
+ code += ", timeoutInterval: " + request.timeout.toString();
194
+ }
195
+ code += ")\n";
196
+
197
+ if (!eq(request.urls[0].method, "GET")) {
198
+ code += "request.httpMethod = " + repr(request.urls[0].method) + "\n";
199
+ }
200
+
201
+ if (request.headers.length) {
202
+ code += "request.allHTTPHeaderFields = headers\n";
203
+ }
204
+
205
+ if (dataArgCode) {
206
+ code += dataArgCode;
207
+ }
208
+
209
+ code += "\n";
210
+ code +=
211
+ "let task = URLSession.shared.dataTask(with: request) { (data, response, error) in\n";
212
+ code += " if let error = error {\n";
213
+ code += " print(error)\n";
214
+ code += " } else if let data = data {\n";
215
+ code += " let str = String(data: data, encoding: .utf8)\n";
216
+ code += ' print(str ?? "")\n';
217
+ code += " }\n";
218
+ code += "}\n";
219
+ code += "\n";
220
+ code += "task.resume()\n";
221
+
222
+ return code;
223
+ }
224
+
225
+ export function toSwiftWarn(
226
+ curlCommand: string | string[],
227
+ warnings: Warnings = [],
228
+ ): [string, Warnings] {
229
+ const requests = parse(curlCommand, supportedArgs, warnings);
230
+ const code = _toSwift(requests, warnings);
231
+ return [code, warnings];
232
+ }
233
+ export function toSwift(curlCommand: string | string[]): string {
234
+ return toSwiftWarn(curlCommand)[0];
235
+ }