@gitbook/react-openapi 1.3.6 → 1.4.1

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/dist/types.d.ts CHANGED
@@ -1,12 +1,21 @@
1
- import type { OpenAPICustomOperationProperties, OpenAPICustomSpecProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
2
- export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & {
1
+ import type { OpenAPICustomOperationProperties, OpenAPICustomPrefillProperties, OpenAPICustomSpecProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ export type OpenAPIServerVariableWithCustomProperties = OpenAPIV3.ServerVariableObject & OpenAPICustomPrefillProperties;
3
+ /**
4
+ * OpenAPI ServerObject type extended to provide x-gitbook prefill custom properties at the variable level.
5
+ */
6
+ export type OpenAPIServerWithCustomProperties = Omit<OpenAPIV3.ServerObject, 'variables'> & {
7
+ variables?: {
8
+ [variable: string]: OpenAPIServerVariableWithCustomProperties;
9
+ };
10
+ } & OpenAPICustomPrefillProperties;
11
+ export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & OpenAPICustomPrefillProperties & {
3
12
  required?: boolean;
4
13
  };
5
14
  export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
6
15
  path: string;
7
16
  method: string;
8
17
  /** Servers to be used for this operation */
9
- servers: OpenAPIV3.ServerObject[];
18
+ servers: OpenAPIServerWithCustomProperties[];
10
19
  /** Spec of the operation */
11
20
  operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
12
21
  /** Securities that should be used for this operation */
@@ -0,0 +1,20 @@
1
+ import type { ApiClientConfiguration } from '@scalar/types';
2
+ import type { PrefillInputContextData } from '../OpenAPIPrefillContextProvider';
3
+ import type { OpenAPIOperationData } from '../types';
4
+ export interface TryItPrefillConfiguration {
5
+ authentication?: ApiClientConfiguration['authentication'];
6
+ servers?: ApiClientConfiguration['servers'];
7
+ }
8
+ /**
9
+ * Resolve the Scalar API client prefill configuration for a given OpenAPI operation.
10
+ */
11
+ export declare function resolveTryItPrefillForOperation(args: {
12
+ /**
13
+ * The parsed OpenAPI operation.
14
+ */
15
+ operation: Pick<OpenAPIOperationData, 'securities' | 'servers'>;
16
+ /**
17
+ * Prefill input context data.
18
+ */
19
+ prefillInputContext: PrefillInputContextData | null;
20
+ }): TryItPrefillConfiguration;
@@ -0,0 +1,129 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ import { ExpressionRuntime, parseTemplate } from '@gitbook/expr';
24
+ /**
25
+ * Resolve the Scalar API client prefill configuration for a given OpenAPI operation.
26
+ */
27
+ export function resolveTryItPrefillForOperation(args) {
28
+ var _a = args.operation, securities = _a.securities, servers = _a.servers, prefillInputContext = args.prefillInputContext;
29
+ if (!prefillInputContext) {
30
+ return {};
31
+ }
32
+ var runtime = new ExpressionRuntime();
33
+ var resolveTryItPrefillExpression = function (expr) {
34
+ var parts = parseTemplate(expr);
35
+ if (!parts.length) {
36
+ return undefined;
37
+ }
38
+ return runtime.evaluateTemplate(expr, prefillInputContext);
39
+ };
40
+ var prefillAuth = securities
41
+ ? resolveTryItPrefillAuthForOperationSecurities({
42
+ securities: securities,
43
+ resolveTryItPrefillExpression: resolveTryItPrefillExpression,
44
+ })
45
+ : undefined;
46
+ var prefillServers = servers
47
+ ? resolveTryItPrefillServersForOperationServers({ servers: servers, resolveTryItPrefillExpression: resolveTryItPrefillExpression })
48
+ : [];
49
+ return __assign(__assign({}, (prefillAuth ? { authentication: prefillAuth } : {})), (prefillServers ? { servers: prefillServers } : {}));
50
+ }
51
+ /**
52
+ * Resolve prefill authentication configuration for the security schemes defined for an operation.
53
+ */
54
+ function resolveTryItPrefillAuthForOperationSecurities(args) {
55
+ var _a, _b;
56
+ var securities = args.securities, resolveTryItPrefillExpression = args.resolveTryItPrefillExpression;
57
+ var prefillAuthConfig = {};
58
+ for (var _i = 0, _c = Object.values(securities); _i < _c.length; _i++) {
59
+ var _d = _c[_i], schemeName = _d[0], security = _d[1];
60
+ var tryitPrefillAuthValue = security['x-gitbook-prefill']
61
+ ? resolveTryItPrefillExpression(security['x-gitbook-prefill'])
62
+ : undefined;
63
+ if (!tryitPrefillAuthValue) {
64
+ continue;
65
+ }
66
+ switch (security.type) {
67
+ case 'http': {
68
+ if ((_a = security.scheme) === null || _a === void 0 ? void 0 : _a.includes('bearer')) {
69
+ prefillAuthConfig[schemeName] = { token: tryitPrefillAuthValue };
70
+ }
71
+ else if (((_b = security.scheme) === null || _b === void 0 ? void 0 : _b.includes('basic')) &&
72
+ tryitPrefillAuthValue.includes(':')) {
73
+ var _e = tryitPrefillAuthValue.split(':', 2), username = _e[0], password = _e[1];
74
+ prefillAuthConfig[schemeName] = { username: username, password: password };
75
+ }
76
+ break;
77
+ }
78
+ case 'apiKey': {
79
+ prefillAuthConfig[schemeName] = {
80
+ name: security.name,
81
+ in: security.in,
82
+ value: tryitPrefillAuthValue,
83
+ };
84
+ break;
85
+ }
86
+ case 'oauth2':
87
+ case 'openIdConnect': {
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ return Object.keys(prefillAuthConfig).length > 0
93
+ ? { securitySchemes: prefillAuthConfig }
94
+ : undefined;
95
+ }
96
+ /**
97
+ * Resolve prefill server configuration for the servers defined for an operation.
98
+ */
99
+ function resolveTryItPrefillServersForOperationServers(args) {
100
+ var servers = args.servers, resolveTryItPrefillExpression = args.resolveTryItPrefillExpression;
101
+ var resolvedServers = [];
102
+ for (var _i = 0, servers_1 = servers; _i < servers_1.length; _i++) {
103
+ var server = servers_1[_i];
104
+ // Url-level prefill
105
+ var tryItPrefillServerUrlExpr = server['x-gitbook-prefill'];
106
+ var tryItPrefillServerUrlValue = tryItPrefillServerUrlExpr
107
+ ? resolveTryItPrefillExpression(tryItPrefillServerUrlExpr)
108
+ : undefined;
109
+ var variables = server.variables
110
+ ? __assign({}, server.variables) : {};
111
+ // Variable-level prefill
112
+ if (server.variables) {
113
+ for (var _a = 0, _b = Object.entries(server.variables); _a < _b.length; _a++) {
114
+ var _c = _b[_a], varName = _c[0], variable = _c[1];
115
+ var tryItPrefillVarExpr = variable["x-gitbook-prefill"], variableProps = __rest(variable, ['x-gitbook-prefill']);
116
+ var tryItPrefillVarValue = tryItPrefillVarExpr
117
+ ? resolveTryItPrefillExpression(tryItPrefillVarExpr)
118
+ : undefined;
119
+ variables[varName] = __assign(__assign({}, variableProps), (tryItPrefillVarValue ? { default: String(tryItPrefillVarValue) } : {}));
120
+ }
121
+ }
122
+ var hasServerVariables = Object.keys(variables).length > 0;
123
+ if (server.url && (tryItPrefillServerUrlValue || hasServerVariables)) {
124
+ var resolvedServer = __assign(__assign({ url: tryItPrefillServerUrlValue !== null && tryItPrefillServerUrlValue !== void 0 ? tryItPrefillServerUrlValue : server.url }, (server.description ? { description: server.description } : {})), (hasServerVariables ? { variables: variables } : {}));
125
+ resolvedServers.push(resolvedServer);
126
+ }
127
+ }
128
+ return resolvedServers.length > 0 ? resolvedServers : undefined;
129
+ }
package/package.json CHANGED
@@ -8,21 +8,25 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.3.6",
11
+ "version": "1.4.1",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
+ "@gitbook/expr": "workspace:*",
14
15
  "@gitbook/openapi-parser": "workspace:*",
15
16
  "@scalar/api-client-react": "^1.3.16",
16
17
  "@scalar/oas-utils": "^0.2.130",
18
+ "@scalar/types": "^0.1.9",
17
19
  "clsx": "^2.1.1",
18
20
  "flatted": "^3.2.9",
19
21
  "json-xml-parse": "^1.3.0",
20
22
  "react-aria-components": "^1.6.0",
21
23
  "react-aria": "^3.37.0",
22
24
  "usehooks-ts": "^3.1.0",
23
- "zustand": "^5.0.3"
25
+ "zustand": "^5.0.3",
26
+ "js-yaml": "^4.1.0"
24
27
  },
25
28
  "devDependencies": {
29
+ "@types/js-yaml": "^4.0.9",
26
30
  "bun-types": "^1.1.20",
27
31
  "typescript": "^5.5.3"
28
32
  },
@@ -112,7 +112,7 @@ export function InteractiveSection(props: {
112
112
  event.stopPropagation();
113
113
  }}
114
114
  >
115
- {tabs.length > 1 ? (
115
+ {tabs.length > 0 ? (
116
116
  <OpenAPISelect
117
117
  stateKey={stateKey}
118
118
  items={tabs}
@@ -66,7 +66,11 @@ function generateCodeSamples(props: {
66
66
  const searchParams = new URLSearchParams();
67
67
  const headersObject: { [k: string]: string } = {};
68
68
 
69
- data.operation.parameters?.forEach((param) => {
69
+ // The parser can sometimes returns invalid parameters (an object instead of an array).
70
+ // It should get fixed in scalar, but in the meantime we just ignore the parameters in that case.
71
+ const params = Array.isArray(data.operation.parameters) ? data.operation.parameters : [];
72
+
73
+ params.forEach((param) => {
70
74
  if (!param) {
71
75
  return;
72
76
  }
@@ -194,7 +198,7 @@ function OpenAPICodeSampleFooter(props: {
194
198
  context: OpenAPIContext;
195
199
  }) {
196
200
  const { data, context, renderers } = props;
197
- const { method, path } = data;
201
+ const { method, path, securities, servers } = data;
198
202
  const { specUrl } = context;
199
203
  const hideTryItPanel = data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'];
200
204
  const hasMultipleMediaTypes =
@@ -226,6 +230,8 @@ function OpenAPICodeSampleFooter(props: {
226
230
  context={getOpenAPIClientContext(context)}
227
231
  method={method}
228
232
  path={path}
233
+ securities={securities}
234
+ servers={servers}
229
235
  specUrl={specUrl}
230
236
  />
231
237
  )}
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+
5
+ /**
6
+ * Prefill data that can be used to dynamically inject info into OpenAPI operation blocks.
7
+ *
8
+ * This is typically dynamic input context, such as visitor data or environment info.
9
+ */
10
+ export type PrefillInputContextData = Record<string, unknown>;
11
+
12
+ /**
13
+ * Context value is function that returns prefill data.
14
+ */
15
+ type PrefillContextValue = () => PrefillInputContextData | null;
16
+
17
+ const OpenAPIPrefillContext = React.createContext<PrefillContextValue | null>(null);
18
+
19
+ /**
20
+ * Provide context to help prefill dynamic info like visitor data in OpenAPI blocks.
21
+ */
22
+ export function OpenAPIPrefillContextProvider(
23
+ props: React.PropsWithChildren<{
24
+ getPrefillInputContextData: () => PrefillInputContextData | null;
25
+ }>
26
+ ) {
27
+ const { getPrefillInputContextData, children } = props;
28
+ return (
29
+ <OpenAPIPrefillContext.Provider value={getPrefillInputContextData}>
30
+ {children}
31
+ </OpenAPIPrefillContext.Provider>
32
+ );
33
+ }
34
+
35
+ /**
36
+ * Hook to access the prefill context function.
37
+ */
38
+ export function useOpenAPIPrefillContext(): PrefillContextValue {
39
+ return React.useContext(OpenAPIPrefillContext) ?? (() => null);
40
+ }
@@ -42,7 +42,13 @@ export function OpenAPIResponseExample(props: {
42
42
  });
43
43
 
44
44
  const tabs = responses
45
- .filter(([_, responseObject]) => responseObject && typeof responseObject === 'object')
45
+ .filter(
46
+ ([_, responseObject]) =>
47
+ responseObject &&
48
+ typeof responseObject === 'object' &&
49
+ // Make sure the response is not hidden
50
+ !responseObject['x-hideSample']
51
+ )
46
52
  .map(([key, responseObject]) => {
47
53
  const description = resolveDescription(responseObject);
48
54
  const label = description ? (
@@ -50,6 +50,20 @@ export function OpenAPIResponses(props: {
50
50
  ];
51
51
  }
52
52
 
53
+ if (!response.content) {
54
+ return [
55
+ {
56
+ key: 'default',
57
+ label: '',
58
+ body: (
59
+ <pre className="openapi-example-empty">
60
+ <p>{t(context.translation, 'no_content')}</p>
61
+ </pre>
62
+ ),
63
+ },
64
+ ];
65
+ }
66
+
53
67
  return Object.entries(response.content ?? {}).map(([contentType, mediaType]) => ({
54
68
  key: contentType,
55
69
  label: contentType,
@@ -117,19 +117,22 @@ function getParameterGroupName(paramIn: string, context: OpenAPIClientContext):
117
117
  /** Deduplicate parameters by name and in.
118
118
  * Some specs have both parameters define at path and operation level.
119
119
  * We only want to display one of them.
120
+ * Parameters can have the wrong type (object instead of array) sometimes, we just return an empty array in that case.
120
121
  */
121
122
  function deduplicateParameters(parameters: OpenAPI.Parameters): OpenAPI.Parameters {
122
123
  const seen = new Set();
123
124
 
124
- return parameters.filter((param) => {
125
- const key = `${param.name}:${param.in}`;
125
+ return Array.isArray(parameters)
126
+ ? parameters.filter((param) => {
127
+ const key = `${param.name}:${param.in}`;
126
128
 
127
- if (seen.has(key)) {
128
- return false;
129
- }
129
+ if (seen.has(key)) {
130
+ return false;
131
+ }
130
132
 
131
- seen.add(key);
133
+ seen.add(key);
132
134
 
133
- return true;
134
- });
135
+ return true;
136
+ })
137
+ : [];
135
138
  }
@@ -1,13 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import { ApiClientModalProvider, useApiClientModal } from '@scalar/api-client-react';
4
- import { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
4
+ import { Suspense, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
 
7
7
  import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
8
8
  import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
9
+ import { useOpenAPIPrefillContext } from './OpenAPIPrefillContextProvider';
9
10
  import type { OpenAPIClientContext } from './context';
10
11
  import { t } from './translate';
12
+ import type { OpenAPIOperationData } from './types';
13
+ import { resolveTryItPrefillForOperation } from './util/tryit-prefill';
11
14
 
12
15
  /**
13
16
  * Button which launches the Scalar API Client
@@ -15,12 +18,15 @@ import { t } from './translate';
15
18
  export function ScalarApiButton(props: {
16
19
  method: OpenAPIV3_1.HttpMethods;
17
20
  path: string;
21
+ securities: OpenAPIOperationData['securities'];
22
+ servers: OpenAPIOperationData['servers'];
18
23
  specUrl: string;
19
24
  context: OpenAPIClientContext;
20
25
  }) {
21
- const { method, path, specUrl, context } = props;
26
+ const { method, path, securities, servers, specUrl, context } = props;
22
27
  const [isOpen, setIsOpen] = useState(false);
23
28
  const controllerRef = useRef<ScalarModalControllerRef>(null);
29
+
24
30
  return (
25
31
  <div className="scalar scalar-activate">
26
32
  <button
@@ -42,12 +48,16 @@ export function ScalarApiButton(props: {
42
48
 
43
49
  {isOpen &&
44
50
  createPortal(
45
- <ScalarModal
46
- controllerRef={controllerRef}
47
- method={method}
48
- path={path}
49
- specUrl={specUrl}
50
- />,
51
+ <Suspense fallback={null}>
52
+ <ScalarModal
53
+ controllerRef={controllerRef}
54
+ method={method}
55
+ path={path}
56
+ securities={securities}
57
+ servers={servers}
58
+ specUrl={specUrl}
59
+ />
60
+ </Suspense>,
51
61
  document.body
52
62
  )}
53
63
  </div>
@@ -57,12 +67,26 @@ export function ScalarApiButton(props: {
57
67
  function ScalarModal(props: {
58
68
  method: OpenAPIV3_1.HttpMethods;
59
69
  path: string;
70
+ securities: OpenAPIOperationData['securities'];
71
+ servers: OpenAPIOperationData['servers'];
60
72
  specUrl: string;
61
73
  controllerRef: React.Ref<ScalarModalControllerRef>;
62
74
  }) {
63
- const { method, path, specUrl, controllerRef } = props;
75
+ const { method, path, securities, servers, specUrl, controllerRef } = props;
76
+
77
+ const getPrefillInputContextData = useOpenAPIPrefillContext();
78
+ const prefillInputContext = getPrefillInputContextData();
79
+
80
+ const prefillConfig = resolveTryItPrefillForOperation({
81
+ operation: { securities, servers },
82
+ prefillInputContext,
83
+ });
84
+
64
85
  return (
65
- <ApiClientModalProvider configuration={{ url: specUrl }} initialRequest={{ method, path }}>
86
+ <ApiClientModalProvider
87
+ configuration={{ url: specUrl, ...prefillConfig }}
88
+ initialRequest={{ method, path }}
89
+ >
66
90
  <ScalarModalController method={method} path={path} controllerRef={controllerRef} />
67
91
  </ApiClientModalProvider>
68
92
  );
@@ -84,7 +108,11 @@ function ScalarModalController(props: {
84
108
  const openClient = useMemo(() => {
85
109
  if (openScalarClient) {
86
110
  return () => {
87
- openScalarClient({ method, path, _source: 'gitbook' });
111
+ openScalarClient({
112
+ method,
113
+ path,
114
+ _source: 'gitbook',
115
+ });
88
116
  trackClientOpening({ method, path });
89
117
  };
90
118
  }
@@ -406,7 +406,7 @@ describe('python code sample generator', () => {
406
406
 
407
407
  it('should format application/json body properly', () => {
408
408
  const input: CodeSampleInput = {
409
- method: 'GET',
409
+ method: 'POST',
410
410
  url: 'https://example.com/path',
411
411
  headers: {
412
412
  'Content-Type': 'application/json',
@@ -422,7 +422,7 @@ describe('python code sample generator', () => {
422
422
  const output = generator?.generate(input);
423
423
 
424
424
  expect(output).toBe(
425
- 'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data=json.dumps({\n "key": "value",\n "truethy": True,\n "falsey": False,\n "nullish": None\n })\n)\n\ndata = response.json()'
425
+ 'import json\nimport requests\n\nresponse = requests.post(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data=json.dumps({\n "key": "value",\n "truethy": True,\n "falsey": False,\n "nullish": None\n })\n)\n\ndata = response.json()'
426
426
  );
427
427
  });
428
428
 
@@ -1,3 +1,4 @@
1
+ import yaml from 'js-yaml';
1
2
  import {
2
3
  isCSV,
3
4
  isFormData,
@@ -8,6 +9,7 @@ import {
8
9
  isPlainObject,
9
10
  isText,
10
11
  isXML,
12
+ isYAML,
11
13
  } from './contentTypeChecks';
12
14
  import { json2xml } from './json2xml';
13
15
  import { stringifyOpenAPI } from './stringifyOpenAPI';
@@ -154,7 +156,8 @@ ${headerString}${bodyString}`;
154
156
  label: 'Python',
155
157
  syntax: 'python',
156
158
  generate: ({ method, url, headers, body }) => {
157
- let code = 'import requests\n\n';
159
+ const contentType = headers?.['Content-Type'];
160
+ let code = `${isJSON(contentType) ? 'import json\n' : ''}import requests\n\n`;
158
161
 
159
162
  if (body) {
160
163
  const lines = BodyGenerators.getPythonBody(body, headers);
@@ -174,7 +177,6 @@ ${headerString}${bodyString}`;
174
177
  code += indent(`headers=${stringifyOpenAPI(headers)},\n`, 4);
175
178
  }
176
179
 
177
- const contentType = headers?.['Content-Type'];
178
180
  if (body) {
179
181
  if (body === 'files') {
180
182
  code += indent(`files=${body}\n`, 4);
@@ -256,6 +258,8 @@ const BodyGenerators = {
256
258
  } else if (isPDF(contentType)) {
257
259
  // We use --data-binary to avoid cURL converting newlines to \r\n
258
260
  body = `--data-binary '@${String(body)}'`;
261
+ } else if (isYAML(contentType)) {
262
+ body = `--data-binary $'${yaml.dump(body).replace(/'/g, '').replace(/\\n/g, '\n')}'`;
259
263
  } else {
260
264
  body = `--data '${stringifyOpenAPI(body, null, 2).replace(/\\n/g, '\n')}'`;
261
265
  }
@@ -325,6 +329,9 @@ const BodyGenerators = {
325
329
  code += indent(convertBodyToXML(body), 4);
326
330
  code += '`;\n\n';
327
331
  body = 'xml';
332
+ } else if (isYAML(contentType)) {
333
+ code += `const yamlBody = \`\n${indent(yaml.dump(body), 4)}\`;\n\n`;
334
+ body = 'yamlBody';
328
335
  } else if (isText(contentType)) {
329
336
  body = stringifyOpenAPI(body, null, 2);
330
337
  } else {
@@ -355,6 +362,9 @@ const BodyGenerators = {
355
362
  } else if (isXML(contentType)) {
356
363
  // Convert JSON to XML if needed
357
364
  body = JSON.stringify(convertBodyToXML(body));
365
+ } else if (isYAML(contentType)) {
366
+ code += `yamlBody = \"\"\"\n${indent(yaml.dump(body), 4)}\"\"\"\n\n`;
367
+ body = 'yamlBody';
358
368
  } else {
359
369
  body = stringifyOpenAPI(
360
370
  body,
@@ -399,6 +409,7 @@ const BodyGenerators = {
399
409
  // Convert JSON to XML if needed
400
410
  return `"${convertBodyToXML(body)}"`;
401
411
  },
412
+ yaml: () => `"${yaml.dump(body).replace(/"/g, '\\"')}"`,
402
413
  csv: () => `"${stringifyOpenAPI(body).replace(/"/g, '')}"`,
403
414
  default: () => `${stringifyOpenAPI(body, null, 2)}`,
404
415
  };
@@ -407,6 +418,7 @@ const BodyGenerators = {
407
418
  if (isFormUrlEncoded(contentType)) return typeHandlers.formUrlEncoded();
408
419
  if (isText(contentType)) return typeHandlers.text();
409
420
  if (isXML(contentType)) return typeHandlers.xml();
421
+ if (isYAML(contentType)) return typeHandlers.yaml();
410
422
  if (isCSV(contentType)) return typeHandlers.csv();
411
423
 
412
424
  return typeHandlers.default();
@@ -6,6 +6,10 @@ export function isXML(contentType?: string): boolean {
6
6
  return contentType?.toLowerCase().includes('application/xml') || false;
7
7
  }
8
8
 
9
+ export function isYAML(contentType?: string): boolean {
10
+ return contentType?.toLowerCase().includes('application/yaml') || false;
11
+ }
12
+
9
13
  export function isGraphQL(contentType?: string): boolean {
10
14
  return contentType?.toLowerCase().includes('application/graphql') || false;
11
15
  }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from './schemas';
2
2
  export * from './OpenAPIOperation';
3
3
  export * from './OpenAPIWebhook';
4
4
  export * from './OpenAPIOperationContext';
5
+ export * from './OpenAPIPrefillContextProvider';
5
6
  export * from './resolveOpenAPIOperation';
6
7
  export * from './resolveOpenAPIWebhook';
7
8
  export type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
package/src/types.ts CHANGED
@@ -1,17 +1,31 @@
1
1
  import type {
2
2
  OpenAPICustomOperationProperties,
3
+ OpenAPICustomPrefillProperties,
3
4
  OpenAPICustomSpecProperties,
4
5
  OpenAPIV3,
5
6
  } from '@gitbook/openapi-parser';
6
7
 
7
- export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
8
+ export type OpenAPIServerVariableWithCustomProperties = OpenAPIV3.ServerVariableObject &
9
+ OpenAPICustomPrefillProperties;
10
+
11
+ /**
12
+ * OpenAPI ServerObject type extended to provide x-gitbook prefill custom properties at the variable level.
13
+ */
14
+ export type OpenAPIServerWithCustomProperties = Omit<OpenAPIV3.ServerObject, 'variables'> & {
15
+ variables?: {
16
+ [variable: string]: OpenAPIServerVariableWithCustomProperties;
17
+ };
18
+ } & OpenAPICustomPrefillProperties;
19
+
20
+ export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject &
21
+ OpenAPICustomPrefillProperties & { required?: boolean };
8
22
 
9
23
  export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
10
24
  path: string;
11
25
  method: string;
12
26
 
13
27
  /** Servers to be used for this operation */
14
- servers: OpenAPIV3.ServerObject[];
28
+ servers: OpenAPIServerWithCustomProperties[];
15
29
 
16
30
  /** Spec of the operation */
17
31
  operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;