httpsnippet-client-api 7.0.0-beta.0 → 7.0.0-beta.13

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/src/index.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  import type { ReducedHelperObject } from '@readme/httpsnippet/helpers/reducer';
2
- import type { Client } from '@readme/httpsnippet/targets';
3
- import type Operation from 'oas/operation';
4
- import type { HttpMethods, OASDocument } from 'oas/rmoas.types';
2
+ import type { Client, ClientPlugin } from '@readme/httpsnippet/targets';
3
+ import type { Operation } from 'oas/operation';
4
+ import type { HttpMethods, OASDocument } from 'oas/types';
5
5
 
6
6
  import { CodeBuilder } from '@readme/httpsnippet/helpers/code-builder';
7
+ import camelCase from 'camelcase'; // eslint-disable-line import/no-extraneous-dependencies
7
8
  import contentType from 'content-type';
8
9
  import Oas from 'oas';
9
10
  import { matchesMimeType } from 'oas/utils';
10
- import stringifyObject from 'stringify-object';
11
+ import { isReservedOrBuiltinsLC } from 'reserved2';
12
+ import stringifyObject from 'stringify-object'; // eslint-disable-line import/no-extraneous-dependencies
11
13
 
12
14
  /**
13
15
  * @note This regex also exists in `api/fetcher`.
@@ -34,7 +36,7 @@ function stringify(obj: any, opts = {}) {
34
36
  return stringifyObject(obj, { indent: ' ', ...opts });
35
37
  }
36
38
 
37
- function buildAuthSnippet(authKey: string | string[]) {
39
+ function buildAuthSnippet(sdkVariable: string, authKey: string[] | string) {
38
40
  // Auth key will be an array for Basic auth cases.
39
41
  if (Array.isArray(authKey)) {
40
42
  const auth: string[] = [];
@@ -47,10 +49,10 @@ function buildAuthSnippet(authKey: string | string[]) {
47
49
  auth.push(`'${token.replace(/'/g, "\\'")}'`);
48
50
  });
49
51
 
50
- return `sdk.auth(${auth.join(', ')});`;
52
+ return `${sdkVariable}.auth(${auth.join(', ')});`;
51
53
  }
52
54
 
53
- return `sdk.auth('${authKey.replace(/'/g, "\\'")}');`;
55
+ return `${sdkVariable}.auth('${authKey.replace(/'/g, "\\'")}');`;
54
56
  }
55
57
 
56
58
  function getAuthSources(operation: Operation) {
@@ -95,21 +97,25 @@ function getAuthSources(operation: Operation) {
95
97
  }
96
98
 
97
99
  interface APIOptions {
98
- apiDefinition: OASDocument;
99
- /**
100
- * The URI that is used to download this API definition from `npx api install`.
101
- *
102
- * @example @developers/v2.0#17273l2glm9fq4l5
103
- */
104
- apiDefinitionUri: string;
100
+ api?: {
101
+ definition: OASDocument;
102
+
103
+ /**
104
+ * The string to identify this SDK as. This is used in the `import sdk from '<identifier>'`
105
+ * sample as well as the the variable name we attach the SDK to.
106
+ *
107
+ * @example `@api/developers`
108
+ */
109
+ identifier?: string;
110
+
111
+ /**
112
+ * The URI that is used to download this API definition from `npx api install`.
113
+ *
114
+ * @example `@developers/v2.0#17273l2glm9fq4l5`
115
+ */
116
+ registryURI: string;
117
+ };
105
118
  escapeBrackets?: boolean;
106
- /**
107
- * The string to identify this SDK as. This is used in the `import sdk from '@api/<identifier>'`
108
- * sample as well as the the variable name we attach the SDK to.
109
- *
110
- * @example developers
111
- */
112
- identifier?: string;
113
119
  indent?: string | false;
114
120
  }
115
121
 
@@ -120,36 +126,45 @@ const client: Client<APIOptions> = {
120
126
  link: 'https://npm.im/api',
121
127
  description: 'Automatic SDK generation from an OpenAPI definition.',
122
128
  extname: '.js',
129
+ installation: 'npx api install "{packageName}"',
123
130
  },
124
131
  convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {
125
132
  const opts = {
126
133
  ...options,
127
- } as APIOptions;
128
-
129
- if (!('apiDefinitionUri' in opts)) {
130
- throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.');
131
- } else if (!('apiDefinition' in opts)) {
132
- throw new Error('This HTTP Snippet client must have an `apiDefinition` option supplied to it.');
134
+ };
135
+
136
+ if (!opts?.api) {
137
+ throw new Error('This HTTPSnippet client must have an `api` config supplied to it.');
138
+ } else if (!opts?.api?.definition) {
139
+ throw new Error('This HTTPSnippet client must have an `api.definition` option supplied to it.');
140
+ } else if (!opts?.api?.registryURI) {
141
+ throw new Error('This HTTPSnippet client must have an `api.registryURI` option supplied to it.');
133
142
  }
134
143
 
135
144
  const method = source.method.toLowerCase() as HttpMethods;
136
- const oas = new Oas(opts.apiDefinition);
145
+ const oas = new Oas(opts.api.definition);
137
146
  const apiDefinition = oas.getDefinition();
138
147
  const foundOperation = oas.findOperation(url, method);
139
148
  if (!foundOperation) {
140
149
  throw new Error(
141
- `Unable to locate a matching operation in the supplied \`apiDefinition\` for: ${source.method} ${url}`,
150
+ `Unable to locate a matching operation in the supplied \`api.definition\` for: ${source.method} ${url}`,
142
151
  );
143
152
  }
144
153
 
145
- let sdkPackageName;
146
- let sdkVariable;
147
- if (opts.identifier) {
148
- sdkPackageName = opts.identifier;
149
- sdkVariable = opts.identifier;
154
+ let sdkPackageName: string | undefined;
155
+ let sdkVariable: string;
156
+ if (opts.api.identifier) {
157
+ sdkPackageName = opts.api.identifier;
158
+
159
+ sdkVariable = camelCase(opts.api.identifier);
160
+ if (isReservedOrBuiltinsLC(sdkVariable)) {
161
+ // If this identifier is a reserved JS word then we should prefix it with an underscore so
162
+ // this snippet can be valid code.
163
+ sdkVariable = `_${sdkVariable}`;
164
+ }
150
165
  } else {
151
- sdkPackageName = getProjectPrefixFromRegistryUUID(opts.apiDefinitionUri);
152
- sdkVariable = 'sdk';
166
+ sdkPackageName = getProjectPrefixFromRegistryUUID(opts.api.registryURI);
167
+ sdkVariable = camelCase(sdkPackageName || 'sdk');
153
168
  }
154
169
 
155
170
  const operationSlugs = foundOperation.url.slugs;
@@ -176,14 +191,14 @@ const client: Client<APIOptions> = {
176
191
  const serverVars = oas.splitVariables(baseUrl);
177
192
  const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;
178
193
 
179
- configData.push(`sdk.server('${serverUrl}');`);
194
+ configData.push(`${sdkVariable}.server('${serverUrl}');`);
180
195
  }
181
196
  }
182
197
 
183
- let metadata: Record<string, string | string[]> = {};
198
+ let metadata: Record<string, string[] | string> = {};
184
199
  Object.keys(queryObj).forEach(param => {
185
200
  if (authSources.query.includes(param)) {
186
- authData.push(buildAuthSnippet(queryObj[param]));
201
+ authData.push(buildAuthSnippet(sdkVariable, queryObj[param]));
187
202
 
188
203
  // If this query param is part of an auth source then we don't want it doubled up in the
189
204
  // snippet.
@@ -195,7 +210,7 @@ const client: Client<APIOptions> = {
195
210
 
196
211
  Object.keys(cookiesObj).forEach(cookie => {
197
212
  if (authSources.cookie.includes(cookie)) {
198
- authData.push(buildAuthSnippet(cookiesObj[cookie]));
213
+ authData.push(buildAuthSnippet(sdkVariable, cookiesObj[cookie]));
199
214
 
200
215
  // If this cookie is part of an auth source then we don't want it doubled up.
201
216
  return;
@@ -241,7 +256,7 @@ const client: Client<APIOptions> = {
241
256
  // into our auth data so we can build up an `.auth()` snippet for the SDK.
242
257
  const authScheme = authSources.header[headerLower];
243
258
  if (authScheme === '*') {
244
- authData.push(buildAuthSnippet(headers[header]));
259
+ authData.push(buildAuthSnippet(sdkVariable, headers[header]));
245
260
  } else {
246
261
  // @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.
247
262
  let authKey = headers[header].replace(`${authSources.header[headerLower]} `, '');
@@ -250,7 +265,7 @@ const client: Client<APIOptions> = {
250
265
  authKey = authKey.split(':');
251
266
  }
252
267
 
253
- authData.push(buildAuthSnippet(authKey));
268
+ authData.push(buildAuthSnippet(sdkVariable, authKey));
254
269
  }
255
270
 
256
271
  delete headers[header];
@@ -361,4 +376,9 @@ const client: Client<APIOptions> = {
361
376
  },
362
377
  };
363
378
 
364
- export default client;
379
+ const plugin: ClientPlugin<APIOptions> = {
380
+ target: 'node',
381
+ client,
382
+ };
383
+
384
+ export default plugin;
package/tsup.config.ts CHANGED
@@ -11,5 +11,15 @@ export default defineConfig((options: Options) => ({
11
11
  ...config,
12
12
 
13
13
  entry: ['src/index.ts'],
14
+
15
+ noExternal: [
16
+ // These dependencies are ESM-only but because we're building for ESM **and** CJS we can't
17
+ // treat them as external dependencies as CJS libraries can't load ESM code that uses `export`.
18
+ // `noExternal` will instead treeshake these dependencies down and include them in our compiled
19
+ // dists.
20
+ 'camelcase',
21
+ 'stringify-object',
22
+ ],
23
+
14
24
  silent: !options.watch,
15
25
  }));