@scalar/snippetz 0.7.8 → 0.9.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 (73) hide show
  1. package/dist/clients/index.d.ts.map +1 -1
  2. package/dist/clients/index.js +5 -4
  3. package/dist/httpsnippet-lite/targets/c/libcurl/client.d.ts.map +1 -1
  4. package/dist/httpsnippet-lite/targets/c/libcurl/client.js +4 -2
  5. package/dist/libs/http.d.ts +0 -4
  6. package/dist/libs/http.d.ts.map +1 -1
  7. package/dist/libs/http.js +1 -11
  8. package/dist/libs/javascript.d.ts.map +1 -1
  9. package/dist/libs/javascript.js +6 -3
  10. package/dist/plugins/csharp/httpclient/httpclient.d.ts.map +1 -1
  11. package/dist/plugins/csharp/httpclient/httpclient.js +2 -3
  12. package/dist/plugins/dart/http/http.d.ts.map +1 -1
  13. package/dist/plugins/dart/http/http.js +1 -4
  14. package/dist/plugins/go/native/native.d.ts.map +1 -1
  15. package/dist/plugins/go/native/native.js +191 -5
  16. package/dist/plugins/http/http11/http11.d.ts.map +1 -1
  17. package/dist/plugins/http/http11/http11.js +2 -6
  18. package/dist/plugins/js/axios/axios.d.ts +1 -2
  19. package/dist/plugins/js/axios/axios.d.ts.map +1 -1
  20. package/dist/plugins/js/axios/axios.js +2 -11
  21. package/dist/plugins/js/fetch/fetch.d.ts.map +1 -1
  22. package/dist/plugins/js/fetch/fetch.js +2 -3
  23. package/dist/plugins/node/axios/axios.d.ts +1 -2
  24. package/dist/plugins/node/axios/axios.d.ts.map +1 -1
  25. package/dist/plugins/node/axios/axios.js +2 -11
  26. package/dist/plugins/node/fetch/fetch.d.ts.map +1 -1
  27. package/dist/plugins/node/fetch/fetch.js +2 -3
  28. package/dist/plugins/node/undici/undici.d.ts.map +1 -1
  29. package/dist/plugins/node/undici/undici.js +2 -3
  30. package/dist/plugins/php/curl/curl.d.ts.map +1 -1
  31. package/dist/plugins/php/curl/curl.js +1 -3
  32. package/dist/plugins/php/laravel/index.d.ts +2 -0
  33. package/dist/plugins/php/laravel/index.d.ts.map +1 -0
  34. package/dist/plugins/php/laravel/index.js +1 -0
  35. package/dist/plugins/php/laravel/laravel.d.ts +6 -0
  36. package/dist/plugins/php/laravel/laravel.d.ts.map +1 -0
  37. package/dist/plugins/php/laravel/laravel.js +134 -0
  38. package/dist/plugins/r/httr2/httr2.d.ts +6 -0
  39. package/dist/plugins/r/httr2/httr2.d.ts.map +1 -0
  40. package/dist/plugins/r/httr2/httr2.js +159 -0
  41. package/dist/plugins/r/httr2/index.d.ts +2 -0
  42. package/dist/plugins/r/httr2/index.d.ts.map +1 -0
  43. package/dist/plugins/r/httr2/index.js +1 -0
  44. package/dist/plugins/ruby/native/native.d.ts.map +1 -1
  45. package/dist/plugins/ruby/native/native.js +138 -5
  46. package/dist/plugins/shared/axios.d.ts +3 -0
  47. package/dist/plugins/shared/axios.d.ts.map +1 -0
  48. package/dist/plugins/shared/axios.js +148 -0
  49. package/dist/plugins/shell/curl/curl.d.ts.map +1 -1
  50. package/dist/plugins/shell/curl/curl.js +1 -3
  51. package/dist/snippetz.d.ts +1 -1
  52. package/package.json +12 -7
  53. package/dist/httpsnippet-lite/targets/go/native/client.d.ts +0 -12
  54. package/dist/httpsnippet-lite/targets/go/native/client.d.ts.map +0 -1
  55. package/dist/httpsnippet-lite/targets/go/native/client.js +0 -157
  56. package/dist/httpsnippet-lite/targets/javascript/axios/client.d.ts +0 -12
  57. package/dist/httpsnippet-lite/targets/javascript/axios/client.d.ts.map +0 -1
  58. package/dist/httpsnippet-lite/targets/javascript/axios/client.js +0 -86
  59. package/dist/httpsnippet-lite/targets/node/axios/client.d.ts +0 -3
  60. package/dist/httpsnippet-lite/targets/node/axios/client.d.ts.map +0 -1
  61. package/dist/httpsnippet-lite/targets/node/axios/client.js +0 -78
  62. package/dist/httpsnippet-lite/targets/r/httr/client.d.ts +0 -12
  63. package/dist/httpsnippet-lite/targets/r/httr/client.d.ts.map +0 -1
  64. package/dist/httpsnippet-lite/targets/r/httr/client.js +0 -115
  65. package/dist/httpsnippet-lite/targets/ruby/native/client.d.ts +0 -3
  66. package/dist/httpsnippet-lite/targets/ruby/native/client.d.ts.map +0 -1
  67. package/dist/httpsnippet-lite/targets/ruby/native/client.js +0 -67
  68. package/dist/plugins/r/httr/httr.d.ts +0 -6
  69. package/dist/plugins/r/httr/httr.d.ts.map +0 -1
  70. package/dist/plugins/r/httr/httr.js +0 -14
  71. package/dist/plugins/r/httr/index.d.ts +0 -2
  72. package/dist/plugins/r/httr/index.d.ts.map +0 -1
  73. package/dist/plugins/r/httr/index.js +0 -1
@@ -0,0 +1,134 @@
1
+ import { accumulateRepeatedValue, buildQueryString } from '../../../libs/http.js';
2
+ import { objectToString } from '../../../libs/php.js';
3
+ const escapePhpString = (value) => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
4
+ const quotePhpString = (value) => `'${escapePhpString(value)}'`;
5
+ const escapePhpObjectKey = escapePhpString;
6
+ const escapeObjectKeys = (value) => {
7
+ if (Array.isArray(value)) {
8
+ return value.map((item) => escapeObjectKeys(item));
9
+ }
10
+ if (value && typeof value === 'object') {
11
+ return Object.entries(value).reduce((acc, [key, nestedValue]) => {
12
+ acc[escapePhpObjectKey(key)] = escapeObjectKeys(nestedValue);
13
+ return acc;
14
+ }, {});
15
+ }
16
+ return value;
17
+ };
18
+ const getCookieDomain = (url) => {
19
+ if (!url) {
20
+ return 'localhost';
21
+ }
22
+ try {
23
+ return new URL(url).hostname || 'localhost';
24
+ }
25
+ catch {
26
+ return 'localhost';
27
+ }
28
+ };
29
+ /**
30
+ * php/laravel
31
+ */
32
+ export const phpLaravel = {
33
+ target: 'php',
34
+ client: 'laravel',
35
+ title: 'Laravel HTTP Client',
36
+ generate(request, configuration) {
37
+ const normalizedRequest = {
38
+ method: 'GET',
39
+ ...request,
40
+ };
41
+ normalizedRequest.method = normalizedRequest.method.toUpperCase();
42
+ const queryString = buildQueryString(normalizedRequest.queryString);
43
+ const url = `${normalizedRequest.url ?? ''}${queryString}`;
44
+ const chain = [];
45
+ if (configuration?.auth?.username && configuration.auth.password) {
46
+ chain.push(`withBasicAuth(${quotePhpString(configuration.auth.username)}, ${quotePhpString(configuration.auth.password)})`);
47
+ }
48
+ if (normalizedRequest.headers?.length) {
49
+ const headers = {};
50
+ normalizedRequest.headers.forEach((header) => {
51
+ accumulateRepeatedValue(headers, header.name, header.value);
52
+ });
53
+ chain.push(`withHeaders(${objectToString(escapeObjectKeys(headers))})`);
54
+ }
55
+ if (normalizedRequest.cookies?.length) {
56
+ const cookies = {};
57
+ normalizedRequest.cookies.forEach((cookie) => {
58
+ accumulateRepeatedValue(cookies, cookie.name, cookie.value);
59
+ });
60
+ chain.push(`withCookies(${objectToString(escapeObjectKeys(cookies))}, ${quotePhpString(getCookieDomain(normalizedRequest.url ?? ''))})`);
61
+ }
62
+ let payload;
63
+ if (normalizedRequest.postData) {
64
+ if (normalizedRequest.postData.mimeType === 'application/json') {
65
+ if (normalizedRequest.postData.text) {
66
+ try {
67
+ payload = JSON.parse(normalizedRequest.postData.text);
68
+ }
69
+ catch {
70
+ chain.push(`withBody(${quotePhpString(normalizedRequest.postData.text)}, 'application/json')`);
71
+ }
72
+ }
73
+ }
74
+ else if (normalizedRequest.postData.mimeType === 'application/x-www-form-urlencoded' &&
75
+ normalizedRequest.postData.params) {
76
+ const formData = {};
77
+ normalizedRequest.postData.params.forEach((param) => {
78
+ accumulateRepeatedValue(formData, param.name, param.value ?? '');
79
+ });
80
+ chain.push('asForm()');
81
+ payload = formData;
82
+ }
83
+ else if (normalizedRequest.postData.mimeType === 'multipart/form-data' && normalizedRequest.postData.params) {
84
+ const multipartData = {};
85
+ normalizedRequest.postData.params.forEach((param) => {
86
+ if (param.fileName !== undefined) {
87
+ const args = [
88
+ quotePhpString(param.name),
89
+ `file_get_contents(${quotePhpString(param.fileName)})`,
90
+ quotePhpString(param.fileName),
91
+ ];
92
+ if (param.contentType) {
93
+ args.push(objectToString(escapeObjectKeys({ 'Content-Type': param.contentType })));
94
+ }
95
+ chain.push(`attach(${args.join(', ')})`);
96
+ }
97
+ else if (param.contentType) {
98
+ chain.push(`attach(${quotePhpString(param.name)}, ${quotePhpString(param.value ?? '')}, null, ${objectToString(escapeObjectKeys({ 'Content-Type': param.contentType }))})`);
99
+ }
100
+ else {
101
+ accumulateRepeatedValue(multipartData, param.name, param.value ?? '');
102
+ }
103
+ });
104
+ if (Object.keys(multipartData).length > 0) {
105
+ payload = multipartData;
106
+ }
107
+ }
108
+ else if (normalizedRequest.postData.mimeType === 'application/octet-stream') {
109
+ chain.push(`withBody(${quotePhpString(normalizedRequest.postData.text ?? '')}, 'application/octet-stream')`);
110
+ }
111
+ else if (normalizedRequest.postData.text) {
112
+ try {
113
+ payload = JSON.parse(normalizedRequest.postData.text);
114
+ }
115
+ catch {
116
+ chain.push(`withBody(${quotePhpString(normalizedRequest.postData.text)}, ${quotePhpString(normalizedRequest.postData.mimeType || 'text/plain')})`);
117
+ }
118
+ }
119
+ }
120
+ const requestMethod = normalizedRequest.method.toLowerCase();
121
+ const supportsDirectMethod = ['delete', 'get', 'head', 'patch', 'post', 'put'].includes(requestMethod);
122
+ const requestCall = supportsDirectMethod
123
+ ? payload !== undefined && requestMethod !== 'head'
124
+ ? `${requestMethod}(${quotePhpString(url)}, ${objectToString(escapeObjectKeys(payload), 1)})`
125
+ : `${requestMethod}(${quotePhpString(url)})`
126
+ : payload !== undefined
127
+ ? `send(${quotePhpString(normalizedRequest.method)}, ${quotePhpString(url)}, ${objectToString(escapeObjectKeys(payload), 1)})`
128
+ : `send(${quotePhpString(normalizedRequest.method)}, ${quotePhpString(url)})`;
129
+ const expression = chain.length > 0
130
+ ? [`Http::${chain[0]}`, ...chain.slice(1).map((method) => ` ->${method}`), ` ->${requestCall}`].join('\n')
131
+ : `Http::${requestCall}`;
132
+ return `use Illuminate\\Support\\Facades\\Http;\n\n$response = ${expression};`;
133
+ },
134
+ };
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from '@scalar/types/snippetz';
2
+ /**
3
+ * r/httr2
4
+ */
5
+ export declare const rHttr2: Plugin;
6
+ //# sourceMappingURL=httr2.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,159 @@
1
+ import { reduceQueryParams } from '../../../libs/http.js';
2
+ /**
3
+ * Formats JSON text as an R list structure
4
+ */
5
+ const jsonToRList = (text, indent) => {
6
+ try {
7
+ const obj = JSON.parse(text);
8
+ return formatRValue(obj, indent);
9
+ }
10
+ catch {
11
+ return `"${text}"`;
12
+ }
13
+ };
14
+ /**
15
+ * Recursively formats a JS value as R syntax
16
+ */
17
+ const formatRValue = (value, indent) => {
18
+ if (value === null || value === undefined) {
19
+ return 'NULL';
20
+ }
21
+ if (typeof value === 'boolean') {
22
+ return value ? 'TRUE' : 'FALSE';
23
+ }
24
+ if (typeof value === 'number') {
25
+ return String(value);
26
+ }
27
+ if (typeof value === 'string') {
28
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
29
+ }
30
+ if (Array.isArray(value)) {
31
+ if (value.length === 0) {
32
+ return 'list()';
33
+ }
34
+ const items = value.map((v) => `${indent} ${formatRValue(v, indent + ' ')}`).join(',\n');
35
+ return `list(\n${items}\n${indent})`;
36
+ }
37
+ if (typeof value === 'object') {
38
+ const entries = Object.entries(value);
39
+ if (entries.length === 0) {
40
+ return 'list()';
41
+ }
42
+ const items = entries.map(([k, v]) => `${indent} ${k} = ${formatRValue(v, indent + ' ')}`).join(',\n');
43
+ return `list(\n${items}\n${indent})`;
44
+ }
45
+ return String(value);
46
+ };
47
+ /**
48
+ * r/httr2
49
+ */
50
+ export const rHttr2 = {
51
+ target: 'r',
52
+ client: 'httr2',
53
+ title: 'httr2',
54
+ generate(request, configuration) {
55
+ const normalizedRequest = {
56
+ url: 'https://example.com',
57
+ method: 'GET',
58
+ ...request,
59
+ };
60
+ const method = normalizedRequest.method.toUpperCase();
61
+ const lines = ['library(httr2)', ''];
62
+ // Start the pipe chain
63
+ lines.push(`response <- request("${normalizedRequest.url}") |>`);
64
+ // Collect pipe steps
65
+ const steps = [];
66
+ // Method (GET is default, so only add for non-GET)
67
+ if (method !== 'GET') {
68
+ steps.push(` req_method("${method}")`);
69
+ }
70
+ // Headers
71
+ const headers = {};
72
+ if (normalizedRequest.headers?.length) {
73
+ for (const header of normalizedRequest.headers) {
74
+ headers[header.name] = header.value;
75
+ }
76
+ }
77
+ // Cookies as Cookie header
78
+ if (normalizedRequest.cookies?.length) {
79
+ const cookieString = normalizedRequest.cookies.map((c) => `${c.name}=${c.value}`).join('; ');
80
+ headers['Cookie'] = cookieString;
81
+ }
82
+ // Auth
83
+ if (configuration?.auth?.username && configuration?.auth?.password) {
84
+ steps.push(` req_auth_basic("${configuration.auth.username}", "${configuration.auth.password}")`);
85
+ }
86
+ if (Object.keys(headers).length) {
87
+ const headerEntries = Object.entries(headers);
88
+ if (headerEntries.length === 1) {
89
+ const [name, value] = headerEntries[0];
90
+ steps.push(` req_headers("${name}" = "${value}")`);
91
+ }
92
+ else {
93
+ const headerLines = headerEntries.map(([name, value]) => ` "${name}" = "${value}"`).join(',\n');
94
+ steps.push(` req_headers(\n${headerLines}\n )`);
95
+ }
96
+ }
97
+ // Query parameters
98
+ if (normalizedRequest.queryString?.length) {
99
+ const params = reduceQueryParams(normalizedRequest.queryString);
100
+ const entries = Object.entries(params);
101
+ if (entries.length === 1) {
102
+ const [name, value] = entries[0];
103
+ if (Array.isArray(value)) {
104
+ const items = value.map((v) => `"${v}"`).join(', ');
105
+ steps.push(` req_url_query("${name}" = c(${items}))`);
106
+ }
107
+ else {
108
+ steps.push(` req_url_query("${name}" = "${value}")`);
109
+ }
110
+ }
111
+ else {
112
+ const paramLines = entries
113
+ .map(([name, value]) => {
114
+ if (Array.isArray(value)) {
115
+ const items = value.map((v) => `"${v}"`).join(', ');
116
+ return ` "${name}" = c(${items})`;
117
+ }
118
+ return ` "${name}" = "${value}"`;
119
+ })
120
+ .join(',\n');
121
+ steps.push(` req_url_query(\n${paramLines}\n )`);
122
+ }
123
+ }
124
+ // Body
125
+ if (normalizedRequest.postData) {
126
+ const { mimeType, text, params } = normalizedRequest.postData;
127
+ if (mimeType === 'application/json' && text) {
128
+ const rList = jsonToRList(text, ' ');
129
+ steps.push(` req_body_json(${rList})`);
130
+ }
131
+ else if (mimeType === 'multipart/form-data' && params) {
132
+ const paramLines = params
133
+ .map((p) => {
134
+ if (p.fileName !== undefined) {
135
+ return ` ${p.name} = curl::form_file("${p.fileName}")`;
136
+ }
137
+ return ` ${p.name} = "${p.value ?? ''}"`;
138
+ })
139
+ .join(',\n');
140
+ steps.push(` req_body_multipart(\n${paramLines}\n )`);
141
+ }
142
+ else if (mimeType === 'application/x-www-form-urlencoded' && params) {
143
+ const paramLines = params.map((p) => ` "${p.name}" = "${p.value ?? ''}"`).join(',\n');
144
+ steps.push(` req_body_form(\n${paramLines}\n )`);
145
+ }
146
+ else if (text) {
147
+ steps.push(` req_body_raw("${text}", type = "${mimeType ?? 'application/octet-stream'}")`);
148
+ }
149
+ }
150
+ // Always end with req_perform
151
+ steps.push(' req_perform()');
152
+ // Join steps with pipe operator
153
+ lines[lines.length - 1] = `response <- request("${normalizedRequest.url}") |>`;
154
+ lines.push(steps.join(' |>\n'));
155
+ lines.push('');
156
+ lines.push('resp_body_string(response)');
157
+ return lines.join('\n');
158
+ },
159
+ };
@@ -0,0 +1,2 @@
1
+ export { rHttr2 } from './httr2.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/r/httr2/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1 @@
1
+ export { rHttr2 } from './httr2.js';
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../../src/plugins/ruby/native/native.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAKpD;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAQxB,CAAA"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../../src/plugins/ruby/native/native.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AA8DpD;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAuGxB,CAAA"}
@@ -1,5 +1,51 @@
1
- import { native } from '../../../httpsnippet-lite/targets/ruby/native/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
1
+ import { buildQueryString } from '../../../libs/http.js';
2
+ const escapeRubyDoubleQuoted = (value) => value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
3
+ const escapeRubySingleQuoted = (value) => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
4
+ const encodeFormComponent = (value) => encodeURIComponent(value).replace(/'/g, '%27');
5
+ const standardMethods = new Set([
6
+ 'GET',
7
+ 'POST',
8
+ 'HEAD',
9
+ 'DELETE',
10
+ 'PATCH',
11
+ 'PUT',
12
+ 'OPTIONS',
13
+ 'COPY',
14
+ 'LOCK',
15
+ 'UNLOCK',
16
+ 'MOVE',
17
+ 'TRACE',
18
+ ]);
19
+ const toRubyMethodClass = (method) => method.charAt(0) + method.slice(1).toLowerCase();
20
+ const maybeAddCustomMethodClass = (lines, method, hasBody) => {
21
+ if (standardMethods.has(method)) {
22
+ return;
23
+ }
24
+ const methodClass = toRubyMethodClass(method);
25
+ lines.push(`class Net::HTTP::${methodClass} < Net::HTTPRequest`);
26
+ lines.push(` METHOD = '${method}'`);
27
+ lines.push(` REQUEST_HAS_BODY = '${hasBody ? 'true' : 'false'}'`);
28
+ lines.push(' RESPONSE_HAS_BODY = true');
29
+ lines.push('end');
30
+ lines.push('');
31
+ };
32
+ const encodeUrlWithPathPreservedBrackets = (url) => {
33
+ try {
34
+ const parsedUrl = new URL(url);
35
+ const encodedPath = parsedUrl.pathname
36
+ .split('/')
37
+ .map((segment) => encodeURIComponent(decodeURIComponent(segment)).replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%24/g, '$'))
38
+ .join('/');
39
+ // Keep legacy behavior from the previous converter: omit trailing slash for origin-only URLs.
40
+ if (parsedUrl.pathname === '/') {
41
+ return `${parsedUrl.origin}${parsedUrl.search}${parsedUrl.hash}`;
42
+ }
43
+ return `${parsedUrl.origin}${encodedPath}${parsedUrl.search}${parsedUrl.hash}`;
44
+ }
45
+ catch {
46
+ return url;
47
+ }
48
+ };
3
49
  /**
4
50
  * ruby/native
5
51
  */
@@ -7,8 +53,95 @@ export const rubyNative = {
7
53
  target: 'ruby',
8
54
  client: 'native',
9
55
  title: 'net::http',
10
- generate(request) {
11
- // TODO: Write an own converter
12
- return convertWithHttpSnippetLite(native, request);
56
+ generate(request, configuration) {
57
+ const normalizedRequest = {
58
+ method: 'GET',
59
+ ...request,
60
+ };
61
+ normalizedRequest.method = normalizedRequest.method.toUpperCase();
62
+ const queryString = buildQueryString(normalizedRequest.queryString);
63
+ const rawUrl = `${normalizedRequest.url ?? ''}${queryString}`;
64
+ const encodedUrl = encodeUrlWithPathPreservedBrackets(rawUrl);
65
+ const lines = ["require 'uri'", "require 'net/http'", ''];
66
+ maybeAddCustomMethodClass(lines, normalizedRequest.method, Boolean(normalizedRequest.postData?.text));
67
+ lines.push(`url = URI("${escapeRubyDoubleQuoted(encodedUrl)}")`, '');
68
+ lines.push('http = Net::HTTP.new(url.host, url.port)');
69
+ if (encodedUrl.startsWith('https://')) {
70
+ lines.push('http.use_ssl = true');
71
+ }
72
+ lines.push('');
73
+ const methodClass = toRubyMethodClass(normalizedRequest.method);
74
+ lines.push(`request = Net::HTTP::${methodClass}.new(url)`);
75
+ if (configuration?.auth?.username && configuration?.auth?.password) {
76
+ const username = escapeRubyDoubleQuoted(configuration.auth.username);
77
+ const password = escapeRubyDoubleQuoted(configuration.auth.password);
78
+ lines.push(`request.basic_auth("${username}", "${password}")`);
79
+ }
80
+ if (normalizedRequest.headers?.length) {
81
+ normalizedRequest.headers.forEach((header) => {
82
+ lines.push(`request["${escapeRubyDoubleQuoted(header.name)}"] = '${escapeRubySingleQuoted(header.value)}'`);
83
+ });
84
+ }
85
+ if (normalizedRequest.cookies?.length) {
86
+ const cookieString = normalizedRequest.cookies
87
+ .map((cookie) => `${encodeFormComponent(cookie.name)}=${encodeFormComponent(cookie.value)}`)
88
+ .join('; ');
89
+ lines.push(`request["Cookie"] = '${escapeRubySingleQuoted(cookieString)}'`);
90
+ }
91
+ if (normalizedRequest.postData) {
92
+ const { mimeType, text, params } = normalizedRequest.postData;
93
+ if (mimeType === 'application/json' && text !== undefined) {
94
+ try {
95
+ const parsed = JSON.parse(text);
96
+ const prettyJson = JSON.stringify(parsed, null, 2);
97
+ lines.push('request.body = <<~JSON');
98
+ lines.push(prettyJson);
99
+ lines.push('JSON');
100
+ }
101
+ catch {
102
+ lines.push(`request.body = ${JSON.stringify(text)}`);
103
+ }
104
+ }
105
+ else if (mimeType === 'application/x-www-form-urlencoded' && params) {
106
+ const encodedForm = params
107
+ .map((param) => `${encodeFormComponent(param.name)}=${encodeFormComponent(param.value ?? '')}`)
108
+ .join('&');
109
+ lines.push(`request.body = '${escapeRubySingleQuoted(encodedForm)}'`);
110
+ }
111
+ else if (mimeType === 'multipart/form-data' && params) {
112
+ lines.push('form_data = []');
113
+ params.forEach((param) => {
114
+ const name = escapeRubySingleQuoted(param.name);
115
+ if (param.fileName !== undefined) {
116
+ const fileName = escapeRubySingleQuoted(param.fileName);
117
+ if (param.contentType) {
118
+ const contentType = escapeRubySingleQuoted(param.contentType);
119
+ lines.push(`form_data << ['${name}', File.open('${fileName}'), { filename: '${fileName}', content_type: '${contentType}' }]`);
120
+ }
121
+ else {
122
+ lines.push(`form_data << ['${name}', File.open('${fileName}')]`);
123
+ }
124
+ }
125
+ else if (param.contentType) {
126
+ const value = escapeRubySingleQuoted(param.value ?? '');
127
+ const contentType = escapeRubySingleQuoted(param.contentType);
128
+ lines.push(`form_data << ['${name}', '${value}', { content_type: '${contentType}' }]`);
129
+ }
130
+ else {
131
+ const value = escapeRubySingleQuoted(param.value ?? '');
132
+ lines.push(`form_data << ['${name}', '${value}']`);
133
+ }
134
+ });
135
+ lines.push("request.set_form(form_data, 'multipart/form-data')");
136
+ }
137
+ else if (mimeType === 'application/octet-stream') {
138
+ lines.push(`request.body = ${JSON.stringify(text ?? '')}`);
139
+ }
140
+ else if (text !== undefined) {
141
+ lines.push(`request.body = ${JSON.stringify(text)}`);
142
+ }
143
+ }
144
+ lines.push('', 'response = http.request(request)', 'puts response.read_body');
145
+ return lines.join('\n');
13
146
  },
14
147
  };
@@ -0,0 +1,3 @@
1
+ import type { Plugin, TargetId } from '@scalar/types/snippetz';
2
+ export declare const createAxiosPlugin: (target: Extract<TargetId, "js" | "node">) => Plugin;
3
+ //# sourceMappingURL=axios.d.ts.map
@@ -0,0 +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,QAAQ,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM,CAAC,KAAG,MAmD3E,CAAA"}
@@ -0,0 +1,148 @@
1
+ import { accumulateRepeatedValue, reduceQueryParams } from '../../libs/http.js';
2
+ import { Raw, objectToString } from '../../libs/javascript.js';
3
+ const escapeJsString = (value) => value.replaceAll('\\', '\\\\').replaceAll('\n', '\\n').replaceAll('\r', '\\r').replaceAll("'", "\\'");
4
+ const sanitizeForGeneratedCode = (value) => {
5
+ if (typeof value === 'string') {
6
+ return escapeJsString(value);
7
+ }
8
+ if (Array.isArray(value)) {
9
+ return value.map((item) => sanitizeForGeneratedCode(item));
10
+ }
11
+ if (value && typeof value === 'object' && !(value instanceof Raw)) {
12
+ return Object.entries(value).reduce((acc, [key, objectValue]) => {
13
+ acc[key] = sanitizeForGeneratedCode(objectValue);
14
+ return acc;
15
+ }, {});
16
+ }
17
+ return value;
18
+ };
19
+ const addHeaderValue = (headers, name, value) => {
20
+ if (value === '') {
21
+ headers[name] = value;
22
+ return;
23
+ }
24
+ accumulateRepeatedValue(headers, name, value);
25
+ };
26
+ const buildHeaders = (request) => {
27
+ const headers = {};
28
+ request?.headers?.forEach((header) => {
29
+ addHeaderValue(headers, header.name, header.value);
30
+ });
31
+ if (request?.cookies?.length) {
32
+ const cookieValue = request.cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join('; ');
33
+ addHeaderValue(headers, 'Cookie', cookieValue);
34
+ }
35
+ return Object.keys(headers).length ? headers : undefined;
36
+ };
37
+ const buildData = (request) => {
38
+ const setup = [];
39
+ const postData = request?.postData;
40
+ if (!postData) {
41
+ return { setup };
42
+ }
43
+ if (postData.mimeType === 'application/json') {
44
+ if (!postData.text) {
45
+ return { setup };
46
+ }
47
+ try {
48
+ return {
49
+ setup,
50
+ data: JSON.parse(postData.text),
51
+ };
52
+ }
53
+ catch {
54
+ return {
55
+ setup,
56
+ data: postData.text,
57
+ };
58
+ }
59
+ }
60
+ if (postData.mimeType === 'application/x-www-form-urlencoded' && postData.params?.length) {
61
+ setup.push('const encodedParams = new URLSearchParams()');
62
+ postData.params.forEach((param) => {
63
+ const encodedName = escapeJsString(param.name);
64
+ const encodedValue = escapeJsString(param.value ?? '');
65
+ setup.push(`encodedParams.append('${encodedName}', '${encodedValue}')`);
66
+ });
67
+ return {
68
+ setup,
69
+ data: new Raw('encodedParams'),
70
+ };
71
+ }
72
+ if (postData.mimeType === 'multipart/form-data' && postData.params?.length) {
73
+ setup.push('const formData = new FormData()');
74
+ postData.params.forEach((param) => {
75
+ const encodedName = escapeJsString(param.name);
76
+ if (param.fileName !== undefined) {
77
+ const encodedFileName = escapeJsString(param.fileName);
78
+ const blobWithType = param.contentType ? `, { type: '${escapeJsString(param.contentType)}' }` : '';
79
+ setup.push(`formData.append('${encodedName}', new Blob([]${blobWithType}), '${encodedFileName}')`);
80
+ return;
81
+ }
82
+ if (param.contentType) {
83
+ const encodedContentType = escapeJsString(param.contentType);
84
+ const encodedValue = escapeJsString(param.value ?? '');
85
+ setup.push(`formData.append('${encodedName}', new Blob(['${encodedValue}'], { type: '${encodedContentType}' }))`);
86
+ return;
87
+ }
88
+ const encodedValue = escapeJsString(param.value ?? '');
89
+ setup.push(`formData.append('${encodedName}', '${encodedValue}')`);
90
+ });
91
+ return {
92
+ setup,
93
+ data: new Raw('formData'),
94
+ };
95
+ }
96
+ if (!postData.text) {
97
+ return { setup };
98
+ }
99
+ return {
100
+ setup,
101
+ data: postData.text,
102
+ };
103
+ };
104
+ export const createAxiosPlugin = (target) => ({
105
+ target,
106
+ client: 'axios',
107
+ title: 'Axios',
108
+ generate(request, configuration) {
109
+ const normalizedRequest = {
110
+ method: 'GET',
111
+ ...request,
112
+ };
113
+ normalizedRequest.method = normalizedRequest.method.toUpperCase();
114
+ const options = {
115
+ method: normalizedRequest.method,
116
+ url: escapeJsString(normalizedRequest.url ?? ''),
117
+ };
118
+ const params = reduceQueryParams(normalizedRequest.queryString);
119
+ if (Object.keys(params).length) {
120
+ options.params = sanitizeForGeneratedCode(params);
121
+ }
122
+ const headers = buildHeaders(normalizedRequest);
123
+ if (headers) {
124
+ options.headers = sanitizeForGeneratedCode(headers);
125
+ }
126
+ if (configuration?.auth?.username && configuration?.auth?.password) {
127
+ options.auth = {
128
+ username: escapeJsString(configuration.auth.username),
129
+ password: escapeJsString(configuration.auth.password),
130
+ };
131
+ }
132
+ const { setup, data } = buildData(normalizedRequest);
133
+ if (data !== undefined) {
134
+ options.data = data instanceof Raw ? data : sanitizeForGeneratedCode(data);
135
+ }
136
+ const setupBlock = setup.length ? `${setup.join('\n')}\n\n` : '';
137
+ return `import axios from 'axios'
138
+
139
+ ${setupBlock}const options = ${objectToString(options)}
140
+
141
+ try {
142
+ const { data } = await axios.request(options)
143
+ console.log(data)
144
+ } catch (error) {
145
+ console.error(error)
146
+ }`;
147
+ },
148
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/curl/curl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAoIvB,CAAA"}
1
+ {"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../../../src/plugins/shell/curl/curl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAkIvB,CAAA"}
@@ -22,9 +22,7 @@ export const shellCurl = {
22
22
  normalizedRequest.queryString
23
23
  .map((param) => {
24
24
  // Ensure both name and value are fully URI encoded
25
- const encodedName = encodeURIComponent(param.name);
26
- const encodedValue = encodeURIComponent(param.value);
27
- return `${encodedName}=${encodedValue}`;
25
+ return `${param.name}=${param.value}`;
28
26
  })
29
27
  .join('&')
30
28
  : '';
@@ -7,7 +7,7 @@ export declare function snippetz(): {
7
7
  clients(): import("@scalar/types/snippetz").Target[];
8
8
  plugins(): {
9
9
  target: "c" | "clojure" | "csharp" | "go" | "http" | "java" | "kotlin" | "node" | "objc" | "ocaml" | "php" | "powershell" | "python" | "r" | "ruby" | "shell" | "swift" | "dart" | "fsharp" | "js" | "rust";
10
- client: "http" | "libcurl" | "clj_http" | "httpclient" | "restsharp" | "native" | "http1.1" | "asynchttp" | "nethttp" | "okhttp" | "unirest" | "axios" | "fetch" | "ofetch" | "undici" | "nsurlsession" | "cohttp" | "curl" | "guzzle" | "restmethod" | "webrequest" | "python3" | "requests" | "httpx_sync" | "httpx_async" | "httr" | "httpie" | "wget" | "jquery" | "xhr" | "reqwest";
10
+ client: "http" | "libcurl" | "clj_http" | "httpclient" | "restsharp" | "native" | "http1.1" | "asynchttp" | "nethttp" | "okhttp" | "unirest" | "axios" | "fetch" | "ofetch" | "undici" | "nsurlsession" | "cohttp" | "curl" | "guzzle" | "laravel" | "restmethod" | "webrequest" | "python3" | "requests" | "httpx_sync" | "httpx_async" | "httr2" | "httpie" | "wget" | "jquery" | "xhr" | "reqwest";
11
11
  }[];
12
12
  findPlugin: <T extends TargetId>(target: T | string, client: ClientId<T> | string) => import("@scalar/types/snippetz").Plugin | undefined;
13
13
  hasPlugin<T extends TargetId>(target: T | string, client: ClientId<T> | string): boolean;