@scalar/snippetz 0.9.30 → 0.9.31

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 (123) hide show
  1. package/dist/libs/browser-request.d.ts +14 -0
  2. package/dist/libs/browser-request.d.ts.map +1 -0
  3. package/dist/libs/browser-request.js +64 -0
  4. package/dist/libs/http.d.ts.map +1 -1
  5. package/dist/libs/java.d.ts +6 -0
  6. package/dist/libs/java.d.ts.map +1 -0
  7. package/dist/libs/java.js +21 -0
  8. package/dist/libs/julia.d.ts.map +1 -1
  9. package/dist/libs/julia.js +2 -1
  10. package/dist/libs/powershell.d.ts +4 -0
  11. package/dist/libs/powershell.d.ts.map +1 -0
  12. package/dist/libs/powershell.js +38 -0
  13. package/dist/libs/prepare-request.d.ts +21 -0
  14. package/dist/libs/prepare-request.d.ts.map +1 -0
  15. package/dist/libs/prepare-request.js +58 -0
  16. package/dist/plugins/clojure/clj_http/clj_http.d.ts.map +1 -1
  17. package/dist/plugins/clojure/clj_http/clj_http.js +2 -1
  18. package/dist/plugins/csharp/restsharp/restsharp.js +2 -2
  19. package/dist/plugins/dart/http/http.d.ts.map +1 -1
  20. package/dist/plugins/java/asynchttp/asynchttp.d.ts +1 -3
  21. package/dist/plugins/java/asynchttp/asynchttp.d.ts.map +1 -1
  22. package/dist/plugins/java/asynchttp/asynchttp.js +16 -8
  23. package/dist/plugins/java/nethttp/nethttp.d.ts +1 -3
  24. package/dist/plugins/java/nethttp/nethttp.d.ts.map +1 -1
  25. package/dist/plugins/java/nethttp/nethttp.js +17 -8
  26. package/dist/plugins/java/okhttp/okhttp.d.ts +1 -3
  27. package/dist/plugins/java/okhttp/okhttp.d.ts.map +1 -1
  28. package/dist/plugins/java/okhttp/okhttp.js +50 -8
  29. package/dist/plugins/java/unirest/unirest.d.ts +1 -3
  30. package/dist/plugins/java/unirest/unirest.d.ts.map +1 -1
  31. package/dist/plugins/java/unirest/unirest.js +13 -8
  32. package/dist/plugins/js/jquery/jquery.d.ts +1 -3
  33. package/dist/plugins/js/jquery/jquery.d.ts.map +1 -1
  34. package/dist/plugins/js/jquery/jquery.js +22 -8
  35. package/dist/plugins/js/xhr/xhr.d.ts +1 -3
  36. package/dist/plugins/js/xhr/xhr.d.ts.map +1 -1
  37. package/dist/plugins/js/xhr/xhr.js +13 -8
  38. package/dist/plugins/kotlin/okhttp/okhttp.d.ts.map +1 -1
  39. package/dist/plugins/kotlin/okhttp/okhttp.js +15 -9
  40. package/dist/plugins/ocaml/cohttp/cohttp.d.ts +1 -3
  41. package/dist/plugins/ocaml/cohttp/cohttp.d.ts.map +1 -1
  42. package/dist/plugins/ocaml/cohttp/cohttp.js +32 -8
  43. package/dist/plugins/php/laravel/laravel.d.ts.map +1 -1
  44. package/dist/plugins/php/laravel/laravel.js +2 -1
  45. package/dist/plugins/powershell/restmethod/restmethod.d.ts +1 -3
  46. package/dist/plugins/powershell/restmethod/restmethod.d.ts.map +1 -1
  47. package/dist/plugins/powershell/restmethod/restmethod.js +4 -8
  48. package/dist/plugins/powershell/webrequest/webrequest.d.ts +1 -3
  49. package/dist/plugins/powershell/webrequest/webrequest.d.ts.map +1 -1
  50. package/dist/plugins/powershell/webrequest/webrequest.js +4 -8
  51. package/dist/plugins/python/requestsLike.d.ts.map +1 -1
  52. package/dist/plugins/r/httr2/httr2.d.ts.map +1 -1
  53. package/dist/plugins/r/httr2/httr2.js +2 -1
  54. package/dist/plugins/shared/axios.d.ts.map +1 -1
  55. package/dist/plugins/shell/curl/curl.d.ts.map +1 -1
  56. package/dist/plugins/shell/curl/curl.js +12 -1
  57. package/dist/plugins/shell/httpie/httpie.d.ts +1 -3
  58. package/dist/plugins/shell/httpie/httpie.d.ts.map +1 -1
  59. package/dist/plugins/shell/httpie/httpie.js +34 -8
  60. package/package.json +3 -10
  61. package/dist/httpsnippet-lite/helpers/code-builder.d.ts +0 -51
  62. package/dist/httpsnippet-lite/helpers/code-builder.d.ts.map +0 -1
  63. package/dist/httpsnippet-lite/helpers/code-builder.js +0 -87
  64. package/dist/httpsnippet-lite/helpers/escape.d.ts +0 -48
  65. package/dist/httpsnippet-lite/helpers/escape.d.ts.map +0 -1
  66. package/dist/httpsnippet-lite/helpers/escape.js +0 -70
  67. package/dist/httpsnippet-lite/helpers/headers.d.ts +0 -15
  68. package/dist/httpsnippet-lite/helpers/headers.d.ts.map +0 -1
  69. package/dist/httpsnippet-lite/helpers/headers.js +0 -18
  70. package/dist/httpsnippet-lite/helpers/reducer.d.ts +0 -2
  71. package/dist/httpsnippet-lite/helpers/reducer.d.ts.map +0 -1
  72. package/dist/httpsnippet-lite/helpers/reducer.js +0 -1
  73. package/dist/httpsnippet-lite/helpers/shell.d.ts +0 -6
  74. package/dist/httpsnippet-lite/helpers/shell.d.ts.map +0 -1
  75. package/dist/httpsnippet-lite/helpers/shell.js +0 -13
  76. package/dist/httpsnippet-lite/helpers/snippet-request.d.ts +0 -33
  77. package/dist/httpsnippet-lite/helpers/snippet-request.d.ts.map +0 -1
  78. package/dist/httpsnippet-lite/helpers/snippet-request.js +0 -1
  79. package/dist/httpsnippet-lite/helpers/url.d.ts +0 -4
  80. package/dist/httpsnippet-lite/helpers/url.d.ts.map +0 -1
  81. package/dist/httpsnippet-lite/helpers/url.js +0 -5
  82. package/dist/httpsnippet-lite/targets/java/asynchttp/client.d.ts +0 -12
  83. package/dist/httpsnippet-lite/targets/java/asynchttp/client.d.ts.map +0 -1
  84. package/dist/httpsnippet-lite/targets/java/asynchttp/client.js +0 -33
  85. package/dist/httpsnippet-lite/targets/java/nethttp/client.d.ts +0 -3
  86. package/dist/httpsnippet-lite/targets/java/nethttp/client.d.ts.map +0 -1
  87. package/dist/httpsnippet-lite/targets/java/nethttp/client.js +0 -41
  88. package/dist/httpsnippet-lite/targets/java/okhttp/client.d.ts +0 -12
  89. package/dist/httpsnippet-lite/targets/java/okhttp/client.d.ts.map +0 -1
  90. package/dist/httpsnippet-lite/targets/java/okhttp/client.js +0 -87
  91. package/dist/httpsnippet-lite/targets/java/unirest/client.d.ts +0 -12
  92. package/dist/httpsnippet-lite/targets/java/unirest/client.d.ts.map +0 -1
  93. package/dist/httpsnippet-lite/targets/java/unirest/client.js +0 -42
  94. package/dist/httpsnippet-lite/targets/javascript/jquery/client.d.ts +0 -3
  95. package/dist/httpsnippet-lite/targets/javascript/jquery/client.d.ts.map +0 -1
  96. package/dist/httpsnippet-lite/targets/javascript/jquery/client.js +0 -80
  97. package/dist/httpsnippet-lite/targets/javascript/xhr/client.d.ts +0 -3
  98. package/dist/httpsnippet-lite/targets/javascript/xhr/client.d.ts.map +0 -1
  99. package/dist/httpsnippet-lite/targets/javascript/xhr/client.js +0 -78
  100. package/dist/httpsnippet-lite/targets/ocaml/cohttp/client.d.ts +0 -3
  101. package/dist/httpsnippet-lite/targets/ocaml/cohttp/client.d.ts.map +0 -1
  102. package/dist/httpsnippet-lite/targets/ocaml/cohttp/client.js +0 -61
  103. package/dist/httpsnippet-lite/targets/powershell/common.d.ts +0 -3
  104. package/dist/httpsnippet-lite/targets/powershell/common.d.ts.map +0 -1
  105. package/dist/httpsnippet-lite/targets/powershell/common.js +0 -48
  106. package/dist/httpsnippet-lite/targets/powershell/restmethod/client.d.ts +0 -3
  107. package/dist/httpsnippet-lite/targets/powershell/restmethod/client.d.ts.map +0 -1
  108. package/dist/httpsnippet-lite/targets/powershell/restmethod/client.js +0 -10
  109. package/dist/httpsnippet-lite/targets/powershell/webrequest/client.d.ts +0 -3
  110. package/dist/httpsnippet-lite/targets/powershell/webrequest/client.d.ts.map +0 -1
  111. package/dist/httpsnippet-lite/targets/powershell/webrequest/client.js +0 -10
  112. package/dist/httpsnippet-lite/targets/shell/httpie/client.d.ts +0 -12
  113. package/dist/httpsnippet-lite/targets/shell/httpie/client.d.ts.map +0 -1
  114. package/dist/httpsnippet-lite/targets/shell/httpie/client.js +0 -124
  115. package/dist/httpsnippet-lite/targets/target.d.ts +0 -19
  116. package/dist/httpsnippet-lite/targets/target.d.ts.map +0 -1
  117. package/dist/httpsnippet-lite/targets/target.js +0 -1
  118. package/dist/utils/convertWithHttpSnippetLite.d.ts +0 -8
  119. package/dist/utils/convertWithHttpSnippetLite.d.ts.map +0 -1
  120. package/dist/utils/convertWithHttpSnippetLite.js +0 -102
  121. package/dist/utils/index.d.ts +0 -2
  122. package/dist/utils/index.d.ts.map +0 -1
  123. package/dist/utils/index.js +0 -1
@@ -1,14 +1,19 @@
1
- import { xhr } from '../../../httpsnippet-lite/targets/javascript/xhr/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
- /**
4
- * js/xhr
5
- */
1
+ import { prepareBrowserRequest } from '../../../libs/browser-request.js';
2
+ /** Generates a request using the browser XMLHttpRequest API. */
6
3
  export const jsXhr = {
7
4
  target: 'js',
8
5
  client: 'xhr',
9
6
  title: 'XHR',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(xhr, request);
7
+ generate(request, configuration) {
8
+ const { url, method, headers, setup, body } = prepareBrowserRequest(request, configuration);
9
+ return [
10
+ ...setup,
11
+ 'const xhr = new XMLHttpRequest();',
12
+ `xhr.open(${JSON.stringify(method)}, ${JSON.stringify(url)});`,
13
+ 'xhr.withCredentials = true;',
14
+ ...headers.map(({ name, value }) => `xhr.setRequestHeader(${JSON.stringify(name)}, ${JSON.stringify(value)});`),
15
+ 'xhr.addEventListener("load", () => console.log(xhr.responseText));',
16
+ `xhr.send(${body});`,
17
+ ].join('\n');
13
18
  },
14
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"okhttp.d.ts","sourceRoot":"","sources":["../../../../src/plugins/kotlin/okhttp/okhttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAcpD;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAqE1B,CAAA"}
1
+ {"version":3,"file":"okhttp.d.ts","sourceRoot":"","sources":["../../../../src/plugins/kotlin/okhttp/okhttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAapD;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MA2E1B,CAAA"}
@@ -1,11 +1,10 @@
1
- import { escapeForDoubleQuotes } from '../../../httpsnippet-lite/helpers/escape.js';
2
1
  import { collectHeaders, joinUrlAndQuery, normalizeMethod, normalizeUrl } from '../../../libs/http.js';
3
2
  /** Methods OkHttp exposes as dedicated builder calls (anything else uses `.method(...)`). */
4
3
  const METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'];
5
4
  /** Methods that accept a request body through their dedicated builder call. */
6
5
  const METHODS_WITH_BODY = ['POST', 'PUT', 'DELETE', 'PATCH'];
7
6
  /** Wrap a value in double quotes, escaping anything that would break the Kotlin string. */
8
- const quote = (value) => `"${escapeForDoubleQuotes(value)}"`;
7
+ const quote = (value) => JSON.stringify(value).replaceAll('$', '\\$');
9
8
  /**
10
9
  * kotlin/okhttp
11
10
  */
@@ -24,7 +23,7 @@ export const kotlinOkhttp = {
24
23
  if (postData?.mimeType === 'application/x-www-form-urlencoded' && postData.params) {
25
24
  lines.push('val body = FormBody.Builder()');
26
25
  postData.params.forEach((param) => {
27
- lines.push(` .addEncoded(${quote(param.name ?? '')}, ${quote(param.value ?? '')})`);
26
+ lines.push(` .add(${quote(param.name ?? '')}, ${quote(param.value ?? '')})`);
28
27
  });
29
28
  lines.push(' .build()', '');
30
29
  hasBody = true;
@@ -33,10 +32,13 @@ export const kotlinOkhttp = {
33
32
  lines.push('val body = MultipartBody.Builder()', ' .setType(MultipartBody.FORM)');
34
33
  postData.params.forEach((param) => {
35
34
  if (param.fileName !== undefined) {
36
- lines.push(` .addFormDataPart(${quote(param.name ?? '')}, ${quote(param.fileName)}, RequestBody.create(MediaType.parse("application/octet-stream"), File(${quote(param.fileName)})))`);
35
+ lines.push(` .addFormDataPart(${quote(param.name ?? '')}, ${quote(param.fileName)}, RequestBody.create(MediaType.parse(${quote(param.contentType ?? 'application/octet-stream')}), File(${quote(param.fileName)})))`);
37
36
  }
38
- else if (param.value !== undefined) {
39
- lines.push(` .addFormDataPart(${quote(param.name ?? '')}, ${quote(param.value)})`);
37
+ else if (param.contentType) {
38
+ lines.push(` .addFormDataPart(${quote(param.name)}, null, RequestBody.create(MediaType.parse(${quote(param.contentType)}), ${quote(param.value ?? '')}))`);
39
+ }
40
+ else {
41
+ lines.push(` .addFormDataPart(${quote(param.name)}, ${quote(param.value ?? '')})`);
40
42
  }
41
43
  });
42
44
  lines.push(' .build()', '');
@@ -44,13 +46,16 @@ export const kotlinOkhttp = {
44
46
  }
45
47
  else if (postData) {
46
48
  lines.push(`val mediaType = MediaType.parse(${quote(postData.mimeType ?? '')})`);
47
- lines.push(`val body = RequestBody.create(mediaType, ${JSON.stringify(postData.text ?? '')})`);
49
+ lines.push(`val body = RequestBody.create(mediaType, ${quote(postData.text ?? '')})`);
48
50
  hasBody = true;
49
51
  }
50
52
  // Request builder
51
53
  lines.push('val request = Request.Builder()', ` .url(${quote(url)})`);
52
54
  // Method, mirroring OkHttp's dedicated builder calls and the generic `.method(...)` fallback
53
- const bodyArg = hasBody ? 'body' : 'null';
55
+ const emptyBody = ['POST', 'PUT', 'PATCH', 'PROPPATCH', 'REPORT'].includes(method)
56
+ ? 'RequestBody.create(null, "")'
57
+ : 'null';
58
+ const bodyArg = hasBody ? 'body' : emptyBody;
54
59
  if (!METHODS.includes(method)) {
55
60
  lines.push(` .method(${quote(method)}, ${bodyArg})`);
56
61
  }
@@ -65,7 +70,8 @@ export const kotlinOkhttp = {
65
70
  lines.push(` .addHeader("Authorization", Credentials.basic(${quote(configuration.auth.username)}, ${quote(configuration.auth.password)}))`);
66
71
  }
67
72
  // Headers, including cookies folded into a single Cookie header
68
- collectHeaders(request?.headers, request?.cookies).forEach((header) => {
73
+ ;
74
+ [...(request?.headers ?? []), ...collectHeaders([], request?.cookies)].forEach((header) => {
69
75
  lines.push(` .addHeader(${quote(header.name)}, ${quote(header.value)})`);
70
76
  });
71
77
  lines.push(' .build()', '', 'val response = client.newCall(request).execute()');
@@ -1,6 +1,4 @@
1
1
  import type { Plugin } from '@scalar/types/snippetz';
2
- /**
3
- * ocaml/cohttp
4
- */
2
+ /** Generates a complete Lwt request, preserving binary file contents in multipart bodies. */
5
3
  export declare const ocamlCohttp: Plugin;
6
4
  //# sourceMappingURL=cohttp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cohttp.d.ts","sourceRoot":"","sources":["../../../../src/plugins/ocaml/cohttp/cohttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAKpD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAQzB,CAAA"}
1
+ {"version":3,"file":"cohttp.d.ts","sourceRoot":"","sources":["../../../../src/plugins/ocaml/cohttp/cohttp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAcpD,6FAA6F;AAC7F,eAAO,MAAM,WAAW,EAAE,MAoCzB,CAAA"}
@@ -1,14 +1,38 @@
1
- import { cohttp } from '../../../httpsnippet-lite/targets/ocaml/cohttp/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
- /**
4
- * ocaml/cohttp
5
- */
1
+ import { prepareRequest } from '../../../libs/prepare-request.js';
2
+ /** OCaml uses three-digit decimal escapes for control bytes. */
3
+ const quote = (value) => `"${Array.from(value, (character) => {
4
+ if (character === '\\' || character === '"') {
5
+ return `\\${character}`;
6
+ }
7
+ const code = character.charCodeAt(0);
8
+ return code < 32 || code === 127 ? `\\${code.toString().padStart(3, '0')}` : character;
9
+ }).join('')}"`;
10
+ /** Generates a complete Lwt request, preserving binary file contents in multipart bodies. */
6
11
  export const ocamlCohttp = {
7
12
  target: 'ocaml',
8
13
  client: 'cohttp',
9
14
  title: 'Cohttp',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(cohttp, request);
15
+ generate(request, configuration) {
16
+ const { url, method, headers, body } = prepareRequest(request, configuration);
17
+ const lines = [
18
+ 'open Lwt.Infix',
19
+ '',
20
+ 'let () =',
21
+ ' Lwt_main.run (',
22
+ ` let uri = Uri.of_string ${quote(url)} in`,
23
+ ' let headers = Cohttp.Header.of_list [',
24
+ ...headers.map(({ name, value }) => ` (${quote(name)}, ${quote(value)});`),
25
+ ' ] in',
26
+ ];
27
+ if (body) {
28
+ for (const [index, segment] of body.entries()) {
29
+ lines.push('file' in segment
30
+ ? ` Lwt_io.with_file ~mode:Lwt_io.Input ${quote(segment.file)} Lwt_io.read >>= fun part${index} ->`
31
+ : ` let part${index} = ${quote(segment.text)} in`);
32
+ }
33
+ lines.push(` let body = Cohttp_lwt.Body.of_string (String.concat "" [${body.map((_, index) => `part${index}`).join('; ')}]) in`);
34
+ }
35
+ lines.push(` Cohttp_lwt_unix.Client.call ~headers ${body ? '~body ' : ''}(Cohttp.Code.method_of_string ${quote(method)}) uri`, ' >>= fun (_response, body) ->', ' Cohttp_lwt.Body.to_string body >>= Lwt_io.printl', ' )');
36
+ return lines.join('\n');
13
37
  },
14
38
  };
@@ -1 +1 @@
1
- {"version":3,"file":"laravel.d.ts","sourceRoot":"","sources":["../../../../src/plugins/php/laravel/laravel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAyCpD;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAiIxB,CAAA"}
1
+ {"version":3,"file":"laravel.d.ts","sourceRoot":"","sources":["../../../../src/plugins/php/laravel/laravel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAsCpD;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAiIxB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { isObjectLike } from '@scalar/helpers/object/is-object';
1
2
  import { accumulateRepeatedValue, buildQueryString } from '../../../libs/http.js';
2
3
  import { objectToString } from '../../../libs/php.js';
3
4
  const escapePhpString = (value) => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
@@ -7,7 +8,7 @@ const escapeObjectKeys = (value) => {
7
8
  if (Array.isArray(value)) {
8
9
  return value.map((item) => escapeObjectKeys(item));
9
10
  }
10
- if (value && typeof value === 'object') {
11
+ if (isObjectLike(value)) {
11
12
  return Object.entries(value).reduce((acc, [key, nestedValue]) => {
12
13
  acc[escapePhpObjectKey(key)] = escapeObjectKeys(nestedValue);
13
14
  return acc;
@@ -1,6 +1,4 @@
1
1
  import type { Plugin } from '@scalar/types/snippetz';
2
- /**
3
- * powershell/restmethod
4
- */
2
+ /** Generates a PowerShell 7 request using Invoke-RestMethod. */
5
3
  export declare const powershellRestmethod: Plugin;
6
4
  //# sourceMappingURL=restmethod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"restmethod.d.ts","sourceRoot":"","sources":["../../../../src/plugins/powershell/restmethod/restmethod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAKpD;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAQlC,CAAA"}
1
+ {"version":3,"file":"restmethod.d.ts","sourceRoot":"","sources":["../../../../src/plugins/powershell/restmethod/restmethod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,MAOlC,CAAA"}
@@ -1,14 +1,10 @@
1
- import { restmethod } from '../../../httpsnippet-lite/targets/powershell/restmethod/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
- /**
4
- * powershell/restmethod
5
- */
1
+ import { generatePowershell } from '../../../libs/powershell.js';
2
+ /** Generates a PowerShell 7 request using Invoke-RestMethod. */
6
3
  export const powershellRestmethod = {
7
4
  target: 'powershell',
8
5
  client: 'restmethod',
9
6
  title: 'Invoke-RestMethod',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(restmethod, request);
7
+ generate(request, configuration) {
8
+ return generatePowershell('Invoke-RestMethod', request, configuration);
13
9
  },
14
10
  };
@@ -1,6 +1,4 @@
1
1
  import type { Plugin } from '@scalar/types/snippetz';
2
- /**
3
- * powershell/webrequest
4
- */
2
+ /** Generates a PowerShell 7 request using Invoke-WebRequest. */
5
3
  export declare const powershellWebrequest: Plugin;
6
4
  //# sourceMappingURL=webrequest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webrequest.d.ts","sourceRoot":"","sources":["../../../../src/plugins/powershell/webrequest/webrequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAKpD;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAQlC,CAAA"}
1
+ {"version":3,"file":"webrequest.d.ts","sourceRoot":"","sources":["../../../../src/plugins/powershell/webrequest/webrequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,MAOlC,CAAA"}
@@ -1,14 +1,10 @@
1
- import { webrequest } from '../../../httpsnippet-lite/targets/powershell/webrequest/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
- /**
4
- * powershell/webrequest
5
- */
1
+ import { generatePowershell } from '../../../libs/powershell.js';
2
+ /** Generates a PowerShell 7 request using Invoke-WebRequest. */
6
3
  export const powershellWebrequest = {
7
4
  target: 'powershell',
8
5
  client: 'webrequest',
9
6
  title: 'Invoke-WebRequest',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(webrequest, request);
7
+ generate(request, configuration) {
8
+ return generatePowershell('Invoke-WebRequest', request, configuration);
13
9
  },
14
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"requestsLike.d.ts","sourceRoot":"","sources":["../../../src/plugins/python/requestsLike.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAI7E,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAsB5C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,SAAI,GAAG,MAAM,CAOzE;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAC7B,aAAa,CAAC,EAAE,mBAAmB,UAiJpC"}
1
+ {"version":3,"file":"requestsLike.d.ts","sourceRoot":"","sources":["../../../src/plugins/python/requestsLike.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAI7E,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAsB5C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,SAAI,GAAG,MAAM,CAOzE;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,EAC7B,aAAa,CAAC,EAAE,mBAAmB,UA8IpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"httr2.d.ts","sourceRoot":"","sources":["../../../../src/plugins/r/httr2/httr2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,MAAM,EAAuB,MAAM,wBAAwB,CAAA;AAkDrF;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAuHpB,CAAA"}
1
+ {"version":3,"file":"httr2.d.ts","sourceRoot":"","sources":["../../../../src/plugins/r/httr2/httr2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,MAAM,EAAuB,MAAM,wBAAwB,CAAA;AAkDrF;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAuHpB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { isObjectLike } from '@scalar/helpers/object/is-object';
1
2
  import { reduceQueryParams } from '../../../libs/http.js';
2
3
  /**
3
4
  * Formats JSON text as an R list structure
@@ -34,7 +35,7 @@ const formatRValue = (value, indent) => {
34
35
  const items = value.map((v) => `${indent} ${formatRValue(v, indent + ' ')}`).join(',\n');
35
36
  return `list(\n${items}\n${indent})`;
36
37
  }
37
- if (typeof value === 'object') {
38
+ if (isObjectLike(value)) {
38
39
  const entries = Object.entries(value);
39
40
  if (entries.length === 0) {
40
41
  return 'list()';
@@ -1 +1 @@
1
- {"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../../../src/plugins/shared/axios.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AA4I9D,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM,CAAC,EAAE,QAAQ,CAAC,KAAG,MAmDxF,CAAA"}
1
+ {"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../../../src/plugins/shared/axios.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAwI9D,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM,CAAC,EAAE,QAAQ,CAAC,KAAG,MAmDxF,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/curl/curl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAiBpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAiJvB,CAAA"}
1
+ {"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/curl/curl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAiBpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MA6JvB,CAAA"}
@@ -36,7 +36,8 @@ export const shellCurl = {
36
36
  ? separator +
37
37
  normalizedRequest.queryString
38
38
  .map((param) => {
39
- // Ensure both name and value are fully URI encoded
39
+ // Keep the name and value raw so the snippet still reads like the documented endpoint; curl's own
40
+ // glob parser is handled with `--globoff` below rather than by percent-encoding the URL
40
41
  return `${param.name}=${param.value}`;
41
42
  })
42
43
  .join('&')
@@ -46,6 +47,16 @@ export const shellCurl = {
46
47
  const isShellSafe = /^[A-Za-z0-9._~:/%@+,=-]*$/.test(url);
47
48
  const urlPart = isShellSafe ? url : `'${escapeSingleQuotes(url)}'`;
48
49
  parts[0] = `curl ${urlPart}`;
50
+ // curl reads `[]` (ranges) and `{}` (sets) in a URL as its own globbing syntax, no matter how the shell
51
+ // quotes them. Square brackets always break curl (`filter[id]=1` throws "bad range"), so disable globbing
52
+ // whenever they appear. Curly braces in the path are almost always placeholders like `/users/{id}` that you
53
+ // replace before running, so we leave those to avoid adding the flag to nearly every snippet — but braces in
54
+ // the query string are real glob sets (`?ids={1,2,3}` fans out into three requests), so disable it there.
55
+ const queryStart = url.indexOf('?');
56
+ const queryPart = queryStart === -1 ? '' : url.slice(queryStart);
57
+ if (/[[\]]/.test(url) || /[{}]/.test(queryPart)) {
58
+ parts.push('--globoff');
59
+ }
49
60
  // Method
50
61
  if (normalizedRequest.method !== 'GET') {
51
62
  parts.push(`--request ${normalizedRequest.method}`);
@@ -1,6 +1,4 @@
1
1
  import type { Plugin } from '@scalar/types/snippetz';
2
- /**
3
- * shell/httpie
4
- */
2
+ /** Generates an HTTPie command, streaming multipart files without shell interpolation. */
5
3
  export declare const shellHttpie: Plugin;
6
4
  //# sourceMappingURL=httpie.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"httpie.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/httpie/httpie.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAKpD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAQzB,CAAA"}
1
+ {"version":3,"file":"httpie.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/httpie/httpie.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAOpD,0FAA0F;AAC1F,eAAO,MAAM,WAAW,EAAE,MAoCzB,CAAA"}
@@ -1,14 +1,40 @@
1
- import { httpie } from '../../../httpsnippet-lite/targets/shell/httpie/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
- /**
4
- * shell/httpie
5
- */
1
+ import { prepareRequest } from '../../../libs/prepare-request.js';
2
+ import { escapeSingleQuotes } from '../../../libs/shell.js';
3
+ const quote = (value) => `'${escapeSingleQuotes(value)}'`;
4
+ /** Generates an HTTPie command, streaming multipart files without shell interpolation. */
6
5
  export const shellHttpie = {
7
6
  target: 'shell',
8
7
  client: 'httpie',
9
8
  title: 'HTTPie',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(httpie, request);
9
+ generate(request, configuration) {
10
+ const { url, method, headers, body } = prepareRequest(request, configuration);
11
+ const rawBody = body?.length === 1 && body[0] && 'text' in body[0] && !body[0].text.includes('\0') ? body[0].text : undefined;
12
+ const parts = [`http${!body || rawBody !== undefined ? ' --ignore-stdin' : ''} ${quote(method)} ${quote(url)}`];
13
+ for (const { name, value } of headers) {
14
+ // HTTPie uses a semicolon for an explicitly empty header; a colon unsets it.
15
+ const escapedName = name.replaceAll('\\', '\\\\').replaceAll(':', '\\:').replaceAll(';', '\\;');
16
+ parts.push(quote(value ? `${escapedName}:${value}` : `${escapedName};`));
17
+ }
18
+ const command = parts.join(' \\\n ');
19
+ if (!body) {
20
+ return command;
21
+ }
22
+ if (rawBody !== undefined) {
23
+ return `${command} \\\n --raw=${quote(rawBody)}`;
24
+ }
25
+ const input = body.map((segment) => {
26
+ if ('file' in segment) {
27
+ return ` cat -- ${quote(segment.file)}`;
28
+ }
29
+ const text = Array.from(segment.text, (character) => {
30
+ if (character === '\\') {
31
+ return '\\\\';
32
+ }
33
+ const code = character.charCodeAt(0);
34
+ return code < 32 ? `\\0${code.toString(8).padStart(3, '0')}` : character;
35
+ }).join('');
36
+ return ` printf '%b' ${quote(text)}`;
37
+ });
38
+ return ['{', ...input, `} | ${command}`].join('\n');
13
39
  },
14
40
  };
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "url": "git+https://github.com/scalar/scalar.git",
10
10
  "directory": "packages/snippetz"
11
11
  },
12
- "version": "0.9.30",
12
+ "version": "0.9.31",
13
13
  "engines": {
14
14
  "node": ">=22"
15
15
  },
@@ -231,11 +231,6 @@
231
231
  "import": "./dist/plugins/swift/nsurlsession/index.js",
232
232
  "types": "./dist/plugins/swift/nsurlsession/index.d.ts",
233
233
  "default": "./dist/plugins/swift/nsurlsession/index.js"
234
- },
235
- "./utils": {
236
- "import": "./dist/utils/index.js",
237
- "types": "./dist/utils/index.d.ts",
238
- "default": "./dist/utils/index.js"
239
234
  }
240
235
  },
241
236
  "files": [
@@ -244,12 +239,10 @@
244
239
  ],
245
240
  "dependencies": {
246
241
  "js-base64": "^3.9.2",
247
- "stringify-object": "^6.0.0",
248
- "@scalar/helpers": "0.11.3",
249
- "@scalar/types": "0.19.0"
242
+ "@scalar/helpers": "0.12.0",
243
+ "@scalar/types": "0.20.0"
250
244
  },
251
245
  "devDependencies": {
252
- "@types/stringify-object": "^4.0.5",
253
246
  "vite": "8.1.5"
254
247
  },
255
248
  "scripts": {
@@ -1,51 +0,0 @@
1
- type PostProcessor = (unreplacedCode: string) => string;
2
- export type CodeBuilderOptions = {
3
- /**
4
- * Desired indentation character for aggregated lines of code
5
- * @default ''
6
- */
7
- indent?: string;
8
- /**
9
- * Desired character to join each line of code
10
- * @default \n
11
- */
12
- join?: string;
13
- };
14
- export declare class CodeBuilder {
15
- postProcessors: PostProcessor[];
16
- code: string[];
17
- indentationCharacter: string;
18
- lineJoin: string;
19
- /**
20
- * Add given indentation level to given line of code
21
- */
22
- indentLine: (line: string, indentationLevel?: number) => string;
23
- /**
24
- * Add the line at the beginning of the current lines
25
- */
26
- unshift: (line: string, indentationLevel?: number) => void;
27
- /**
28
- * Add the line at the end of the current lines
29
- */
30
- push: (line: string, indentationLevel?: number) => void;
31
- /**
32
- * Add an empty line at the end of current lines
33
- */
34
- blank: () => void;
35
- /**
36
- * Concatenate all current lines using the given lineJoin, then apply any replacers that may have been added
37
- */
38
- join: () => string;
39
- /**
40
- * Often when writing modules you may wish to add a literal tag or bit of metadata that you wish to transform after other processing as a final step.
41
- * To do so, you can provide a PostProcessor function and it will be run automatically for you when you call `join()` later on.
42
- */
43
- addPostProcessor: (postProcessor: PostProcessor) => void;
44
- /**
45
- * Helper object to format and aggragate lines of code.
46
- * Lines are aggregated in a `code` array, and need to be joined to obtain a proper code snippet.
47
- */
48
- constructor({ indent, join }?: CodeBuilderOptions);
49
- }
50
- export {};
51
- //# sourceMappingURL=code-builder.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-builder.d.ts","sourceRoot":"","sources":["../../../src/httpsnippet-lite/helpers/code-builder.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG,CAAC,cAAc,EAAE,MAAM,KAAK,MAAM,CAAA;AAEvD,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAKD,qBAAa,WAAW;IACtB,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,oBAAoB,EAAE,MAAM,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC/D;;OAEG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1D;;OAEG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACvD;;OAEG;IACH,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB;;OAEG;IACH,IAAI,EAAE,MAAM,MAAM,CAAA;IAClB;;;OAGG;IACH,gBAAgB,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAA;IAExD;;;OAGG;gBACS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAE,kBAAuB;CAsDtD"}
@@ -1,87 +0,0 @@
1
- const DEFAULT_INDENTATION_CHARACTER = '';
2
- const DEFAULT_LINE_JOIN = '\n';
3
- export class CodeBuilder {
4
- postProcessors;
5
- code;
6
- indentationCharacter;
7
- lineJoin;
8
- /**
9
- * Add given indentation level to given line of code
10
- */
11
- indentLine;
12
- /**
13
- * Add the line at the beginning of the current lines
14
- */
15
- unshift;
16
- /**
17
- * Add the line at the end of the current lines
18
- */
19
- push;
20
- /**
21
- * Add an empty line at the end of current lines
22
- */
23
- blank;
24
- /**
25
- * Concatenate all current lines using the given lineJoin, then apply any replacers that may have been added
26
- */
27
- join;
28
- /**
29
- * Often when writing modules you may wish to add a literal tag or bit of metadata that you wish to transform after other processing as a final step.
30
- * To do so, you can provide a PostProcessor function and it will be run automatically for you when you call `join()` later on.
31
- */
32
- addPostProcessor;
33
- /**
34
- * Helper object to format and aggragate lines of code.
35
- * Lines are aggregated in a `code` array, and need to be joined to obtain a proper code snippet.
36
- */
37
- constructor({ indent, join } = {}) {
38
- this.postProcessors = [];
39
- this.code = [];
40
- this.indentationCharacter = DEFAULT_INDENTATION_CHARACTER;
41
- this.lineJoin = DEFAULT_LINE_JOIN;
42
- /**
43
- * Add given indentation level to given line of code
44
- */
45
- this.indentLine = (line, indentationLevel = 0) => {
46
- const whitespace = this.indentationCharacter.repeat(indentationLevel);
47
- return `${whitespace}${line}`;
48
- };
49
- /**
50
- * Add the line at the beginning of the current lines
51
- */
52
- this.unshift = (line, indentationLevel) => {
53
- const newLine = this.indentLine(line, indentationLevel);
54
- this.code.unshift(newLine);
55
- };
56
- /**
57
- * Add the line at the end of the current lines
58
- */
59
- this.push = (line, indentationLevel) => {
60
- const newLine = this.indentLine(line, indentationLevel);
61
- this.code.push(newLine);
62
- };
63
- /**
64
- * Add an empty line at the end of current lines
65
- */
66
- this.blank = () => {
67
- this.code.push('');
68
- };
69
- /**
70
- * Concatenate all current lines using the given lineJoin, then apply any replacers that may have been added
71
- */
72
- this.join = () => {
73
- const unreplacedCode = this.code.join(this.lineJoin);
74
- const replacedOutput = this.postProcessors.reduce((accumulator, replacer) => replacer(accumulator), unreplacedCode);
75
- return replacedOutput;
76
- };
77
- /**
78
- * Often when writing modules you may wish to add a literal tag or bit of metadata that you wish to transform after other processing as a final step.
79
- * To do so, you can provide a PostProcessor function and it will be run automatically for you when you call `join()` later on.
80
- */
81
- this.addPostProcessor = (postProcessor) => {
82
- this.postProcessors = [...this.postProcessors, postProcessor];
83
- };
84
- this.indentationCharacter = indent || DEFAULT_INDENTATION_CHARACTER;
85
- this.lineJoin = join !== null && join !== void 0 ? join : DEFAULT_LINE_JOIN;
86
- }
87
- }
@@ -1,48 +0,0 @@
1
- type EscapeOptions = {
2
- /**
3
- * The delimiter that will be used to wrap the string (and so must be escaped
4
- * when used within the string).
5
- * Defaults to "
6
- */
7
- delimiter?: string;
8
- /**
9
- * The char to use to escape the delimiter and other special characters.
10
- * Defaults to \
11
- */
12
- escapeChar?: string;
13
- /**
14
- * Whether newlines (\n and \r) should be escaped within the string.
15
- * Defaults to true.
16
- */
17
- escapeNewlines?: boolean;
18
- };
19
- /**
20
- * Escape characters within a value to make it safe to insert directly into a
21
- * snippet. Takes options which define the escape requirements.
22
- *
23
- * This is closely based on the JSON-stringify string serialization algorithm,
24
- * but generalized for other string delimiters (e.g. " or ') and different escape
25
- * characters (e.g. Powershell uses `)
26
- *
27
- * See https://tc39.es/ecma262/multipage/structured-data.html#sec-quotejsonstring
28
- * for the complete original algorithm.
29
- */
30
- export declare function escapeString(rawValue: string, options?: EscapeOptions): string;
31
- /**
32
- * Make a string value safe to insert literally into a snippet within single quotes,
33
- * by escaping problematic characters, including single quotes inside the string,
34
- * backslashes, newlines, and other special characters.
35
- *
36
- * If value is not a string, it will be stringified with .toString() first.
37
- */
38
- export declare const escapeForSingleQuotes: (value: string) => string;
39
- /**
40
- * Make a string value safe to insert literally into a snippet within double quotes,
41
- * by escaping problematic characters, including double quotes inside the string,
42
- * backslashes, newlines, and other special characters.
43
- *
44
- * If value is not a string, it will be stringified with .toString() first.
45
- */
46
- export declare const escapeForDoubleQuotes: (value: string) => string;
47
- export {};
48
- //# sourceMappingURL=escape.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../../src/httpsnippet-lite/helpers/escape.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,UA0CzE;AACD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,MAAiD,CAAA;AACvG;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,MAAiD,CAAA"}