@scalar/oas-utils 0.10.7 → 0.10.9

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 (129) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/entities/cookie/cookie.js +11 -15
  3. package/dist/entities/cookie/index.js +1 -5
  4. package/dist/entities/environment/environment.js +7 -11
  5. package/dist/entities/environment/index.js +1 -5
  6. package/dist/entities/hotkeys/hotkeys.js +116 -111
  7. package/dist/entities/hotkeys/index.js +1 -6
  8. package/dist/entities/shared/index.js +1 -7
  9. package/dist/entities/shared/utility.js +9 -9
  10. package/dist/entities/spec/collection.js +91 -89
  11. package/dist/entities/spec/index.js +10 -59
  12. package/dist/entities/spec/operation.js +6 -6
  13. package/dist/entities/spec/parameters.js +38 -38
  14. package/dist/entities/spec/request-examples.js +421 -331
  15. package/dist/entities/spec/requests.js +102 -84
  16. package/dist/entities/spec/server.js +61 -46
  17. package/dist/entities/spec/spec-objects.js +121 -76
  18. package/dist/entities/spec/x-scalar-environments.js +18 -20
  19. package/dist/entities/spec/x-scalar-secrets.js +6 -8
  20. package/dist/entities/workspace/index.js +1 -7
  21. package/dist/entities/workspace/workspace.js +47 -46
  22. package/dist/helpers/client-plugins.js +13 -13
  23. package/dist/helpers/fetch-document.js +30 -25
  24. package/dist/helpers/fetch-with-proxy-fallback.js +26 -21
  25. package/dist/helpers/index.d.ts +1 -2
  26. package/dist/helpers/index.d.ts.map +1 -1
  27. package/dist/helpers/index.js +80 -119
  28. package/dist/helpers/normalize-mime-type-object.js +19 -18
  29. package/dist/helpers/normalize-mime-type.js +11 -9
  30. package/dist/helpers/operation-stability.js +25 -20
  31. package/dist/helpers/parse.d.ts +0 -4
  32. package/dist/helpers/parse.d.ts.map +1 -1
  33. package/dist/helpers/parse.js +77 -77
  34. package/dist/helpers/schema-model.js +13 -16
  35. package/dist/helpers/security/get-schemes.js +7 -8
  36. package/dist/helpers/security/has-token.js +18 -19
  37. package/dist/helpers/security/index.js +2 -7
  38. package/dist/helpers/servers.js +128 -79
  39. package/dist/helpers/should-ignore-entity.js +4 -5
  40. package/dist/migrations/data-version.js +15 -7
  41. package/dist/migrations/generate-types.js +34 -37
  42. package/dist/migrations/index.js +4 -18
  43. package/dist/migrations/local-storage.js +31 -29
  44. package/dist/migrations/migrate-to-indexdb.js +706 -529
  45. package/dist/migrations/migrator.js +58 -54
  46. package/dist/migrations/semver.js +24 -24
  47. package/dist/migrations/v-0.0.0/types.generated.js +1 -1
  48. package/dist/migrations/v-2.1.0/migration.js +272 -258
  49. package/dist/migrations/v-2.1.0/types.generated.js +1 -1
  50. package/dist/migrations/v-2.2.0/migration.js +99 -96
  51. package/dist/migrations/v-2.2.0/types.generated.js +1 -1
  52. package/dist/migrations/v-2.3.0/migration.js +45 -48
  53. package/dist/migrations/v-2.3.0/types.generated.js +1 -1
  54. package/dist/migrations/v-2.4.0/migration.js +25 -25
  55. package/dist/migrations/v-2.4.0/types.generated.js +1 -1
  56. package/dist/migrations/v-2.5.0/migration.js +122 -139
  57. package/dist/migrations/v-2.5.0/types.generated.js +1 -1
  58. package/dist/spec-getters/get-example-from-schema.js +489 -385
  59. package/dist/spec-getters/get-parameters-from-operation.js +39 -23
  60. package/dist/spec-getters/get-request-body-from-operation.d.ts.map +1 -1
  61. package/dist/spec-getters/get-request-body-from-operation.js +168 -126
  62. package/dist/spec-getters/get-server-variable-examples.js +10 -13
  63. package/dist/spec-getters/index.js +4 -11
  64. package/dist/transforms/import-spec.js +381 -291
  65. package/dist/transforms/index.js +1 -11
  66. package/package.json +15 -19
  67. package/dist/entities/cookie/cookie.js.map +0 -7
  68. package/dist/entities/cookie/index.js.map +0 -7
  69. package/dist/entities/environment/environment.js.map +0 -7
  70. package/dist/entities/environment/index.js.map +0 -7
  71. package/dist/entities/hotkeys/hotkeys.js.map +0 -7
  72. package/dist/entities/hotkeys/index.js.map +0 -7
  73. package/dist/entities/shared/index.js.map +0 -7
  74. package/dist/entities/shared/utility.js.map +0 -7
  75. package/dist/entities/spec/collection.js.map +0 -7
  76. package/dist/entities/spec/index.js.map +0 -7
  77. package/dist/entities/spec/operation.js.map +0 -7
  78. package/dist/entities/spec/parameters.js.map +0 -7
  79. package/dist/entities/spec/request-examples.js.map +0 -7
  80. package/dist/entities/spec/requests.js.map +0 -7
  81. package/dist/entities/spec/server.js.map +0 -7
  82. package/dist/entities/spec/spec-objects.js.map +0 -7
  83. package/dist/entities/spec/x-scalar-environments.js.map +0 -7
  84. package/dist/entities/spec/x-scalar-secrets.js.map +0 -7
  85. package/dist/entities/workspace/index.js.map +0 -7
  86. package/dist/entities/workspace/workspace.js.map +0 -7
  87. package/dist/helpers/client-plugins.js.map +0 -7
  88. package/dist/helpers/fetch-document.js.map +0 -7
  89. package/dist/helpers/fetch-with-proxy-fallback.js.map +0 -7
  90. package/dist/helpers/index.js.map +0 -7
  91. package/dist/helpers/normalize-mime-type-object.js.map +0 -7
  92. package/dist/helpers/normalize-mime-type.js.map +0 -7
  93. package/dist/helpers/operation-stability.js.map +0 -7
  94. package/dist/helpers/parse.js.map +0 -7
  95. package/dist/helpers/pretty-print-json.d.ts +0 -9
  96. package/dist/helpers/pretty-print-json.d.ts.map +0 -1
  97. package/dist/helpers/pretty-print-json.js +0 -38
  98. package/dist/helpers/pretty-print-json.js.map +0 -7
  99. package/dist/helpers/schema-model.js.map +0 -7
  100. package/dist/helpers/security/get-schemes.js.map +0 -7
  101. package/dist/helpers/security/has-token.js.map +0 -7
  102. package/dist/helpers/security/index.js.map +0 -7
  103. package/dist/helpers/servers.js.map +0 -7
  104. package/dist/helpers/should-ignore-entity.js.map +0 -7
  105. package/dist/migrations/data-version.js.map +0 -7
  106. package/dist/migrations/generate-types.js.map +0 -7
  107. package/dist/migrations/index.js.map +0 -7
  108. package/dist/migrations/local-storage.js.map +0 -7
  109. package/dist/migrations/migrate-to-indexdb.js.map +0 -7
  110. package/dist/migrations/migrator.js.map +0 -7
  111. package/dist/migrations/semver.js.map +0 -7
  112. package/dist/migrations/v-0.0.0/types.generated.js.map +0 -7
  113. package/dist/migrations/v-2.1.0/migration.js.map +0 -7
  114. package/dist/migrations/v-2.1.0/types.generated.js.map +0 -7
  115. package/dist/migrations/v-2.2.0/migration.js.map +0 -7
  116. package/dist/migrations/v-2.2.0/types.generated.js.map +0 -7
  117. package/dist/migrations/v-2.3.0/migration.js.map +0 -7
  118. package/dist/migrations/v-2.3.0/types.generated.js.map +0 -7
  119. package/dist/migrations/v-2.4.0/migration.js.map +0 -7
  120. package/dist/migrations/v-2.4.0/types.generated.js.map +0 -7
  121. package/dist/migrations/v-2.5.0/migration.js.map +0 -7
  122. package/dist/migrations/v-2.5.0/types.generated.js.map +0 -7
  123. package/dist/spec-getters/get-example-from-schema.js.map +0 -7
  124. package/dist/spec-getters/get-parameters-from-operation.js.map +0 -7
  125. package/dist/spec-getters/get-request-body-from-operation.js.map +0 -7
  126. package/dist/spec-getters/get-server-variable-examples.js.map +0 -7
  127. package/dist/spec-getters/index.js.map +0 -7
  128. package/dist/transforms/import-spec.js.map +0 -7
  129. package/dist/transforms/index.js.map +0 -7
@@ -1,359 +1,449 @@
1
- import { isDefined } from "@scalar/helpers/array/is-defined";
2
- import { objectKeys } from "@scalar/helpers/object/object-keys";
3
- import { keysOf } from "@scalar/object-utils/arrays";
4
- import { nanoidSchema } from "@scalar/types/utils";
5
- import { z } from "zod";
6
- import { schemaModel } from "../../helpers/schema-model.js";
7
- import { getRequestBodyFromOperation } from "../../spec-getters/get-request-body-from-operation.js";
8
- import { getServerVariableExamples } from "../../spec-getters/get-server-variable-examples.js";
9
- const requestExampleParametersSchema = z.object({
10
- key: z.string().default(""),
11
- value: z.coerce.string().default(""),
12
- enabled: z.boolean().default(true),
13
- file: z.any().optional(),
14
- description: z.string().optional(),
15
- required: z.boolean().optional(),
16
- enum: z.array(z.string()).optional(),
17
- examples: z.array(z.any()).optional(),
18
- type: z.union([
19
- // 'string'
20
- z.string(),
21
- // ['string', 'null']
22
- z.array(z.string())
23
- ]).optional(),
24
- format: z.string().optional(),
25
- minimum: z.number().optional(),
26
- maximum: z.number().optional(),
27
- default: z.any().optional(),
28
- nullable: z.boolean().optional()
29
- }).transform((_data) => {
30
- const data = { ..._data };
31
- if (Array.isArray(data.type) && data.type.includes("null")) {
32
- data.nullable = true;
33
- }
34
- if (Array.isArray(data.type) && data.type.length === 2 && data.type.includes("null")) {
35
- data.type = data.type.find((item) => item !== "null");
36
- }
37
- return data;
1
+ import { isDefined } from '@scalar/helpers/array/is-defined';
2
+ import { objectKeys } from '@scalar/helpers/object/object-keys';
3
+ import { keysOf } from '@scalar/object-utils/arrays';
4
+ import { nanoidSchema } from '@scalar/types/utils';
5
+ import { z } from 'zod';
6
+ import { schemaModel } from '../../helpers/schema-model.js';
7
+ import { getRequestBodyFromOperation } from '../../spec-getters/get-request-body-from-operation.js';
8
+ import { getServerVariableExamples } from '../../spec-getters/get-server-variable-examples.js';
9
+ // ---------------------------------------------------------------------------
10
+ // Example Parameters
11
+ /**
12
+ * TODO: Deprecate this.
13
+ *
14
+ * The request schema should be stored in the request and any
15
+ * parameters should be validated against that
16
+ */
17
+ export const requestExampleParametersSchema = z
18
+ .object({
19
+ key: z.string().default(''),
20
+ value: z.coerce.string().default(''),
21
+ enabled: z.boolean().default(true),
22
+ file: z.any().optional(),
23
+ description: z.string().optional(),
24
+ required: z.boolean().optional(),
25
+ enum: z.array(z.string()).optional(),
26
+ examples: z.array(z.any()).optional(),
27
+ type: z
28
+ .union([
29
+ // 'string'
30
+ z.string(),
31
+ // ['string', 'null']
32
+ z.array(z.string()),
33
+ ])
34
+ .optional(),
35
+ format: z.string().optional(),
36
+ minimum: z.number().optional(),
37
+ maximum: z.number().optional(),
38
+ default: z.any().optional(),
39
+ nullable: z.boolean().optional(),
40
+ })
41
+ // set nullable: to true if type is ['string', 'null']
42
+ .transform((_data) => {
43
+ const data = { ..._data };
44
+ // type: ['string', 'null'] -> nullable: true
45
+ if (Array.isArray(data.type) && data.type.includes('null')) {
46
+ data.nullable = true;
47
+ }
48
+ // Hey, if it's just one value and 'null', we can make it a string and ditch the 'null'.
49
+ if (Array.isArray(data.type) && data.type.length === 2 && data.type.includes('null')) {
50
+ data.type = data.type.find((item) => item !== 'null');
51
+ }
52
+ return data;
38
53
  });
39
- const parameterArrayToObject = (params) => params.reduce((map, param) => {
40
- map[param.key] = param.value;
41
- return map;
54
+ /** Convert the array of parameters to an object keyed by the parameter name */
55
+ export const parameterArrayToObject = (params) => params.reduce((map, param) => {
56
+ map[param.key] = param.value;
57
+ return map;
42
58
  }, {});
43
- const xScalarFileValueSchema = z.object({
44
- url: z.string(),
45
- base64: z.string().optional()
46
- }).nullable();
59
+ const xScalarFileValueSchema = z
60
+ .object({
61
+ url: z.string(),
62
+ base64: z.string().optional(),
63
+ })
64
+ .nullable();
65
+ /**
66
+ * When files are required for an example we provide the options
67
+ * to provide a public URL or a base64 encoded string
68
+ */
69
+ // not used but kept for consistency
70
+ // export type XScalarFileValue = z.infer<typeof xScalarFileValueSchema>
71
+ /**
72
+ * Schema for the OAS serialization of request example parameters
73
+ *
74
+ * File values can be optionally fetched on import OR inserted as a base64 encoded string
75
+ */
47
76
  const xScalarFormDataValue = z.union([
48
- z.object({
49
- type: z.literal("string"),
50
- value: z.string()
51
- }),
52
- z.object({
53
- type: z.literal("file"),
54
- file: xScalarFileValueSchema
55
- })
77
+ z.object({
78
+ type: z.literal('string'),
79
+ value: z.string(),
80
+ }),
81
+ z.object({
82
+ type: z.literal('file'),
83
+ file: xScalarFileValueSchema,
84
+ }),
56
85
  ]);
57
- const exampleRequestBodyEncoding = ["json", "text", "html", "javascript", "xml", "yaml", "edn"];
86
+ // ---------------------------------------------------------------------------
87
+ // Example Body
88
+ /**
89
+ * Possible encodings for example request bodies when using text formats
90
+ *
91
+ * TODO: This list may not be comprehensive enough
92
+ */
93
+ const exampleRequestBodyEncoding = ['json', 'text', 'html', 'javascript', 'xml', 'yaml', 'edn'];
58
94
  const exampleBodyMime = [
59
- "application/json",
60
- "text/plain",
61
- "text/html",
62
- "application/javascript",
63
- "application/xml",
64
- "application/yaml",
65
- "application/edn",
66
- "application/octet-stream",
67
- "application/x-www-form-urlencoded",
68
- "multipart/form-data",
69
- /** Used for direct files */
70
- "binary"
95
+ 'application/json',
96
+ 'text/plain',
97
+ 'text/html',
98
+ 'application/javascript',
99
+ 'application/xml',
100
+ 'application/yaml',
101
+ 'application/edn',
102
+ 'application/octet-stream',
103
+ 'application/x-www-form-urlencoded',
104
+ 'multipart/form-data',
105
+ /** Used for direct files */
106
+ 'binary',
71
107
  ];
72
108
  const contentMapping = {
73
- json: "application/json",
74
- text: "text/plain",
75
- html: "text/html",
76
- javascript: "application/javascript",
77
- xml: "application/xml",
78
- yaml: "application/yaml",
79
- edn: "application/edn"
109
+ json: 'application/json',
110
+ text: 'text/plain',
111
+ html: 'text/html',
112
+ javascript: 'application/javascript',
113
+ xml: 'application/xml',
114
+ yaml: 'application/yaml',
115
+ edn: 'application/edn',
80
116
  };
117
+ /**
118
+ * TODO: Migrate away from this layout to the format used in the extension
119
+ *
120
+ * If a user changes the encoding of the body we expect the content to change as well
121
+ */
81
122
  const exampleRequestBodySchema = z.object({
82
- raw: z.object({
83
- encoding: z.enum(exampleRequestBodyEncoding),
84
- value: z.string().default(""),
85
- mimeType: z.string().optional()
86
- }).optional(),
87
- formData: z.object({
88
- encoding: z.union([z.literal("form-data"), z.literal("urlencoded")]).default("form-data"),
89
- value: requestExampleParametersSchema.array().default([])
90
- }).optional(),
91
- binary: z.instanceof(Blob).optional(),
92
- activeBody: z.union([z.literal("raw"), z.literal("formData"), z.literal("binary")]).default("raw")
123
+ raw: z
124
+ .object({
125
+ encoding: z.enum(exampleRequestBodyEncoding),
126
+ value: z.string().default(''),
127
+ mimeType: z.string().optional(),
128
+ })
129
+ .optional(),
130
+ formData: z
131
+ .object({
132
+ encoding: z.union([z.literal('form-data'), z.literal('urlencoded')]).default('form-data'),
133
+ value: requestExampleParametersSchema.array().default([]),
134
+ })
135
+ .optional(),
136
+ binary: z.instanceof(Blob).optional(),
137
+ activeBody: z.union([z.literal('raw'), z.literal('formData'), z.literal('binary')]).default('raw'),
93
138
  });
139
+ /** Schema for the OAS serialization of request example bodies */
94
140
  const xScalarExampleBodySchema = z.object({
95
- encoding: z.enum(exampleBodyMime),
96
- /**
97
- * Body content as an object with a separately specified encoding or a simple pre-encoded string value
98
- *
99
- * Ideally we would convert any objects into the proper encoding on import
100
- */
101
- content: z.union([z.record(z.string(), z.any()), z.string()]),
102
- /** When the encoding is `binary` this will be used to link to the file */
103
- file: xScalarFileValueSchema.optional()
141
+ encoding: z.enum(exampleBodyMime),
142
+ /**
143
+ * Body content as an object with a separately specified encoding or a simple pre-encoded string value
144
+ *
145
+ * Ideally we would convert any objects into the proper encoding on import
146
+ */
147
+ content: z.union([z.record(z.string(), z.any()), z.string()]),
148
+ /** When the encoding is `binary` this will be used to link to the file */
149
+ file: xScalarFileValueSchema.optional(),
104
150
  });
105
- const requestExampleSchema = z.object({
106
- uid: nanoidSchema.brand(),
107
- type: z.literal("requestExample").optional().default("requestExample"),
108
- requestUid: z.string().brand().optional(),
109
- name: z.string().optional().default("Name"),
110
- body: exampleRequestBodySchema.optional().default({ activeBody: "raw" }),
111
- parameters: z.object({
112
- path: requestExampleParametersSchema.array().default([]),
113
- query: requestExampleParametersSchema.array().default([]),
114
- headers: requestExampleParametersSchema.array().default([{ key: "Accept", value: "*/*", enabled: true }]),
115
- cookies: requestExampleParametersSchema.array().default([])
116
- }).optional().default({
117
- path: [],
118
- query: [],
119
- headers: [{ key: "Accept", value: "*/*", enabled: true }],
120
- cookies: []
121
- }),
122
- /** TODO: Should this be deprecated? */
123
- serverVariables: z.record(z.string(), z.array(z.string())).optional()
151
+ // ---------------------------------------------------------------------------
152
+ // Example Schema
153
+ export const requestExampleSchema = z.object({
154
+ uid: nanoidSchema.brand(),
155
+ type: z.literal('requestExample').optional().default('requestExample'),
156
+ requestUid: z.string().brand().optional(),
157
+ name: z.string().optional().default('Name'),
158
+ body: exampleRequestBodySchema.optional().default({ activeBody: 'raw' }),
159
+ parameters: z
160
+ .object({
161
+ path: requestExampleParametersSchema.array().default([]),
162
+ query: requestExampleParametersSchema.array().default([]),
163
+ headers: requestExampleParametersSchema.array().default([{ key: 'Accept', value: '*/*', enabled: true }]),
164
+ cookies: requestExampleParametersSchema.array().default([]),
165
+ })
166
+ .optional()
167
+ .default({
168
+ path: [],
169
+ query: [],
170
+ headers: [{ key: 'Accept', value: '*/*', enabled: true }],
171
+ cookies: [],
172
+ }),
173
+ /** TODO: Should this be deprecated? */
174
+ serverVariables: z.record(z.string(), z.array(z.string())).optional(),
124
175
  });
176
+ /** For OAS serialization we just store the simple key/value pairs */
125
177
  const xScalarExampleParameterSchema = z.record(z.string(), z.string()).optional();
126
- const xScalarExampleSchema = z.object({
127
- /** TODO: Should this be required? */
128
- name: z.string().optional(),
129
- body: xScalarExampleBodySchema.optional(),
130
- parameters: z.object({
131
- path: xScalarExampleParameterSchema,
132
- query: xScalarExampleParameterSchema,
133
- headers: xScalarExampleParameterSchema,
134
- cookies: xScalarExampleParameterSchema
135
- })
178
+ /** Schema for the OAS serialization of request examples */
179
+ export const xScalarExampleSchema = z.object({
180
+ /** TODO: Should this be required? */
181
+ name: z.string().optional(),
182
+ body: xScalarExampleBodySchema.optional(),
183
+ parameters: z.object({
184
+ path: xScalarExampleParameterSchema,
185
+ query: xScalarExampleParameterSchema,
186
+ headers: xScalarExampleParameterSchema,
187
+ cookies: xScalarExampleParameterSchema,
188
+ }),
136
189
  });
137
- function convertExampleToXScalar(example) {
138
- const active = example.body?.activeBody;
139
- const xScalarBody = {
140
- encoding: "text/plain",
141
- content: ""
142
- };
143
- if (example.body?.activeBody === "binary") {
144
- xScalarBody.encoding = "binary";
145
- xScalarBody.file = null;
146
- }
147
- if (active === "formData" && example.body?.[active]) {
148
- const body = example.body[active];
149
- xScalarBody.encoding = body.encoding === "form-data" ? "multipart/form-data" : "application/x-www-form-urlencoded";
150
- xScalarBody.content = body.value.reduce((map, param) => {
151
- map[param.key] = param.file ? {
152
- type: "file",
153
- file: null
154
- } : {
155
- type: "string",
156
- value: param.value
157
- };
158
- return map;
159
- }, {});
160
- }
161
- if (example.body?.activeBody === "raw") {
162
- xScalarBody.encoding = contentMapping[example.body.raw?.encoding ?? "text"] ?? "text/plain";
163
- xScalarBody.content = example.body.raw?.value ?? "";
164
- }
165
- const parameters = {};
166
- keysOf(example.parameters ?? {}).forEach((key) => {
167
- if (example.parameters?.[key].length) {
168
- parameters[key] = parameterArrayToObject(example.parameters[key]);
169
- }
170
- });
171
- return xScalarExampleSchema.parse({
172
- /** Only add the body if we have content or the body should be a file */
173
- body: xScalarBody.content || xScalarBody.encoding === "binary" ? xScalarBody : void 0,
174
- parameters
175
- });
176
- }
177
- function createParamInstance(param) {
178
- const schema = param.schema;
179
- const firstExample = (() => {
180
- if (param.examples && !Array.isArray(param.examples) && objectKeys(param.examples).length > 0) {
181
- const exampleValues = Object.entries(param.examples).map(([_, example2]) => {
182
- if (example2.externalValue) {
183
- return example2.externalValue;
184
- }
185
- return example2.value;
186
- });
187
- return { value: exampleValues[0], examples: exampleValues };
188
- }
189
- if (isDefined(param.example)) {
190
- return { value: param.example };
190
+ /**
191
+ * Convert a request example to the xScalar serialized format
192
+ *
193
+ * TODO: The base format should be migrated to align MUCH closer to the serialized format
194
+ */
195
+ export function convertExampleToXScalar(example) {
196
+ const active = example.body?.activeBody;
197
+ const xScalarBody = {
198
+ encoding: 'text/plain',
199
+ content: '',
200
+ };
201
+ if (example.body?.activeBody === 'binary') {
202
+ xScalarBody.encoding = 'binary';
203
+ // TODO: Need to allow users to set these properties
204
+ xScalarBody.file = null;
191
205
  }
192
- if (Array.isArray(param.examples) && param.examples.length > 0) {
193
- return { value: param.examples[0] };
206
+ if (active === 'formData' && example.body?.[active]) {
207
+ const body = example.body[active];
208
+ xScalarBody.encoding = body.encoding === 'form-data' ? 'multipart/form-data' : 'application/x-www-form-urlencoded';
209
+ // TODO: Need to allow users to set these properties
210
+ xScalarBody.content = body.value.reduce((map, param) => {
211
+ /** TODO: We need to ensure only file or value is set */
212
+ map[param.key] = param.file
213
+ ? {
214
+ type: 'file',
215
+ file: null,
216
+ }
217
+ : {
218
+ type: 'string',
219
+ value: param.value,
220
+ };
221
+ return map;
222
+ }, {});
194
223
  }
195
- if (isDefined(schema?.example)) {
196
- return { value: schema.example };
224
+ if (example.body?.activeBody === 'raw') {
225
+ xScalarBody.encoding = contentMapping[example.body.raw?.encoding ?? 'text'] ?? 'text/plain';
226
+ xScalarBody.content = example.body.raw?.value ?? '';
197
227
  }
198
- if (Array.isArray(schema?.examples) && schema.examples.length > 0) {
199
- if (schema?.type === "boolean") {
200
- return { value: schema.default ?? false };
201
- }
202
- return { value: schema.examples[0] };
203
- }
204
- if (param.content) {
205
- const firstContentType = objectKeys(param.content)[0];
206
- if (firstContentType) {
207
- const content = param.content[firstContentType];
208
- if (content?.examples) {
209
- const firstExampleKey = Object.keys(content.examples)[0];
210
- if (firstExampleKey) {
211
- const example2 = content.examples[firstExampleKey];
212
- if (isDefined(example2?.value)) {
213
- return { value: example2.value };
228
+ const parameters = {};
229
+ keysOf(example.parameters ?? {}).forEach((key) => {
230
+ if (example.parameters?.[key].length) {
231
+ parameters[key] = parameterArrayToObject(example.parameters[key]);
232
+ }
233
+ });
234
+ return xScalarExampleSchema.parse({
235
+ /** Only add the body if we have content or the body should be a file */
236
+ body: xScalarBody.content || xScalarBody.encoding === 'binary' ? xScalarBody : undefined,
237
+ parameters,
238
+ });
239
+ }
240
+ // ---------------------------------------------------------------------------
241
+ // Example Helpers
242
+ /** Create new instance parameter from a request parameter */
243
+ export function createParamInstance(param) {
244
+ const schema = param.schema;
245
+ const firstExample = (() => {
246
+ if (param.examples && !Array.isArray(param.examples) && objectKeys(param.examples).length > 0) {
247
+ const exampleValues = Object.entries(param.examples).map(([_, example]) => {
248
+ // returns the external value if it exists
249
+ if (example.externalValue) {
250
+ return example.externalValue;
251
+ }
252
+ // returns the value if it exists and is defined
253
+ // e.g. { examples: { foo: { value: 'bar' } } } would return ['bar']
254
+ return example.value;
255
+ });
256
+ // returns the first example as selected value along other examples
257
+ return { value: exampleValues[0], examples: exampleValues };
258
+ }
259
+ // param example e.g. { example: 'foo' }
260
+ if (isDefined(param.example)) {
261
+ return { value: param.example };
262
+ }
263
+ // param examples e.g. { examples: ['foo', 'bar'] }
264
+ if (Array.isArray(param.examples) && param.examples.length > 0) {
265
+ return { value: param.examples[0] };
266
+ }
267
+ // schema example e.g. { example: 'foo' } while being discouraged
268
+ // see https://spec.openapis.org/oas/v3.1.1.html#fixed-fields-20
269
+ if (isDefined(schema?.example)) {
270
+ return { value: schema.example };
271
+ }
272
+ // schema examples e.g. { examples: ['foo', 'bar'] }
273
+ if (Array.isArray(schema?.examples) && schema.examples.length > 0) {
274
+ // For boolean type, default to false when using schema examples
275
+ if (schema?.type === 'boolean') {
276
+ return { value: schema.default ?? false };
214
277
  }
215
- }
278
+ return { value: schema.examples[0] };
216
279
  }
217
- if (isDefined(content?.example)) {
218
- return { value: content.example };
280
+ // content examples e.g. { content: { 'application/json': { examples: { foo: { value: 'bar' } } } } }
281
+ if (param.content) {
282
+ const firstContentType = objectKeys(param.content)[0];
283
+ if (firstContentType) {
284
+ const content = param.content[firstContentType];
285
+ if (content?.examples) {
286
+ const firstExampleKey = Object.keys(content.examples)[0];
287
+ if (firstExampleKey) {
288
+ const example = content.examples[firstExampleKey];
289
+ if (isDefined(example?.value)) {
290
+ return { value: example.value };
291
+ }
292
+ }
293
+ }
294
+ // content example e.g. { example: 'foo' }
295
+ if (isDefined(content?.example)) {
296
+ return { value: content.example };
297
+ }
298
+ }
219
299
  }
220
- }
221
- }
222
- return null;
223
- })();
224
- const value = String(firstExample?.value ?? schema?.default ?? "");
225
- const parseEnum = (() => {
226
- if (schema?.enum && schema?.type !== "string") {
227
- return schema.enum?.map(String);
228
- }
229
- if (schema?.items?.enum && schema?.type === "array") {
230
- return schema.items.enum.map(String);
300
+ return null;
301
+ })();
302
+ /**
303
+ * TODO:
304
+ * - Need better value defaulting here
305
+ * - Need to handle non-string parameters much better
306
+ * - Need to handle unions/array values for schema
307
+ */
308
+ const value = String(firstExample?.value ?? schema?.default ?? '');
309
+ // Handle non-string enums and enums within items for array types
310
+ const parseEnum = (() => {
311
+ if (schema?.enum && schema?.type !== 'string') {
312
+ return schema.enum?.map(String);
313
+ }
314
+ if (schema?.items?.enum && schema?.type === 'array') {
315
+ return schema.items.enum.map(String);
316
+ }
317
+ return schema?.enum;
318
+ })();
319
+ // Handle parameter examples
320
+ const examples = firstExample?.examples ||
321
+ (schema?.examples && schema?.type !== 'string' ? schema.examples?.map(String) : schema?.examples);
322
+ // safe parse the example
323
+ const example = schemaModel({
324
+ ...schema,
325
+ key: param.name,
326
+ value,
327
+ description: param.description,
328
+ required: param.required,
329
+ /** Initialized all required properties to enabled */
330
+ enabled: !!param.required,
331
+ enum: parseEnum,
332
+ examples,
333
+ }, requestExampleParametersSchema, false);
334
+ if (!example) {
335
+ console.warn(`Example at ${param.name} is invalid.`);
336
+ return requestExampleParametersSchema.parse({});
231
337
  }
232
- return schema?.enum;
233
- })();
234
- const examples = firstExample?.examples || (schema?.examples && schema?.type !== "string" ? schema.examples?.map(String) : schema?.examples);
235
- const example = schemaModel(
236
- {
237
- ...schema,
238
- key: param.name,
239
- value,
240
- description: param.description,
241
- required: param.required,
242
- /** Initialized all required properties to enabled */
243
- enabled: !!param.required,
244
- enum: parseEnum,
245
- examples
246
- },
247
- requestExampleParametersSchema,
248
- false
249
- );
250
- if (!example) {
251
- console.warn(`Example at ${param.name} is invalid.`);
252
- return requestExampleParametersSchema.parse({});
253
- }
254
- return example;
338
+ return example;
255
339
  }
256
- function createExampleFromRequest(request, name, server) {
257
- const parameters = {
258
- path: [],
259
- query: [],
260
- cookie: [],
261
- // deprecated TODO: add zod transform to remove
262
- header: [],
263
- headers: [{ key: "Accept", value: "*/*", enabled: true }]
264
- };
265
- request.parameters?.forEach((p) => parameters[p.in].push(createParamInstance(p)));
266
- if (parameters.header.length > 0) {
267
- parameters.headers = parameters.header;
268
- parameters.header = [];
269
- }
270
- const contentTypeHeader = parameters.headers.find((h) => h.key.toLowerCase() === "content-type");
271
- const body = {
272
- activeBody: "raw"
273
- };
274
- if (request.requestBody || contentTypeHeader?.value) {
275
- const requestBody = getRequestBodyFromOperation(request);
276
- const contentType = request.requestBody ? requestBody?.mimeType : contentTypeHeader?.value;
277
- if (contentType?.includes("/json") || contentType?.endsWith("+json")) {
278
- body.activeBody = "raw";
279
- body.raw = {
280
- encoding: "json",
281
- mimeType: contentType,
282
- value: requestBody?.text ?? JSON.stringify({})
283
- };
284
- }
285
- if (contentType === "application/xml") {
286
- body.activeBody = "raw";
287
- body.raw = {
288
- encoding: "xml",
289
- value: requestBody?.text ?? ""
290
- };
291
- }
292
- if (contentType === "application/octet-stream") {
293
- body.activeBody = "binary";
294
- body.binary = void 0;
340
+ /**
341
+ * Create new request example from a request
342
+ * Iterates the name of the example if provided
343
+ */
344
+ export function createExampleFromRequest(request, name, server) {
345
+ // ---------------------------------------------------------------------------
346
+ // Populate all parameters with an example value
347
+ const parameters = {
348
+ path: [],
349
+ query: [],
350
+ cookie: [],
351
+ // deprecated TODO: add zod transform to remove
352
+ header: [],
353
+ headers: [{ key: 'Accept', value: '*/*', enabled: true }],
354
+ };
355
+ // Populated the separated params
356
+ request.parameters?.forEach((p) => parameters[p.in].push(createParamInstance(p)));
357
+ // TODO: add zod transform to remove header and only support headers
358
+ if (parameters.header.length > 0) {
359
+ parameters.headers = parameters.header;
360
+ parameters.header = [];
295
361
  }
296
- if (contentType === "application/x-www-form-urlencoded" || contentType === "multipart/form-data") {
297
- body.activeBody = "formData";
298
- body.formData = {
299
- encoding: contentType === "application/x-www-form-urlencoded" ? "urlencoded" : "form-data",
300
- value: (requestBody?.params || []).map((param) => {
301
- if (param.value instanceof File) {
302
- return {
303
- key: param.name,
304
- value: "BINARY",
305
- file: param.value,
306
- enabled: true
362
+ // Get content type header
363
+ const contentTypeHeader = parameters.headers.find((h) => h.key.toLowerCase() === 'content-type');
364
+ // ---------------------------------------------------------------------------
365
+ // Handle request body defaulting for various content type encodings
366
+ const body = {
367
+ activeBody: 'raw',
368
+ };
369
+ // If we have a request body or a content type header
370
+ // TODO: we don't even handle path parameters here
371
+ if (request.requestBody || contentTypeHeader?.value) {
372
+ const requestBody = getRequestBodyFromOperation(request);
373
+ const contentType = request.requestBody ? requestBody?.mimeType : contentTypeHeader?.value;
374
+ // Handle JSON and JSON-like mimetypes
375
+ if (contentType?.includes('/json') || contentType?.endsWith('+json')) {
376
+ body.activeBody = 'raw';
377
+ body.raw = {
378
+ encoding: 'json',
379
+ mimeType: contentType,
380
+ value: requestBody?.text ?? JSON.stringify({}),
307
381
  };
308
- }
309
- return {
310
- key: param.name,
311
- value: param.value || "",
312
- enabled: true
313
- };
314
- })
315
- };
316
- }
317
- if (contentType?.startsWith("text/")) {
318
- body.activeBody = "raw";
319
- body.raw = {
320
- encoding: "text",
321
- value: requestBody?.text ?? ""
322
- };
382
+ }
383
+ if (contentType === 'application/xml') {
384
+ body.activeBody = 'raw';
385
+ body.raw = {
386
+ encoding: 'xml',
387
+ value: requestBody?.text ?? '',
388
+ };
389
+ }
390
+ /**
391
+ * TODO: Are we loading example files from somewhere based on the spec?
392
+ * How are we handling the body values
393
+ */
394
+ if (contentType === 'application/octet-stream') {
395
+ body.activeBody = 'binary';
396
+ body.binary = undefined;
397
+ }
398
+ if (contentType === 'application/x-www-form-urlencoded' || contentType === 'multipart/form-data') {
399
+ body.activeBody = 'formData';
400
+ body.formData = {
401
+ encoding: contentType === 'application/x-www-form-urlencoded' ? 'urlencoded' : 'form-data',
402
+ value: (requestBody?.params || []).map((param) => {
403
+ if (param.value instanceof File) {
404
+ return {
405
+ key: param.name,
406
+ value: 'BINARY',
407
+ file: param.value,
408
+ enabled: true,
409
+ };
410
+ }
411
+ return {
412
+ key: param.name,
413
+ value: param.value || '',
414
+ enabled: true,
415
+ };
416
+ }),
417
+ };
418
+ }
419
+ if (contentType?.startsWith('text/')) {
420
+ body.activeBody = 'raw';
421
+ body.raw = {
422
+ encoding: 'text',
423
+ value: requestBody?.text ?? '',
424
+ };
425
+ }
426
+ // Add the content-type header if it doesn't exist and if it's not multipart request
427
+ if (requestBody?.mimeType && !contentTypeHeader && !requestBody.mimeType.startsWith('multipart/')) {
428
+ parameters.headers.push({
429
+ key: 'Content-Type',
430
+ value: requestBody.mimeType,
431
+ enabled: true,
432
+ });
433
+ }
323
434
  }
324
- if (requestBody?.mimeType && !contentTypeHeader && !requestBody.mimeType.startsWith("multipart/")) {
325
- parameters.headers.push({
326
- key: "Content-Type",
327
- value: requestBody.mimeType,
328
- enabled: true
329
- });
435
+ const serverVariables = server ? getServerVariableExamples(server) : {};
436
+ // safe parse the example
437
+ const example = schemaModel({
438
+ requestUid: request.uid,
439
+ parameters,
440
+ name,
441
+ body,
442
+ serverVariables,
443
+ }, requestExampleSchema, false);
444
+ if (!example) {
445
+ console.warn(`Example at ${request.uid} is invalid.`);
446
+ return requestExampleSchema.parse({});
330
447
  }
331
- }
332
- const serverVariables = server ? getServerVariableExamples(server) : {};
333
- const example = schemaModel(
334
- {
335
- requestUid: request.uid,
336
- parameters,
337
- name,
338
- body,
339
- serverVariables
340
- },
341
- requestExampleSchema,
342
- false
343
- );
344
- if (!example) {
345
- console.warn(`Example at ${request.uid} is invalid.`);
346
- return requestExampleSchema.parse({});
347
- }
348
- return example;
448
+ return example;
349
449
  }
350
- export {
351
- convertExampleToXScalar,
352
- createExampleFromRequest,
353
- createParamInstance,
354
- parameterArrayToObject,
355
- requestExampleParametersSchema,
356
- requestExampleSchema,
357
- xScalarExampleSchema
358
- };
359
- //# sourceMappingURL=request-examples.js.map