oas 20.8.9 → 20.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.
@@ -1,3 +1,4 @@
1
1
  import type { SchemaObject } from 'rmoas.types';
2
2
  export declare function hasSchemaType(schema: SchemaObject, discriminator: 'array' | 'object'): boolean;
3
+ export declare function isObject(val: unknown): boolean;
3
4
  export declare function isPrimitive(val: unknown): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPrimitive = exports.hasSchemaType = void 0;
3
+ exports.isPrimitive = exports.isObject = exports.hasSchemaType = void 0;
4
4
  function hasSchemaType(schema, discriminator) {
5
5
  if (Array.isArray(schema.type)) {
6
6
  return schema.type.includes(discriminator);
@@ -8,6 +8,10 @@ function hasSchemaType(schema, discriminator) {
8
8
  return schema.type === discriminator;
9
9
  }
10
10
  exports.hasSchemaType = hasSchemaType;
11
+ function isObject(val) {
12
+ return typeof val === 'object' && val !== null && !Array.isArray(val);
13
+ }
14
+ exports.isObject = isObject;
11
15
  function isPrimitive(val) {
12
16
  return typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean';
13
17
  }
@@ -1,5 +1,4 @@
1
1
  import * as RMOAS from '../rmoas.types';
2
- type PrevSchemasType = RMOAS.SchemaObject[];
3
2
  export interface toJSONSchemaOptions {
4
3
  /**
5
4
  * Whether or not to extend descriptions with a list of any present enums.
@@ -26,9 +25,13 @@ export interface toJSONSchemaOptions {
26
25
  */
27
26
  isPolymorphicAllOfChild?: boolean;
28
27
  /**
29
- * Array of parent schemas to utilize when attempting to path together examples.
28
+ * Array of parent `default` schemas to utilzie when attempting to path together schema defaults.
30
29
  */
31
- prevSchemas?: PrevSchemasType;
30
+ prevDefaultSchemas?: RMOAS.SchemaObject[];
31
+ /**
32
+ * Array of parent `example` schemas to utilize when attempting to path together schema examples.
33
+ */
34
+ prevExampleSchemas?: RMOAS.SchemaObject[];
32
35
  /**
33
36
  * A function that's called anytime a (circular) `$ref` is found.
34
37
  */
@@ -78,4 +81,3 @@ export declare function getSchemaVersionString(schema: RMOAS.SchemaObject, api:
78
81
  * @param data OpenAPI Schema Object to convert to pure JSON Schema.
79
82
  */
80
83
  export default function toJSONSchema(data: RMOAS.SchemaObject | boolean, opts?: toJSONSchemaOptions): RMOAS.SchemaObject;
81
- export {};
@@ -141,8 +141,8 @@ function isRequestBodySchema(schema) {
141
141
  return 'content' in schema;
142
142
  }
143
143
  /**
144
- * Given a JSON pointer and an array of examples do a reverse search through them until we find the
145
- * JSON pointer, or part of it, within the array.
144
+ * Given a JSON pointer, a type of property to look for, and an array of schemas do a reverse
145
+ * search through them until we find the JSON pointer, or part of it, within the array.
146
146
  *
147
147
  * This function will allow you to take a pointer like `/tags/name` and return back `buster` from
148
148
  * the following array:
@@ -170,12 +170,13 @@ function isRequestBodySchema(schema) {
170
170
  * it shouldn't raise immediate cause for alarm.
171
171
  *
172
172
  * @see {@link https://tools.ietf.org/html/rfc6901}
173
+ * @param property Specific type of schema property to look for a value for.
173
174
  * @param pointer JSON pointer to search for an example for.
174
- * @param examples Array of previous schemas we've found relating to this pointer.
175
+ * @param schemas Array of previous schemas we've found relating to this pointer.
175
176
  */
176
- function searchForExampleByPointer(pointer, examples) {
177
- if (examples === void 0) { examples = []; }
178
- if (!examples.length || !pointer.length) {
177
+ function searchForValueByPropAndPointer(property, pointer, schemas) {
178
+ if (schemas === void 0) { schemas = []; }
179
+ if (!schemas.length || !pointer.length) {
179
180
  return undefined;
180
181
  }
181
182
  var locSplit = pointer.split('/').filter(Boolean).reverse();
@@ -185,38 +186,43 @@ function searchForExampleByPointer(pointer, examples) {
185
186
  point = "/".concat(locSplit[i]).concat(point);
186
187
  pointers.push(point);
187
188
  }
188
- var example;
189
- var rev = __spreadArray([], examples, true).reverse();
189
+ var foundValue;
190
+ var rev = __spreadArray([], schemas, true).reverse();
190
191
  for (var i = 0; i < pointers.length; i += 1) {
191
192
  for (var ii = 0; ii < rev.length; ii += 1) {
192
193
  var schema = rev[ii];
193
- if ('example' in schema) {
194
- schema = schema.example;
194
+ if (property === 'example') {
195
+ if ('example' in schema) {
196
+ schema = schema.example;
197
+ }
198
+ else {
199
+ if (!Array.isArray(schema.examples) || !schema.examples.length) {
200
+ continue;
201
+ }
202
+ // Prevent us from crashing if `examples` is a completely empty object.
203
+ schema = __spreadArray([], schema.examples, true).shift();
204
+ }
195
205
  }
196
206
  else {
197
- if (!Array.isArray(schema.examples) || !schema.examples.length) {
198
- continue;
199
- }
200
- // Prevent us from crashing if `examples` is a completely empty object.
201
- schema = __spreadArray([], schema.examples, true).shift();
207
+ schema = schema.default;
202
208
  }
203
209
  try {
204
- example = jsonpointer_1.default.get(schema, pointers[i]);
210
+ foundValue = jsonpointer_1.default.get(schema, pointers[i]);
205
211
  }
206
212
  catch (err) {
207
213
  // If the schema we're looking at is `{obj: null}` and our pointer is `/obj/propertyName`
208
214
  // `jsonpointer` will throw an error. If that happens, we should silently catch and toss it
209
215
  // and return no example.
210
216
  }
211
- if (example !== undefined) {
217
+ if (foundValue !== undefined) {
212
218
  break;
213
219
  }
214
220
  }
215
- if (example !== undefined) {
221
+ if (foundValue !== undefined) {
216
222
  break;
217
223
  }
218
224
  }
219
- return example;
225
+ return foundValue;
220
226
  }
221
227
  /**
222
228
  * Given an OpenAPI-flavored JSON Schema, make an effort to modify it so it's shaped more towards
@@ -258,7 +264,7 @@ function toJSONSchema(data, opts) {
258
264
  if (opts === void 0) { opts = {}; }
259
265
  var schema = data === true ? {} : __assign({}, data);
260
266
  var schemaAdditionalProperties = RMOAS.isSchema(schema) ? schema.additionalProperties : null;
261
- var _a = __assign({ addEnumsToDescriptions: false, currentLocation: '', globalDefaults: {}, hideReadOnlyProperties: false, hideWriteOnlyProperties: false, isPolymorphicAllOfChild: false, prevSchemas: [], refLogger: function () { return true; }, transformer: function (s) { return s; } }, opts), addEnumsToDescriptions = _a.addEnumsToDescriptions, currentLocation = _a.currentLocation, globalDefaults = _a.globalDefaults, hideReadOnlyProperties = _a.hideReadOnlyProperties, hideWriteOnlyProperties = _a.hideWriteOnlyProperties, isPolymorphicAllOfChild = _a.isPolymorphicAllOfChild, prevSchemas = _a.prevSchemas, refLogger = _a.refLogger, transformer = _a.transformer;
267
+ var _a = __assign({ addEnumsToDescriptions: false, currentLocation: '', globalDefaults: {}, hideReadOnlyProperties: false, hideWriteOnlyProperties: false, isPolymorphicAllOfChild: false, prevDefaultSchemas: [], prevExampleSchemas: [], refLogger: function () { return true; }, transformer: function (s) { return s; } }, opts), addEnumsToDescriptions = _a.addEnumsToDescriptions, currentLocation = _a.currentLocation, globalDefaults = _a.globalDefaults, hideReadOnlyProperties = _a.hideReadOnlyProperties, hideWriteOnlyProperties = _a.hideWriteOnlyProperties, isPolymorphicAllOfChild = _a.isPolymorphicAllOfChild, prevDefaultSchemas = _a.prevDefaultSchemas, prevExampleSchemas = _a.prevExampleSchemas, refLogger = _a.refLogger, transformer = _a.transformer;
262
268
  // If this schema contains a `$ref`, it's circular and we shouldn't try to resolve it. Just
263
269
  // return and move along.
264
270
  if (RMOAS.isRef(schema)) {
@@ -337,7 +343,8 @@ function toJSONSchema(data, opts) {
337
343
  hideReadOnlyProperties: hideReadOnlyProperties,
338
344
  hideWriteOnlyProperties: hideWriteOnlyProperties,
339
345
  isPolymorphicAllOfChild: false,
340
- prevSchemas: prevSchemas,
346
+ prevDefaultSchemas: prevDefaultSchemas,
347
+ prevExampleSchemas: prevExampleSchemas,
341
348
  refLogger: refLogger,
342
349
  transformer: transformer,
343
350
  };
@@ -496,6 +503,9 @@ function toJSONSchema(data, opts) {
496
503
  }
497
504
  }
498
505
  if (RMOAS.isSchema(schema, isPolymorphicAllOfChild)) {
506
+ if ('default' in schema && (0, helpers_1.isObject)(schema.default)) {
507
+ prevDefaultSchemas.push({ default: schema.default });
508
+ }
499
509
  // JSON Schema doesn't support OpenAPI-style examples so we need to reshape them a bit.
500
510
  if ('example' in schema) {
501
511
  // Only bother adding primitive examples.
@@ -509,7 +519,7 @@ function toJSONSchema(data, opts) {
509
519
  }
510
520
  }
511
521
  else {
512
- prevSchemas.push({ example: schema.example });
522
+ prevExampleSchemas.push({ example: schema.example });
513
523
  }
514
524
  delete schema.example;
515
525
  }
@@ -535,9 +545,9 @@ function toJSONSchema(data, opts) {
535
545
  }
536
546
  else {
537
547
  // If this example is neither a primitive or an array we should dump it into the
538
- // `prevSchemas` array because we might be able to extract an example from it further
539
- // downstream.
540
- prevSchemas.push({
548
+ // `prevExampleSchemas` array because we might be able to extract an example from it
549
+ // further downstream.
550
+ prevExampleSchemas.push({
541
551
  example: example.value,
542
552
  });
543
553
  }
@@ -561,7 +571,7 @@ function toJSONSchema(data, opts) {
561
571
  // find one. But as we're only looking for primitive example, only try to search for one if
562
572
  // we're dealing with a primitive schema.
563
573
  if (!(0, helpers_1.hasSchemaType)(schema, 'array') && !(0, helpers_1.hasSchemaType)(schema, 'object') && !schema.examples) {
564
- var foundExample = searchForExampleByPointer(currentLocation, prevSchemas);
574
+ var foundExample = searchForValueByPropAndPointer('example', currentLocation, prevExampleSchemas);
565
575
  if (foundExample) {
566
576
  // We can only really deal with primitives, so only promote those as the found example if
567
577
  // it is.
@@ -585,7 +595,7 @@ function toJSONSchema(data, opts) {
585
595
  globalDefaults: globalDefaults,
586
596
  hideReadOnlyProperties: hideReadOnlyProperties,
587
597
  hideWriteOnlyProperties: hideWriteOnlyProperties,
588
- prevSchemas: prevSchemas,
598
+ prevExampleSchemas: prevExampleSchemas,
589
599
  refLogger: refLogger,
590
600
  transformer: transformer,
591
601
  });
@@ -615,7 +625,8 @@ function toJSONSchema(data, opts) {
615
625
  globalDefaults: globalDefaults,
616
626
  hideReadOnlyProperties: hideReadOnlyProperties,
617
627
  hideWriteOnlyProperties: hideWriteOnlyProperties,
618
- prevSchemas: prevSchemas,
628
+ prevDefaultSchemas: prevDefaultSchemas,
629
+ prevExampleSchemas: prevExampleSchemas,
619
630
  refLogger: refLogger,
620
631
  transformer: transformer,
621
632
  });
@@ -661,7 +672,8 @@ function toJSONSchema(data, opts) {
661
672
  globalDefaults: globalDefaults,
662
673
  hideReadOnlyProperties: hideReadOnlyProperties,
663
674
  hideWriteOnlyProperties: hideWriteOnlyProperties,
664
- prevSchemas: prevSchemas,
675
+ prevDefaultSchemas: prevDefaultSchemas,
676
+ prevExampleSchemas: prevExampleSchemas,
665
677
  refLogger: refLogger,
666
678
  transformer: transformer,
667
679
  });
@@ -713,21 +725,40 @@ function toJSONSchema(data, opts) {
713
725
  }
714
726
  // Only add a default value if we actually have one.
715
727
  if ('default' in schema && typeof schema.default !== 'undefined') {
716
- // If it's an enum and not the response schema, add the default to the description.
717
- // If there's an existing description, trim trailing new lines so it doesn't look ugly.
718
- if ('enum' in schema && !addEnumsToDescriptions) {
719
- schema.description = schema.description
720
- ? "".concat(schema.description.replace(/\n$/, ''), "\n\nDefault: `").concat(schema.default, "`")
721
- : "Default: ".concat(schema.default);
722
- }
723
- if (('allowEmptyValue' in schema && schema.allowEmptyValue && schema.default === '') || schema.default !== '') {
724
- // If we have `allowEmptyValue` present, and the default is actually an empty string, let it
725
- // through as it's allowed.
728
+ if ((0, helpers_1.hasSchemaType)(schema, 'object')) {
729
+ // Defaults for `object` and types have been dereferenced into their children schemas already
730
+ // above so we don't need to preserve this default anymore.
731
+ delete schema.default;
726
732
  }
727
733
  else {
728
- // If the default is empty and we don't want to allowEmptyValue, we need to remove the
729
- // default.
730
- delete schema.default;
734
+ // If it's an enum and not the response schema, add the default to the description.
735
+ // If there's an existing description, trim trailing new lines so it doesn't look ugly.
736
+ if ('enum' in schema && !addEnumsToDescriptions) {
737
+ schema.description = schema.description
738
+ ? "".concat(schema.description.replace(/\n$/, ''), "\n\nDefault: `").concat(schema.default, "`")
739
+ : "Default: ".concat(schema.default);
740
+ }
741
+ if (('allowEmptyValue' in schema && schema.allowEmptyValue && schema.default === '') || schema.default !== '') {
742
+ // If we have `allowEmptyValue` present, and the default is actually an empty string, let it
743
+ // through as it's allowed.
744
+ }
745
+ else {
746
+ // If the default is empty and we don't want to allowEmptyValue, we need to remove the
747
+ // default.
748
+ delete schema.default;
749
+ }
750
+ }
751
+ }
752
+ else if (prevDefaultSchemas.length) {
753
+ var foundDefault = searchForValueByPropAndPointer('default', currentLocation, prevDefaultSchemas);
754
+ // We shouldn't ever set an object default out of the parent lineage tree defaults because
755
+ // the contents of that object will be set on the schema that they're a part of. Setting
756
+ // that object as well would result us in duplicating the defaults for that schema in two
757
+ // places.
758
+ if ((0, helpers_1.isPrimitive)(foundDefault) ||
759
+ foundDefault === null ||
760
+ (Array.isArray(foundDefault) && (0, helpers_1.hasSchemaType)(schema, 'array'))) {
761
+ schema.default = foundDefault;
731
762
  }
732
763
  }
733
764
  if (RMOAS.isSchema(schema, isPolymorphicAllOfChild) && 'enum' in schema && Array.isArray(schema.enum)) {
@@ -99,7 +99,7 @@ function getParametersAsJSONSchema(operation, api, opts) {
99
99
  globalDefaults: opts.globalDefaults,
100
100
  hideReadOnlyProperties: opts.hideReadOnlyProperties,
101
101
  hideWriteOnlyProperties: opts.hideWriteOnlyProperties,
102
- prevSchemas: [],
102
+ prevExampleSchemas: [],
103
103
  refLogger: refLogger,
104
104
  transformer: opts.transformer,
105
105
  });
@@ -135,12 +135,12 @@ function getParametersAsJSONSchema(operation, api, opts) {
135
135
  if (!mediaTypeObject.schema || !Object.keys(mediaTypeObject.schema).length) {
136
136
  return null;
137
137
  }
138
- var prevSchemas = [];
138
+ var prevExampleSchemas = [];
139
139
  if ('example' in mediaTypeObject) {
140
- prevSchemas.push({ example: mediaTypeObject.example });
140
+ prevExampleSchemas.push({ example: mediaTypeObject.example });
141
141
  }
142
142
  else if ('examples' in mediaTypeObject) {
143
- prevSchemas.push({
143
+ prevExampleSchemas.push({
144
144
  examples: Object.values(mediaTypeObject.examples)
145
145
  .map(function (example) { return example.value; })
146
146
  .filter(function (val) { return val !== undefined; }),
@@ -153,7 +153,7 @@ function getParametersAsJSONSchema(operation, api, opts) {
153
153
  globalDefaults: opts.globalDefaults,
154
154
  hideReadOnlyProperties: opts.hideReadOnlyProperties,
155
155
  hideWriteOnlyProperties: opts.hideWriteOnlyProperties,
156
- prevSchemas: prevSchemas,
156
+ prevExampleSchemas: prevExampleSchemas,
157
157
  refLogger: refLogger,
158
158
  transformer: opts.transformer,
159
159
  });
@@ -12,9 +12,7 @@ var __assign = (this && this.__assign) || function () {
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.deeplyStripKey = exports.isFunc = exports.normalizeArray = exports.objectify = exports.usesPolymorphism = void 0;
15
- function isObject(obj) {
16
- return !!obj && typeof obj === 'object';
17
- }
15
+ var helpers_1 = require("../lib/helpers");
18
16
  function usesPolymorphism(schema) {
19
17
  if (schema.oneOf) {
20
18
  return 'oneOf';
@@ -29,7 +27,7 @@ function usesPolymorphism(schema) {
29
27
  }
30
28
  exports.usesPolymorphism = usesPolymorphism;
31
29
  function objectify(thing) {
32
- if (!isObject(thing)) {
30
+ if (!(0, helpers_1.isObject)(thing)) {
33
31
  return {};
34
32
  }
35
33
  return thing;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oas",
3
- "version": "20.8.9",
3
+ "version": "20.9.0",
4
4
  "description": "Comprehensive tooling for working with OpenAPI definitions",
5
5
  "license": "MIT",
6
6
  "author": "ReadMe <support@readme.io> (https://readme.com)",
@@ -59,16 +59,16 @@
59
59
  "devDependencies": {
60
60
  "@commitlint/cli": "^17.6.6",
61
61
  "@commitlint/config-conventional": "^17.6.6",
62
- "@readme/eslint-config": "^10.6.1",
62
+ "@readme/eslint-config": "^10.6.2",
63
63
  "@readme/oas-examples": "^5.11.1",
64
64
  "@readme/openapi-parser": "^2.5.0",
65
- "@types/jest": "^29.5.1",
65
+ "@types/jest": "^29.5.3",
66
66
  "@types/json-schema-merge-allof": "^0.6.1",
67
67
  "@types/memoizee": "^0.4.6",
68
- "@types/node": "^20.3.3",
68
+ "@types/node": "^20.4.1",
69
69
  "eslint": "^8.44.0",
70
70
  "husky": "^8.0.3",
71
- "jest": "^29.5.0",
71
+ "jest": "^29.6.1",
72
72
  "prettier": "^2.8.8",
73
73
  "ts-jest": "^29.1.1",
74
74
  "typescript": "^5.1.6"
@@ -8,6 +8,10 @@ export function hasSchemaType(schema: SchemaObject, discriminator: 'array' | 'ob
8
8
  return schema.type === discriminator;
9
9
  }
10
10
 
11
+ export function isObject(val: unknown) {
12
+ return typeof val === 'object' && val !== null && !Array.isArray(val);
13
+ }
14
+
11
15
  export function isPrimitive(val: unknown): boolean {
12
16
  return typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean';
13
17
  }
@@ -9,7 +9,7 @@ import removeUndefinedObjects from 'remove-undefined-objects';
9
9
 
10
10
  import * as RMOAS from '../rmoas.types';
11
11
 
12
- import { hasSchemaType, isPrimitive } from './helpers';
12
+ import { hasSchemaType, isObject, isPrimitive } from './helpers';
13
13
 
14
14
  /**
15
15
  * This list has been pulled from `openapi-schema-to-json-schema` but been slightly modified to fit
@@ -25,8 +25,6 @@ const UNSUPPORTED_SCHEMA_PROPS = [
25
25
  'xml',
26
26
  ] as const;
27
27
 
28
- type PrevSchemasType = RMOAS.SchemaObject[];
29
-
30
28
  export interface toJSONSchemaOptions {
31
29
  /**
32
30
  * Whether or not to extend descriptions with a list of any present enums.
@@ -59,9 +57,14 @@ export interface toJSONSchemaOptions {
59
57
  isPolymorphicAllOfChild?: boolean;
60
58
 
61
59
  /**
62
- * Array of parent schemas to utilize when attempting to path together examples.
60
+ * Array of parent `default` schemas to utilzie when attempting to path together schema defaults.
61
+ */
62
+ prevDefaultSchemas?: RMOAS.SchemaObject[];
63
+
64
+ /**
65
+ * Array of parent `example` schemas to utilize when attempting to path together schema examples.
63
66
  */
64
- prevSchemas?: PrevSchemasType;
67
+ prevExampleSchemas?: RMOAS.SchemaObject[];
65
68
 
66
69
  /**
67
70
  * A function that's called anytime a (circular) `$ref` is found.
@@ -154,8 +157,8 @@ function isRequestBodySchema(schema: unknown): schema is RMOAS.RequestBodyObject
154
157
  }
155
158
 
156
159
  /**
157
- * Given a JSON pointer and an array of examples do a reverse search through them until we find the
158
- * JSON pointer, or part of it, within the array.
160
+ * Given a JSON pointer, a type of property to look for, and an array of schemas do a reverse
161
+ * search through them until we find the JSON pointer, or part of it, within the array.
159
162
  *
160
163
  * This function will allow you to take a pointer like `/tags/name` and return back `buster` from
161
164
  * the following array:
@@ -183,11 +186,16 @@ function isRequestBodySchema(schema: unknown): schema is RMOAS.RequestBodyObject
183
186
  * it shouldn't raise immediate cause for alarm.
184
187
  *
185
188
  * @see {@link https://tools.ietf.org/html/rfc6901}
189
+ * @param property Specific type of schema property to look for a value for.
186
190
  * @param pointer JSON pointer to search for an example for.
187
- * @param examples Array of previous schemas we've found relating to this pointer.
191
+ * @param schemas Array of previous schemas we've found relating to this pointer.
188
192
  */
189
- function searchForExampleByPointer(pointer: string, examples: PrevSchemasType = []) {
190
- if (!examples.length || !pointer.length) {
193
+ function searchForValueByPropAndPointer(
194
+ property: 'example' | 'default',
195
+ pointer: string,
196
+ schemas: toJSONSchemaOptions['prevExampleSchemas'] | toJSONSchemaOptions['prevDefaultSchemas'] = []
197
+ ) {
198
+ if (!schemas.length || !pointer.length) {
191
199
  return undefined;
192
200
  }
193
201
 
@@ -200,42 +208,47 @@ function searchForExampleByPointer(pointer: string, examples: PrevSchemasType =
200
208
  pointers.push(point);
201
209
  }
202
210
 
203
- let example;
204
- const rev = [...examples].reverse();
211
+ let foundValue;
212
+ const rev = [...schemas].reverse();
205
213
 
206
214
  for (let i = 0; i < pointers.length; i += 1) {
207
215
  for (let ii = 0; ii < rev.length; ii += 1) {
208
216
  let schema = rev[ii];
209
- if ('example' in schema) {
210
- schema = schema.example;
211
- } else {
212
- if (!Array.isArray(schema.examples) || !schema.examples.length) {
213
- continue;
214
- }
215
217
 
216
- // Prevent us from crashing if `examples` is a completely empty object.
217
- schema = [...schema.examples].shift();
218
+ if (property === 'example') {
219
+ if ('example' in schema) {
220
+ schema = schema.example;
221
+ } else {
222
+ if (!Array.isArray(schema.examples) || !schema.examples.length) {
223
+ continue;
224
+ }
225
+
226
+ // Prevent us from crashing if `examples` is a completely empty object.
227
+ schema = [...schema.examples].shift();
228
+ }
229
+ } else {
230
+ schema = schema.default;
218
231
  }
219
232
 
220
233
  try {
221
- example = jsonpointer.get(schema, pointers[i]);
234
+ foundValue = jsonpointer.get(schema, pointers[i]);
222
235
  } catch (err) {
223
236
  // If the schema we're looking at is `{obj: null}` and our pointer is `/obj/propertyName`
224
237
  // `jsonpointer` will throw an error. If that happens, we should silently catch and toss it
225
238
  // and return no example.
226
239
  }
227
240
 
228
- if (example !== undefined) {
241
+ if (foundValue !== undefined) {
229
242
  break;
230
243
  }
231
244
  }
232
245
 
233
- if (example !== undefined) {
246
+ if (foundValue !== undefined) {
234
247
  break;
235
248
  }
236
249
  }
237
250
 
238
- return example;
251
+ return foundValue;
239
252
  }
240
253
 
241
254
  /**
@@ -288,7 +301,8 @@ export default function toJSONSchema(
288
301
  hideReadOnlyProperties,
289
302
  hideWriteOnlyProperties,
290
303
  isPolymorphicAllOfChild,
291
- prevSchemas,
304
+ prevDefaultSchemas,
305
+ prevExampleSchemas,
292
306
  refLogger,
293
307
  transformer,
294
308
  } = {
@@ -298,7 +312,8 @@ export default function toJSONSchema(
298
312
  hideReadOnlyProperties: false,
299
313
  hideWriteOnlyProperties: false,
300
314
  isPolymorphicAllOfChild: false,
301
- prevSchemas: [] as PrevSchemasType,
315
+ prevDefaultSchemas: [] as toJSONSchemaOptions['prevDefaultSchemas'],
316
+ prevExampleSchemas: [] as toJSONSchemaOptions['prevExampleSchemas'],
302
317
  refLogger: () => true,
303
318
  transformer: (s: RMOAS.SchemaObject) => s,
304
319
  ...opts,
@@ -391,7 +406,8 @@ export default function toJSONSchema(
391
406
  hideReadOnlyProperties,
392
407
  hideWriteOnlyProperties,
393
408
  isPolymorphicAllOfChild: false,
394
- prevSchemas,
409
+ prevDefaultSchemas,
410
+ prevExampleSchemas,
395
411
  refLogger,
396
412
  transformer,
397
413
  };
@@ -564,6 +580,10 @@ export default function toJSONSchema(
564
580
  }
565
581
 
566
582
  if (RMOAS.isSchema(schema, isPolymorphicAllOfChild)) {
583
+ if ('default' in schema && isObject(schema.default)) {
584
+ prevDefaultSchemas.push({ default: schema.default });
585
+ }
586
+
567
587
  // JSON Schema doesn't support OpenAPI-style examples so we need to reshape them a bit.
568
588
  if ('example' in schema) {
569
589
  // Only bother adding primitive examples.
@@ -575,7 +595,7 @@ export default function toJSONSchema(
575
595
  delete schema.examples;
576
596
  }
577
597
  } else {
578
- prevSchemas.push({ example: schema.example });
598
+ prevExampleSchemas.push({ example: schema.example });
579
599
  }
580
600
 
581
601
  delete schema.example;
@@ -598,9 +618,9 @@ export default function toJSONSchema(
598
618
  reshapedExamples = true;
599
619
  } else {
600
620
  // If this example is neither a primitive or an array we should dump it into the
601
- // `prevSchemas` array because we might be able to extract an example from it further
602
- // downstream.
603
- prevSchemas.push({
621
+ // `prevExampleSchemas` array because we might be able to extract an example from it
622
+ // further downstream.
623
+ prevExampleSchemas.push({
604
624
  example: example.value,
605
625
  });
606
626
  }
@@ -626,7 +646,7 @@ export default function toJSONSchema(
626
646
  // find one. But as we're only looking for primitive example, only try to search for one if
627
647
  // we're dealing with a primitive schema.
628
648
  if (!hasSchemaType(schema, 'array') && !hasSchemaType(schema, 'object') && !schema.examples) {
629
- const foundExample = searchForExampleByPointer(currentLocation, prevSchemas);
649
+ const foundExample = searchForValueByPropAndPointer('example', currentLocation, prevExampleSchemas);
630
650
  if (foundExample) {
631
651
  // We can only really deal with primitives, so only promote those as the found example if
632
652
  // it is.
@@ -650,7 +670,7 @@ export default function toJSONSchema(
650
670
  globalDefaults,
651
671
  hideReadOnlyProperties,
652
672
  hideWriteOnlyProperties,
653
- prevSchemas,
673
+ prevExampleSchemas,
654
674
  refLogger,
655
675
  transformer,
656
676
  });
@@ -679,7 +699,8 @@ export default function toJSONSchema(
679
699
  globalDefaults,
680
700
  hideReadOnlyProperties,
681
701
  hideWriteOnlyProperties,
682
- prevSchemas,
702
+ prevDefaultSchemas,
703
+ prevExampleSchemas,
683
704
  refLogger,
684
705
  transformer,
685
706
  });
@@ -727,7 +748,8 @@ export default function toJSONSchema(
727
748
  globalDefaults,
728
749
  hideReadOnlyProperties,
729
750
  hideWriteOnlyProperties,
730
- prevSchemas,
751
+ prevDefaultSchemas,
752
+ prevExampleSchemas,
731
753
  refLogger,
732
754
  transformer,
733
755
  });
@@ -786,21 +808,41 @@ export default function toJSONSchema(
786
808
 
787
809
  // Only add a default value if we actually have one.
788
810
  if ('default' in schema && typeof schema.default !== 'undefined') {
789
- // If it's an enum and not the response schema, add the default to the description.
790
- // If there's an existing description, trim trailing new lines so it doesn't look ugly.
791
- if ('enum' in schema && !addEnumsToDescriptions) {
792
- schema.description = schema.description
793
- ? `${schema.description.replace(/\n$/, '')}\n\nDefault: \`${schema.default}\``
794
- : `Default: ${schema.default}`;
795
- }
796
-
797
- if (('allowEmptyValue' in schema && schema.allowEmptyValue && schema.default === '') || schema.default !== '') {
798
- // If we have `allowEmptyValue` present, and the default is actually an empty string, let it
799
- // through as it's allowed.
800
- } else {
801
- // If the default is empty and we don't want to allowEmptyValue, we need to remove the
802
- // default.
811
+ if (hasSchemaType(schema, 'object')) {
812
+ // Defaults for `object` and types have been dereferenced into their children schemas already
813
+ // above so we don't need to preserve this default anymore.
803
814
  delete schema.default;
815
+ } else {
816
+ // If it's an enum and not the response schema, add the default to the description.
817
+ // If there's an existing description, trim trailing new lines so it doesn't look ugly.
818
+ if ('enum' in schema && !addEnumsToDescriptions) {
819
+ schema.description = schema.description
820
+ ? `${schema.description.replace(/\n$/, '')}\n\nDefault: \`${schema.default}\``
821
+ : `Default: ${schema.default}`;
822
+ }
823
+
824
+ if (('allowEmptyValue' in schema && schema.allowEmptyValue && schema.default === '') || schema.default !== '') {
825
+ // If we have `allowEmptyValue` present, and the default is actually an empty string, let it
826
+ // through as it's allowed.
827
+ } else {
828
+ // If the default is empty and we don't want to allowEmptyValue, we need to remove the
829
+ // default.
830
+ delete schema.default;
831
+ }
832
+ }
833
+ } else if (prevDefaultSchemas.length) {
834
+ const foundDefault = searchForValueByPropAndPointer('default', currentLocation, prevDefaultSchemas);
835
+
836
+ // We shouldn't ever set an object default out of the parent lineage tree defaults because
837
+ // the contents of that object will be set on the schema that they're a part of. Setting
838
+ // that object as well would result us in duplicating the defaults for that schema in two
839
+ // places.
840
+ if (
841
+ isPrimitive(foundDefault) ||
842
+ foundDefault === null ||
843
+ (Array.isArray(foundDefault) && hasSchemaType(schema, 'array'))
844
+ ) {
845
+ schema.default = foundDefault;
804
846
  }
805
847
  }
806
848
 
@@ -1,3 +1,4 @@
1
+ import type { toJSONSchemaOptions } from '../lib/openapi-to-json-schema';
1
2
  import type Operation from '../operation';
2
3
  import type { ComponentsObject, ExampleObject, OASDocument, ParameterObject, SchemaObject } from '../rmoas.types';
3
4
  import type { OpenAPIV3_1 } from 'openapi-types';
@@ -125,7 +126,7 @@ export default function getParametersAsJSONSchema(
125
126
  globalDefaults: opts.globalDefaults,
126
127
  hideReadOnlyProperties: opts.hideReadOnlyProperties,
127
128
  hideWriteOnlyProperties: opts.hideWriteOnlyProperties,
128
- prevSchemas: [],
129
+ prevExampleSchemas: [],
129
130
  refLogger,
130
131
  transformer: opts.transformer,
131
132
  });
@@ -170,11 +171,11 @@ export default function getParametersAsJSONSchema(
170
171
  return null;
171
172
  }
172
173
 
173
- const prevSchemas: SchemaObject[] = [];
174
+ const prevExampleSchemas: toJSONSchemaOptions['prevExampleSchemas'] = [];
174
175
  if ('example' in mediaTypeObject) {
175
- prevSchemas.push({ example: mediaTypeObject.example });
176
+ prevExampleSchemas.push({ example: mediaTypeObject.example });
176
177
  } else if ('examples' in mediaTypeObject) {
177
- prevSchemas.push({
178
+ prevExampleSchemas.push({
178
179
  examples: Object.values(mediaTypeObject.examples)
179
180
  .map((example: ExampleObject) => example.value)
180
181
  .filter(val => val !== undefined),
@@ -189,7 +190,7 @@ export default function getParametersAsJSONSchema(
189
190
  globalDefaults: opts.globalDefaults,
190
191
  hideReadOnlyProperties: opts.hideReadOnlyProperties,
191
192
  hideWriteOnlyProperties: opts.hideWriteOnlyProperties,
192
- prevSchemas,
193
+ prevExampleSchemas,
193
194
  refLogger,
194
195
  transformer: opts.transformer,
195
196
  });
@@ -6,9 +6,7 @@
6
6
  */
7
7
  import type * as RMOAS from '../rmoas.types';
8
8
 
9
- function isObject(obj: unknown) {
10
- return !!obj && typeof obj === 'object';
11
- }
9
+ import { isObject } from '../lib/helpers';
12
10
 
13
11
  export function usesPolymorphism(schema: RMOAS.SchemaObject) {
14
12
  if (schema.oneOf) {
package/tsconfig.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "lib": ["dom", "es2020"],
8
8
  "noImplicitAny": true,
9
9
  "outDir": "./dist",
10
- "resolveJsonModule": true,
10
+ "resolveJsonModule": true
11
11
  },
12
12
  "include": ["./src/**/*"]
13
13
  }