@scalar/snippetz 0.2.16 → 0.2.18

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.
package/README.md CHANGED
@@ -7,8 +7,6 @@
7
7
 
8
8
  A modern way to generate HTTP request examples for different languages and libraries.
9
9
 
10
- Check out some examples [here](https://scalar-snippetz-801498848929.us-central1.run.app/)
11
-
12
10
  ## Installation
13
11
 
14
12
  ```bash
@@ -24,21 +24,6 @@ export declare const python: {
24
24
  method: any;
25
25
  }, options?: {}) => any;
26
26
  };
27
- requests: {
28
- info: {
29
- key: string;
30
- title: string;
31
- link: string;
32
- description: string;
33
- };
34
- convert: ({ queryObj, url, postData, allHeaders, method }: {
35
- queryObj: any;
36
- url: any;
37
- postData: any;
38
- allHeaders: any;
39
- method: any;
40
- }, options: any) => any;
41
- };
42
27
  };
43
28
  };
44
29
  //# sourceMappingURL=target.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"target.d.ts","sourceRoot":"","sources":["../../../../../src/httpsnippet-lite/esm/targets/python/target.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWlB,CAAA"}
1
+ {"version":3,"file":"target.d.ts","sourceRoot":"","sources":["../../../../../src/httpsnippet-lite/esm/targets/python/target.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUlB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../../../src/plugins/python/requests/requests.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAQ5B,CAAA"}
1
+ {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../../../src/plugins/python/requests/requests.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAsI5B,CAAA"}
@@ -1,6 +1,4 @@
1
- import { requests } from '../../../httpsnippet-lite/esm/targets/python/requests/client.js';
2
- import { convertWithHttpSnippetLite } from '../../../utils/convertWithHttpSnippetLite.js';
3
-
1
+ const LENGTH_CONSIDERED_AS_SHORT = 40;
4
2
  /**
5
3
  * python/requests
6
4
  */
@@ -8,9 +6,126 @@ const pythonRequests = {
8
6
  target: 'python',
9
7
  client: 'requests',
10
8
  title: 'Requests',
11
- generate(request) {
12
- // TODO: Write an own converter
13
- return convertWithHttpSnippetLite(requests, request);
9
+ generate(request, configuration) {
10
+ // Normalize request with defaults
11
+ const normalizedRequest = {
12
+ url: 'https://example.com',
13
+ method: 'get',
14
+ ...request,
15
+ };
16
+ // Normalize method to lowercase for requests library
17
+ const method = normalizedRequest.method.toLowerCase();
18
+ // Build options object
19
+ const options = {};
20
+ // Add headers if present
21
+ if (normalizedRequest.headers?.length) {
22
+ options.headers = normalizedRequest.headers.reduce((acc, header) => {
23
+ if (!(header.name in acc)) {
24
+ acc[header.name] = header.value;
25
+ }
26
+ return acc;
27
+ }, {});
28
+ }
29
+ // Add query parameters if present
30
+ if (normalizedRequest.queryString?.length) {
31
+ options.params = Object.fromEntries(normalizedRequest.queryString.map((q) => [q.name, q.value]));
32
+ }
33
+ // Add cookies if present
34
+ if (normalizedRequest.cookies?.length) {
35
+ options.cookies = Object.fromEntries(normalizedRequest.cookies.map((c) => [c.name, c.value]));
36
+ }
37
+ // Add auth if present
38
+ if (configuration?.auth?.username && configuration?.auth?.password) {
39
+ options.auth = [configuration.auth.username, configuration.auth.password];
40
+ }
41
+ // Handle request body
42
+ if (normalizedRequest.postData) {
43
+ const { mimeType, text, params } = normalizedRequest.postData;
44
+ if (mimeType === 'application/json' && text) {
45
+ try {
46
+ options.json = JSON.parse(text);
47
+ }
48
+ catch {
49
+ options.data = text;
50
+ }
51
+ }
52
+ else if (mimeType === 'application/octet-stream' && text) {
53
+ options.data = text; // Store raw text, we'll handle the b"..." formatting later
54
+ }
55
+ else if (mimeType === 'multipart/form-data' && params) {
56
+ const files = {};
57
+ const formData = {};
58
+ params.forEach((param) => {
59
+ if (param.fileName !== undefined) {
60
+ files[param.name] = `open("${param.fileName}", "rb")`;
61
+ }
62
+ else if (param.value !== undefined) {
63
+ formData[param.name] = param.value;
64
+ }
65
+ });
66
+ if (Object.keys(files).length) {
67
+ options.files = files;
68
+ }
69
+ if (Object.keys(formData).length) {
70
+ options.data = formData;
71
+ }
72
+ }
73
+ else if (mimeType === 'application/x-www-form-urlencoded' && params) {
74
+ options.data = Object.fromEntries(params.map((p) => [p.name, p.value]));
75
+ }
76
+ }
77
+ // Format all parameters
78
+ const formattedParams = [];
79
+ // Format URL based on length
80
+ const urlParam = `"${normalizedRequest.url}"`;
81
+ if (normalizedRequest.url.length > LENGTH_CONSIDERED_AS_SHORT) {
82
+ formattedParams.push(urlParam);
83
+ }
84
+ else {
85
+ // Will be handled in the return statement for short URLs
86
+ formattedParams.push('');
87
+ }
88
+ // Format options
89
+ for (const [key, value] of Object.entries(options)) {
90
+ if (key === 'auth') {
91
+ formattedParams.push(`${key}=(${JSON.stringify(value[0])}, ${JSON.stringify(value[1])})`);
92
+ }
93
+ else if (key === 'files') {
94
+ const filesStr = JSON.stringify(value)
95
+ .replace(/"open\((.*?)\)"/g, 'open($1)')
96
+ .replace(/":open/g, '": open')
97
+ .replace(/\\"/g, '"');
98
+ formattedParams.push(`${key}=${filesStr}`);
99
+ }
100
+ else if (key === 'json') {
101
+ const jsonString = JSON.stringify(value, null, 2)
102
+ .split('\n')
103
+ .map((line, i) => (i === 0 ? line : ' ' + line))
104
+ .join('\n');
105
+ formattedParams.push(`${key}=${jsonString}`);
106
+ }
107
+ else if (key === 'data' && normalizedRequest.postData?.mimeType === 'application/octet-stream') {
108
+ // Special handling for binary data
109
+ formattedParams.push(`${key}=b"${value}"`);
110
+ }
111
+ else {
112
+ const str = JSON.stringify(value, null, 2)
113
+ .split('\n')
114
+ .map((line, i) => (i === 0 ? line : ' ' + line))
115
+ .join('\n');
116
+ formattedParams.push(`${key}=${str}`);
117
+ }
118
+ }
119
+ // Build the final request string with conditional URL formatting
120
+ if (normalizedRequest.url.length > LENGTH_CONSIDERED_AS_SHORT) {
121
+ return `requests.${method}(\n ${formattedParams.join(',\n ')}\n)`;
122
+ }
123
+ // For short URLs with no additional parameters, return a single-line format
124
+ if (formattedParams.length <= 1) {
125
+ return `requests.${method}(${urlParam})`;
126
+ }
127
+ // For short URLs with parameters, maintain the multi-line format
128
+ return `requests.${method}(${urlParam}${formattedParams.length > 1 ? ',' : ''}\n ${formattedParams.slice(1).join(',\n ')}\n)`;
14
129
  },
15
130
  };
16
131
 
@@ -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;AAEpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAyGvB,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;AAEpD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAqHvB,CAAA"}
@@ -67,9 +67,15 @@ const shellCurl = {
67
67
  if (normalizedRequest.postData.mimeType === 'application/json') {
68
68
  // Pretty print JSON data
69
69
  if (normalizedRequest.postData.text) {
70
- const jsonData = JSON.parse(normalizedRequest.postData.text);
71
- const prettyJson = JSON.stringify(jsonData, null, 2);
72
- parts.push(`--data '${prettyJson}'`);
70
+ try {
71
+ const jsonData = JSON.parse(normalizedRequest.postData.text);
72
+ const prettyJson = JSON.stringify(jsonData, null, 2);
73
+ parts.push(`--data '${prettyJson}'`);
74
+ }
75
+ catch {
76
+ // If JSON parsing fails, use the original text
77
+ parts.push(`--data '${normalizedRequest.postData.text}'`);
78
+ }
73
79
  }
74
80
  }
75
81
  else if (normalizedRequest.postData.mimeType === 'application/octet-stream') {
@@ -94,7 +100,15 @@ const shellCurl = {
94
100
  });
95
101
  }
96
102
  else {
97
- parts.push(`--data "${normalizedRequest.postData.text}"`);
103
+ // Try to parse and pretty print if it's JSON, otherwise use raw text
104
+ try {
105
+ const jsonData = JSON.parse(normalizedRequest.postData.text ?? '');
106
+ const prettyJson = JSON.stringify(jsonData, null, 2);
107
+ parts.push(`--data '${prettyJson}'`);
108
+ }
109
+ catch {
110
+ parts.push(`--data '${normalizedRequest.postData.text}'`);
111
+ }
98
112
  }
99
113
  }
100
114
  return parts.join(' \\\n ');
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.2.16",
12
+ "version": "0.2.18",
13
13
  "engines": {
14
14
  "node": ">=18"
15
15
  },
@@ -212,8 +212,8 @@
212
212
  },
213
213
  "devDependencies": {
214
214
  "vite": "^5.4.10",
215
- "@scalar/build-tooling": "0.1.16",
216
- "@scalar/types": "0.0.39"
215
+ "@scalar/build-tooling": "0.1.17",
216
+ "@scalar/types": "0.1.3"
217
217
  },
218
218
  "scripts": {
219
219
  "build": "scalar-build-rollup",
@@ -1,62 +0,0 @@
1
- // @ts-nocheck
2
- /**
3
- * Create a string corresponding to a Dictionary or Array literal representation with pretty option
4
- * and indentation.
5
- */
6
- function concatValues(concatType, values, pretty, indentation, indentLevel) {
7
- const currentIndent = indentation.repeat(indentLevel);
8
- const closingBraceIndent = indentation.repeat(indentLevel - 1);
9
- const join = pretty ? `,\n${currentIndent}` : ', ';
10
- const openingBrace = concatType === 'object' ? '{' : '[';
11
- const closingBrace = concatType === 'object' ? '}' : ']';
12
- if (pretty) {
13
- return `${openingBrace}\n${currentIndent}${values.join(join)}\n${closingBraceIndent}${closingBrace}`;
14
- }
15
- if (concatType === 'object' && values.length > 0) {
16
- return `${openingBrace} ${values.join(join)} ${closingBrace}`;
17
- }
18
- return `${openingBrace}${values.join(join)}${closingBrace}`;
19
- }
20
- /**
21
- * Create a valid Python string of a literal value according to its type.
22
- *
23
- * @param {*} value Any JavaScript literal
24
- * @param {object} opts Target options
25
- * @return {string}
26
- */
27
- const literalRepresentation = (value, opts, indentLevel) => {
28
- indentLevel = indentLevel === undefined ? 1 : indentLevel + 1;
29
- switch (Object.prototype.toString.call(value)) {
30
- case '[object Number]':
31
- return value;
32
- case '[object Array]': {
33
- let pretty = false;
34
- const valuesRepresentation = value.map((v) => {
35
- // Switch to prettify if the value is a dictionary with multiple keys
36
- if (Object.prototype.toString.call(v) === '[object Object]') {
37
- pretty = Object.keys(v).length > 1;
38
- }
39
- return literalRepresentation(v, opts, indentLevel);
40
- });
41
- return concatValues('array', valuesRepresentation, pretty, opts.indent, indentLevel);
42
- }
43
- case '[object Object]': {
44
- const keyValuePairs = [];
45
- for (const key in value) {
46
- keyValuePairs.push(`"${key}": ${literalRepresentation(value[key], opts, indentLevel)}`);
47
- }
48
- return concatValues('object', keyValuePairs, opts.pretty && keyValuePairs.length > 1, opts.indent, indentLevel);
49
- }
50
- case '[object Null]':
51
- return 'None';
52
- case '[object Boolean]':
53
- return value ? 'True' : 'False';
54
- default:
55
- if (value === null || value === undefined) {
56
- return '';
57
- }
58
- return `"${value.toString().replace(/"/g, '\\"')}"`;
59
- }
60
- };
61
-
62
- export { literalRepresentation };
@@ -1,16 +0,0 @@
1
- export declare const requests: {
2
- info: {
3
- key: string;
4
- title: string;
5
- link: string;
6
- description: string;
7
- };
8
- convert: ({ queryObj, url, postData, allHeaders, method }: {
9
- queryObj: any;
10
- url: any;
11
- postData: any;
12
- allHeaders: any;
13
- method: any;
14
- }, options: any) => any;
15
- };
16
- //# sourceMappingURL=client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../../../src/httpsnippet-lite/esm/targets/python/requests/client.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;CAqJpB,CAAA"}
@@ -1,176 +0,0 @@
1
- import { CodeBuilder } from '../../../helpers/code-builder.js';
2
- import { escapeForDoubleQuotes } from '../../../helpers/escape.js';
3
- import { getHeaderName } from '../../../helpers/headers.js';
4
- import { literalRepresentation } from '../helpers.js';
5
-
6
- // @ts-nocheck
7
- /**
8
- * @description
9
- * HTTP code snippet generator for Python using Requests
10
- *
11
- * @author
12
- * @montanaflynn
13
- *
14
- * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
15
- */
16
- const builtInMethods = [
17
- 'HEAD',
18
- 'GET',
19
- 'POST',
20
- 'PUT',
21
- 'PATCH',
22
- 'DELETE',
23
- 'OPTIONS',
24
- ];
25
- const requests = {
26
- info: {
27
- key: 'requests',
28
- title: 'Requests',
29
- link: 'http://docs.python-requests.org/en/latest/api/#requests.request',
30
- description: 'Requests HTTP library',
31
- },
32
- convert: ({ queryObj, url, postData, allHeaders, method }, options) => {
33
- const opts = {
34
- indent: ' ',
35
- pretty: true,
36
- ...options,
37
- };
38
- // Start snippet
39
- const { push, blank, join } = new CodeBuilder({ indent: opts.indent });
40
- // Import requests
41
- push('import requests');
42
- blank();
43
- // Set URL
44
- push(`url = "${url}"`);
45
- blank();
46
- // Construct query string
47
- let qs;
48
- if (Object.keys(queryObj).length) {
49
- qs = `querystring = ${JSON.stringify(queryObj)}`;
50
- push(qs);
51
- blank();
52
- }
53
- const headers = allHeaders;
54
- // Construct payload
55
- let payload = {};
56
- const files = {};
57
- let hasFiles = false;
58
- let hasPayload = false;
59
- let jsonPayload = false;
60
- switch (postData === null || postData === void 0 ? void 0 : postData.mimeType) {
61
- case 'application/json':
62
- if (postData.jsonObj) {
63
- push(`payload = ${literalRepresentation(postData.jsonObj, opts)}`);
64
- jsonPayload = true;
65
- hasPayload = true;
66
- }
67
- break;
68
- case 'multipart/form-data':
69
- if (!postData.params) {
70
- break;
71
- }
72
- payload = {};
73
- postData.params.forEach((p) => {
74
- if (p.fileName) {
75
- files[p.name] = `open('${p.fileName}', 'rb')`;
76
- hasFiles = true;
77
- }
78
- else {
79
- payload[p.name] = p.value;
80
- hasPayload = true;
81
- }
82
- });
83
- if (hasFiles) {
84
- push(`files = ${literalRepresentation(files, opts)}`);
85
- if (hasPayload) {
86
- push(`payload = ${literalRepresentation(payload, opts)}`);
87
- }
88
- // The requests library will only automatically add a `multipart/form-data` header if there are files being sent. If we're **only** sending form data we still need to send the boundary ourselves.
89
- const headerName = getHeaderName(headers, 'content-type');
90
- if (headerName) {
91
- delete headers[headerName];
92
- }
93
- }
94
- else {
95
- const nonFilePayload = JSON.stringify(postData.text);
96
- if (nonFilePayload) {
97
- push(`payload = ${nonFilePayload}`);
98
- hasPayload = true;
99
- }
100
- }
101
- break;
102
- default: {
103
- if (!postData) {
104
- break;
105
- }
106
- if (postData.mimeType === 'application/x-www-form-urlencoded' &&
107
- postData.paramsObj) {
108
- push(`payload = ${literalRepresentation(postData.paramsObj, opts)}`);
109
- hasPayload = true;
110
- break;
111
- }
112
- const payload = JSON.stringify(postData.text);
113
- if (payload) {
114
- push(`payload = ${payload}`);
115
- hasPayload = true;
116
- }
117
- }
118
- }
119
- // Construct headers
120
- const headerCount = Object.keys(headers).length;
121
- if (headerCount === 0 && (hasPayload || hasFiles)) {
122
- // If we don't have any heads but we do have a payload we should put a blank line here between that payload consturction and our execution of the requests library.
123
- blank();
124
- }
125
- else if (headerCount === 1) {
126
- for (const header in headers) {
127
- push(`headers = {"${header}": "${escapeForDoubleQuotes(headers[header])}"}`);
128
- blank();
129
- }
130
- }
131
- else if (headerCount > 1) {
132
- let count = 1;
133
- push('headers = {');
134
- for (const header in headers) {
135
- if (count !== headerCount) {
136
- push(`"${header}": "${escapeForDoubleQuotes(headers[header])}",`, 1);
137
- }
138
- else {
139
- push(`"${header}": "${escapeForDoubleQuotes(headers[header])}"`, 1);
140
- }
141
- count += 1;
142
- }
143
- push('}');
144
- blank();
145
- }
146
- // Construct request
147
- let request = builtInMethods.includes(method)
148
- ? `response = requests.${method.toLowerCase()}(url`
149
- : `response = requests.request("${method}", url`;
150
- if (hasPayload) {
151
- if (jsonPayload) {
152
- request += ', json=payload';
153
- }
154
- else {
155
- request += ', data=payload';
156
- }
157
- }
158
- if (hasFiles) {
159
- request += ', files=files';
160
- }
161
- if (headerCount > 0) {
162
- request += ', headers=headers';
163
- }
164
- if (qs) {
165
- request += ', params=querystring';
166
- }
167
- request += ')';
168
- push(request);
169
- blank();
170
- // Print response
171
- push('print(response.json())');
172
- return join();
173
- },
174
- };
175
-
176
- export { requests };