@goast/core 0.0.5 → 0.1.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.
@@ -31,6 +31,7 @@ class OpenApiSchemasGenerationProviderBase extends generator_1.OpenApiGeneration
31
31
  result = this.generateSchema(ctx, schema);
32
32
  }
33
33
  (0, internal_utils_1.addSourceIfTest)(ctx.config, result, () => `${schema.$src.file}#${schema.$src.path}`);
34
+ ctx.existingSchemaResults.set(schema.id, result);
34
35
  this.addSchemaResult(ctx, schema, result);
35
36
  return result;
36
37
  }
@@ -56,6 +56,7 @@ function collectPathItem(data, pathItems, path) {
56
56
  }
57
57
  function collectSchema(data, schemas) {
58
58
  (0, helpers_1.collect)(data, schemas, (data, schema) => {
59
+ var _a;
59
60
  const key = `${schema.$src.file}#${schema.$src.path}`;
60
61
  if (data.schemas.has(key))
61
62
  return;
@@ -75,6 +76,9 @@ function collectSchema(data, schemas) {
75
76
  if (typeof schema.additionalItems === 'object') {
76
77
  collectSchema(data, schema.additionalItems);
77
78
  }
79
+ if (typeof schema.discriminator === 'object') {
80
+ (0, helpers_1.collectRecord)(data, (_a = schema.discriminator) === null || _a === void 0 ? void 0 : _a.mapping, collectSchema);
81
+ }
78
82
  });
79
83
  }
80
84
  function collectParameter(data, parameters) {
@@ -11,6 +11,7 @@ const yaml_1 = tslib_1.__importDefault(require("yaml"));
11
11
  const deref_proxy_1 = require("./deref-proxy");
12
12
  const collector_1 = require("../collect/collector");
13
13
  const transformer_1 = require("../transform/transformer");
14
+ const utils_1 = require("../utils");
14
15
  class OpenApiParser {
15
16
  constructor() {
16
17
  this._loadedDocuments = new Map();
@@ -61,7 +62,9 @@ class OpenApiParser {
61
62
  if (key === '$ref')
62
63
  continue;
63
64
  const v = value[key];
64
- if (v && typeof v === 'object') {
65
+ if ((0, utils_1.isNullish)(v))
66
+ continue;
67
+ if (typeof v === 'object') {
65
68
  if (Array.isArray(v)) {
66
69
  result[key] = yield Promise.all(v.map((v, index) => tslib_1.__awaiter(this, void 0, void 0, function* () {
67
70
  if (v && typeof v === 'object') {
@@ -76,6 +79,9 @@ class OpenApiParser {
76
79
  result[key] = yield this.dereference(file, `${path}/${String(key)}`, v);
77
80
  }
78
81
  }
82
+ if (typeof v === 'string' && path.endsWith('/discriminator/mapping')) {
83
+ result[key] = yield this.resolveReference(file, { $ref: v });
84
+ }
79
85
  }
80
86
  return result;
81
87
  });
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformSchema = void 0;
4
4
  const helpers_1 = require("./helpers");
5
5
  const utils_1 = require("../utils");
6
- function transformSchema(context, schema, isReference = false) {
6
+ function transformSchema(context, schema) {
7
7
  var _a, _b;
8
8
  if (!schema) {
9
9
  throw new Error('Schema is required.');
@@ -33,12 +33,11 @@ function transformSchema(context, schema, isReference = false) {
33
33
  kind = (0, helpers_1.determineSchemaKind)(schema);
34
34
  }
35
35
  }
36
- const ref = schema.$ref ? transformSchema(context, schema.$ref, true) : undefined;
37
36
  const id = context.idGenerator.generateId('schema');
38
37
  const nameInfo = (0, helpers_1.determineSchemaName)(schema, id);
39
- const result = {
38
+ const incompleteSchema = {
40
39
  $src: Object.assign(Object.assign({}, schema.$src), { component: schema }),
41
- $ref: ref,
40
+ $ref: undefined,
42
41
  id,
43
42
  name: nameInfo.name,
44
43
  isNameGenerated: nameInfo.isGenerated,
@@ -54,16 +53,25 @@ function transformSchema(context, schema, isReference = false) {
54
53
  custom: (0, helpers_1.getCustomFields)(schema),
55
54
  not: schema.not ? transformSchema(context, schema.not) : undefined,
56
55
  const: schema.const,
56
+ discriminator: schema.discriminator
57
+ ? {
58
+ propertyName: typeof schema.discriminator === 'string' ? schema.discriminator : schema.discriminator.propertyName,
59
+ mapping: {},
60
+ }
61
+ : undefined,
62
+ inheritedSchemas: [],
57
63
  };
58
- context.incompleteSchemas.set(schemaSource, result);
64
+ context.incompleteSchemas.set(schemaSource, incompleteSchema);
65
+ if (schema.$ref) {
66
+ incompleteSchema.$ref = transformSchema(context, schema.$ref);
67
+ }
59
68
  const extensions = schemaTransformers[kind](schema, context);
60
- Object.assign(result, extensions);
69
+ const completeSchema = Object.assign(incompleteSchema, extensions);
70
+ resolveDescriminatorMapping(context, completeSchema);
61
71
  context.incompleteSchemas.delete(schemaSource);
62
- context.transformed.schemas.set(openApiObjectId, result);
63
- if (!isReference) {
64
- context.schemas.set(schemaSource, result);
65
- }
66
- return result;
72
+ context.transformed.schemas.set(openApiObjectId, completeSchema);
73
+ context.schemas.set(schemaSource, completeSchema);
74
+ return completeSchema;
67
75
  }
68
76
  exports.transformSchema = transformSchema;
69
77
  const schemaTransformers = {
@@ -139,3 +147,14 @@ const schemaTransformers = {
139
147
  null: () => ({ type: 'null' }),
140
148
  unknown: () => ({}),
141
149
  };
150
+ function resolveDescriminatorMapping(context, schema) {
151
+ const discriminator = schema.$src.component.discriminator;
152
+ if (!discriminator || typeof discriminator === 'string' || !discriminator.mapping)
153
+ return;
154
+ for (const key of Object.keys(discriminator.mapping)) {
155
+ const mappedSchemaRef = discriminator.mapping[key];
156
+ const mappedSchema = transformSchema(context, mappedSchemaRef);
157
+ schema.discriminator.mapping[key] = mappedSchema;
158
+ mappedSchema.inheritedSchemas.push(schema);
159
+ }
160
+ }
@@ -65,58 +65,69 @@ class SourceBuilder extends string_utils_1.StringBuilder {
65
65
  * @returns The current SourceBuilder.
66
66
  */
67
67
  append(...value) {
68
- if (value.length === 0 || !value.some((v) => v && v.length > 0)) {
69
- return this;
70
- }
71
- const str = value.join('');
72
- let lineStartIndex = 0;
73
- for (let i = 0; i < str.length; i++) {
74
- if (str[i] === '\r')
68
+ for (const str of value) {
69
+ if (!str)
75
70
  continue;
76
- if (str[i] === '\n') {
77
- let lineLength = i - lineStartIndex;
78
- for (let j = i; j > 0 && str[j - 1] === '\r'; j--) {
79
- lineLength--;
80
- }
81
- if (lineLength > 0) {
82
- if (!this._isLineIndented) {
71
+ if (typeof str === 'function') {
72
+ str(this);
73
+ continue;
74
+ }
75
+ let lineStartIndex = 0;
76
+ for (let i = 0; i < str.length; i++) {
77
+ if (str[i] === '\r')
78
+ continue;
79
+ if (str[i] === '\n') {
80
+ let lineLength = i - lineStartIndex;
81
+ for (let j = i; j > 0 && str[j - 1] === '\r'; j--) {
82
+ lineLength--;
83
+ }
84
+ if (lineLength > 0) {
85
+ if (!this._isLineIndented) {
86
+ this.appendIndent();
87
+ }
88
+ super.append(str.substring(lineStartIndex, i).replace(/\r/g, ''));
89
+ }
90
+ this._isLastLineEmpty = this._isCurrentLineEmpty;
91
+ super.append(this.__options.newLine);
92
+ if (this._linePrefix) {
83
93
  this.appendIndent();
94
+ this._isLineIndented = true;
95
+ this._isCurrentLineEmpty = false;
84
96
  }
85
- super.append(str.substring(lineStartIndex, i).replace(/\r/g, ''));
97
+ else {
98
+ this._isLineIndented = false;
99
+ this._isCurrentLineEmpty = true;
100
+ }
101
+ lineStartIndex = i + 1;
102
+ }
103
+ if (!this._emptyLineCharRegex.test(str[i])) {
104
+ this._isCurrentLineEmpty = false;
86
105
  }
87
- this._isLastLineEmpty = this._isCurrentLineEmpty;
88
- super.append(this.__options.newLine);
89
- this._isCurrentLineEmpty = true;
90
- this._isLineIndented = false;
91
- lineStartIndex = i + 1;
92
106
  }
93
- if (!this._emptyLineCharRegex.test(str[i])) {
94
- this._isCurrentLineEmpty = false;
107
+ if (!this._isLineIndented && (lineStartIndex < str.length || this._linePrefix)) {
108
+ this.appendIndent();
109
+ this._isLineIndented = true;
95
110
  }
111
+ super.append(str.substring(lineStartIndex).replace(/\r/g, ''));
96
112
  }
97
- if (!this._isLineIndented && lineStartIndex < str.length) {
98
- this.appendIndent();
99
- this._isLineIndented = true;
100
- }
101
- super.append(str.substring(lineStartIndex).replace(/\r/g, ''));
102
113
  return this;
103
114
  }
104
115
  /**
105
- * Appends one or more strings to the end of the current SourceBuilder, followed by a line terminator.
116
+ * Appends one or more strings to the end of the current SourceBuilder if the specified condition is true.
117
+ * @param condition The condition to check before appending the specified value.
106
118
  * @param value The string(s) to append.
107
119
  * @returns The current SourceBuilder.
108
120
  */
109
- appendLine(...value) {
110
- return this.append(...value, '\n');
121
+ appendIf(condition, ...value) {
122
+ return this.if(condition, (builder) => builder.append(...value));
111
123
  }
112
124
  /**
113
- * Appends one or more strings to the end of the current SourceBuilder if the specified condition is true.
114
- * @param condition The condition to check before appending the specified value.
125
+ * Appends one or more strings to the end of the current SourceBuilder, followed by a line terminator.
115
126
  * @param value The string(s) to append.
116
127
  * @returns The current SourceBuilder.
117
128
  */
118
- appendIf(condition, ...value) {
119
- return (0, condition_1.evalCondition)(condition) ? this.append(...value) : this;
129
+ appendLine(...value) {
130
+ return this.append(...value, '\n');
120
131
  }
121
132
  /**
122
133
  * Appends one or more strings to the end of the current SourceBuilder, followed by a line terminator, if the specified condition is true.
@@ -125,7 +136,7 @@ class SourceBuilder extends string_utils_1.StringBuilder {
125
136
  * @returns The current SourceBuilder.
126
137
  */
127
138
  appendLineIf(condition, ...value) {
128
- return (0, condition_1.evalCondition)(condition) ? this.appendLine(...value) : this;
139
+ return this.if(condition, (builder) => builder.appendLine(...value));
129
140
  }
130
141
  /**
131
142
  * Appends the specified values to this source builder with the specified line prefix.
@@ -134,7 +145,15 @@ class SourceBuilder extends string_utils_1.StringBuilder {
134
145
  * @returns {SourceBuilder} This source builder instance.
135
146
  */
136
147
  appendWithLinePrefix(prefix, ...value) {
137
- return this.applyWithLinePrefix(prefix, (builder) => builder.append(...value));
148
+ const previousLinePrefix = this._linePrefix;
149
+ this._linePrefix += prefix;
150
+ try {
151
+ this.append(...value);
152
+ }
153
+ finally {
154
+ this._linePrefix = previousLinePrefix;
155
+ }
156
+ return this;
138
157
  }
139
158
  /**
140
159
  * Appends the specified values to this source builder as a new line with the specified line prefix.
@@ -143,7 +162,7 @@ class SourceBuilder extends string_utils_1.StringBuilder {
143
162
  * @returns {SourceBuilder} This source builder instance.
144
163
  */
145
164
  appendLineWithLinePrefix(prefix, ...value) {
146
- return this.applyWithLinePrefix(prefix, (builder) => builder.appendLine(...value));
165
+ return this.appendWithLinePrefix(prefix, ...value, '\n');
147
166
  }
148
167
  /**
149
168
  * Prepends one or more strings to the beginning of the current SourceBuilder if the specified condition is true.
@@ -152,7 +171,7 @@ class SourceBuilder extends string_utils_1.StringBuilder {
152
171
  * @returns The current SourceBuilder.
153
172
  */
154
173
  prependIf(condition, ...value) {
155
- return (0, condition_1.evalCondition)(condition) ? this.prepend(...value) : this;
174
+ return this.if(condition, (builder) => builder.prepend(...value));
156
175
  }
157
176
  /**
158
177
  * Prepends one or more strings to the beginning of the current SourceBuilder, followed by a line terminator, if the specified condition is true.
@@ -161,33 +180,7 @@ class SourceBuilder extends string_utils_1.StringBuilder {
161
180
  * @returns The current SourceBuilder.
162
181
  */
163
182
  prependLineIf(condition, ...value) {
164
- return (0, condition_1.evalCondition)(condition) ? this.prependLine(...value) : this;
165
- }
166
- /**
167
- * Applies the provided builder function to this source builder.
168
- * @param builderFn The builder function to apply.
169
- * @returns This source builder instance.
170
- */
171
- apply(builderFn) {
172
- builderFn(this);
173
- return this;
174
- }
175
- /**
176
- * Applies the provided builder function to this source builder with the specified line prefix.
177
- * @param prefix The line prefix to use.
178
- * @param builderFn The builder function to apply.
179
- * @returns This source builder instance.
180
- */
181
- applyWithLinePrefix(prefix, builderFn) {
182
- const previousLinePrefix = this._linePrefix;
183
- this._linePrefix += prefix;
184
- try {
185
- builderFn(this);
186
- }
187
- finally {
188
- this._linePrefix = previousLinePrefix;
189
- }
190
- return this;
183
+ return this.if(condition, (builder) => builder.prependLine(...value));
191
184
  }
192
185
  /**
193
186
  * Ensures that the current line is empty or consists only of whitespace characters.
@@ -215,136 +208,82 @@ class SourceBuilder extends string_utils_1.StringBuilder {
215
208
  /**
216
209
  * Inserts specified content if the specified condition is true.
217
210
  * @param condition The condition to check before inserting content.
218
- * @param builderFn The function to add content.
219
- * @returns A reference to this instance.
220
- */
221
- applyIf(condition, builderFn) {
222
- if ((0, condition_1.evalCondition)(condition)) {
223
- builderFn(this);
224
- }
225
- return this;
226
- }
227
- /**
228
- * Inserts specified content depending on the specified condition.
229
- * @param condition The condition to check before inserting content.
230
211
  * @param builderFn The function to add content if the condition is true.
231
212
  * @param elseBuilderFn The function to add content if the condition is false.
232
213
  * @returns A reference to this instance.
233
214
  */
234
- applyIfElse(condition, builderFn, elseBuilderFn) {
215
+ if(condition, builderFn, elseBuilderFn) {
235
216
  if ((0, condition_1.evalCondition)(condition)) {
236
217
  builderFn(this);
237
218
  }
238
219
  else {
239
- elseBuilderFn(this);
220
+ elseBuilderFn === null || elseBuilderFn === void 0 ? void 0 : elseBuilderFn(this);
240
221
  }
241
222
  return this;
242
223
  }
243
224
  /**
244
225
  * Adds one indentation level. If the current line already contains characters, only subsequent lines are affected.
245
- * @param builderFn The function to add indented content.
226
+ * @param builderFn The function to add indented content or the content itself.
246
227
  * @param condition The condition to check before adding indentation.
247
228
  * @returns A reference to this instance.
248
229
  */
249
- indent(builderFn, condition = true) {
250
- const shouldIndent = (0, condition_1.evalCondition)(condition);
251
- if (shouldIndent) {
252
- this.currentIndentLevel++;
253
- }
230
+ indent(value) {
231
+ this.currentIndentLevel++;
254
232
  try {
255
- builderFn(this);
233
+ this.append(value);
256
234
  }
257
235
  finally {
258
- if (shouldIndent) {
259
- this.currentIndentLevel--;
260
- }
236
+ this.currentIndentLevel--;
261
237
  }
262
238
  return this;
263
239
  }
264
240
  /**
265
- * Adds parentheses around the specified content and adds one indentation level.
266
- * @param brackets The brackets to use.
267
- * @param builderFn The function to add content inside parentheses.
268
- * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
241
+ * Adds one indentation level if the specified condition is true. If the current line already contains characters, only subsequent lines are affected.
242
+ * @param builderFn The function to add indented content or the content itself.
243
+ * @param condition The condition to check before adding indentation.
269
244
  * @returns A reference to this instance.
270
245
  */
271
- parenthesize(brackets, builderFn, indent = true) {
272
- var _a, _b;
273
- this.append((_a = brackets[0]) !== null && _a !== void 0 ? _a : '');
274
- this.indent(builderFn, indent);
275
- this.append((_b = brackets[1]) !== null && _b !== void 0 ? _b : '');
276
- return this;
246
+ indentIf(condition, value) {
247
+ return this.if(condition, (builder) => builder.indent(value), (builder) => builder.append(value));
277
248
  }
278
249
  /**
279
- * Adds parentheses around the specified content if the specified condition is true.
280
- * @param condition The condition to check before adding parentheses.
250
+ * Adds parentheses around the specified content.
281
251
  * @param brackets The brackets to use.
282
- * @param builderFn The function to add content inside parentheses.
283
- * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
284
- * @returns A reference to this instance.
285
- */
286
- parenthesizeIf(condition, brackets, builderFn, indent) {
287
- if ((0, condition_1.evalCondition)(condition)) {
288
- this.parenthesize(brackets, builderFn, indent !== null && indent !== void 0 ? indent : true);
289
- }
290
- else {
291
- this.indent(builderFn, indent !== null && indent !== void 0 ? indent : false);
292
- }
293
- return this;
294
- }
295
- /**
296
- * Adds content for each item in the specified array.
297
- * @param items The items to add content for.
298
- * @param builderFn The function to add content for each item.
252
+ * @param value The function to add content inside parentheses or one string that should be parenthesized.
253
+ * @param options Options for the parentheses.
299
254
  * @returns A reference to this instance.
300
255
  */
301
- forEach(items, builderFn) {
302
- return this.forEachImpl(items, builderFn);
256
+ parenthesize(brackets, value, options) {
257
+ var _a, _b, _c, _d;
258
+ return this.if((_a = options === null || options === void 0 ? void 0 : options.multiline) !== null && _a !== void 0 ? _a : false, (b) => { var _a; return b.appendLine((_a = brackets[0]) !== null && _a !== void 0 ? _a : ''); }, (b) => { var _a; return b.append((_a = brackets[0]) !== null && _a !== void 0 ? _a : ''); })
259
+ .indentIf((_b = options === null || options === void 0 ? void 0 : options.indent) !== null && _b !== void 0 ? _b : true, value)
260
+ .if((_c = options === null || options === void 0 ? void 0 : options.multiline) !== null && _c !== void 0 ? _c : false, (b) => b.ensureCurrentLineEmpty())
261
+ .append((_d = brackets[1]) !== null && _d !== void 0 ? _d : '');
303
262
  }
304
263
  /**
305
- * Adds content for each item in the specified array.
306
- * @param items The items to add content for.
307
- * @param condition The condition to check before adding content.
308
- * @param builderFn The function to add content for each item.
309
- * @returns A reference to this instance.
310
- */
311
- forEachIf(items, condition, builderFn) {
312
- return (0, condition_1.evalCondition)(condition) ? this.forEachImpl(items, builderFn) : this;
313
- }
314
- /**
315
- * Adds content for each item in the specified array.
316
- * @param items The items to add content for.
317
- * @param condition The condition to check before adding content for each item.
318
- * @param builderFn The function to add content for each item.
319
- * @returns A reference to this instance.
320
- */
321
- forEachMatching(items, condition, builderFn) {
322
- return this.forEachImpl(items, builderFn, undefined, condition);
323
- }
324
- /**
325
- * Adds content for each item in the specified array.
326
- * @param items The items to add content for.
327
- * @param seperator The seperator to add between items.
328
- * @param builderFn The function to add content for each item.
264
+ * Adds parentheses around the specified content if the specified condition is true.
265
+ * @param condition The condition to check before adding parentheses.
266
+ * @param brackets The brackets to use.
267
+ * @param value The function to add content inside parentheses or one string that should be parenthesized.
268
+ * @param options Options for the parentheses.
329
269
  * @returns A reference to this instance.
330
270
  */
331
- forEachSeparated(items, seperator, builderFn) {
332
- return this.forEachImpl(items, builderFn, seperator);
271
+ parenthesizeIf(condition, brackets, value, options) {
272
+ return this.if(condition, (builder) => builder.parenthesize(brackets, value, options), (builder) => builder.indentIf((options === null || options === void 0 ? void 0 : options.indent) === true, value));
333
273
  }
334
274
  /**
335
275
  * Adds content for each item in the specified array.
336
276
  * @param items The items to add content for.
337
- * @param condition The condition to check before adding content for each item.
338
- * @param seperator The seperator to add between items.
339
277
  * @param builderFn The function to add content for each item.
278
+ * @param options The options for the loop.
340
279
  * @returns A reference to this instance.
341
280
  */
342
- forEachMatchingSeparated(items, condition, seperator, builderFn) {
343
- return this.forEachImpl(items, builderFn, seperator, condition);
344
- }
345
- forEachImpl(items, builderFn, seperator, condition = true) {
346
- if (condition === false)
281
+ forEach(items, builderFn, options) {
282
+ var _a;
283
+ const condition = (_a = options === null || options === void 0 ? void 0 : options.condition) !== null && _a !== void 0 ? _a : true;
284
+ if ((options === null || options === void 0 ? void 0 : options.condition) === false)
347
285
  return this;
286
+ const seperator = options === null || options === void 0 ? void 0 : options.separator;
348
287
  let previousIndex = -1;
349
288
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
350
289
  let previousItem = undefined;
@@ -367,6 +306,15 @@ class SourceBuilder extends string_utils_1.StringBuilder {
367
306
  }
368
307
  return this;
369
308
  }
309
+ forEachIf(condition, items, builderFn, options) {
310
+ return this.if(condition, (b) => b.forEach(items, builderFn, options));
311
+ }
312
+ appendSeparated(items, separator) {
313
+ return this.forEach(items, (builder, item) => builder.append(item), { separator });
314
+ }
315
+ appendSeparatedIf(condition, items, separator) {
316
+ return this.forEachIf(condition, items, (builder, item) => builder.append(item), { separator });
317
+ }
370
318
  appendIndent() {
371
319
  super.append(this._indentString.repeat(this.currentIndentLevel));
372
320
  if (this._linePrefix) {
@@ -277,9 +277,14 @@ class StringBuilder {
277
277
  */
278
278
  append(...value) {
279
279
  for (const part of value) {
280
- if ((0, common_utils_1.isNullish)(part) || part.length === 0)
280
+ if (!part)
281
281
  continue;
282
- this._str += part;
282
+ if (typeof part === 'string') {
283
+ this._str += part;
284
+ }
285
+ else {
286
+ part(this);
287
+ }
283
288
  }
284
289
  return this;
285
290
  }
@@ -28,6 +28,7 @@ export class OpenApiSchemasGenerationProviderBase extends OpenApiGenerationProvi
28
28
  result = this.generateSchema(ctx, schema);
29
29
  }
30
30
  addSourceIfTest(ctx.config, result, () => `${schema.$src.file}#${schema.$src.path}`);
31
+ ctx.existingSchemaResults.set(schema.id, result);
31
32
  this.addSchemaResult(ctx, schema, result);
32
33
  return result;
33
34
  }
@@ -52,6 +52,7 @@ function collectPathItem(data, pathItems, path) {
52
52
  }
53
53
  function collectSchema(data, schemas) {
54
54
  collect(data, schemas, (data, schema) => {
55
+ var _a;
55
56
  const key = `${schema.$src.file}#${schema.$src.path}`;
56
57
  if (data.schemas.has(key))
57
58
  return;
@@ -71,6 +72,9 @@ function collectSchema(data, schemas) {
71
72
  if (typeof schema.additionalItems === 'object') {
72
73
  collectSchema(data, schema.additionalItems);
73
74
  }
75
+ if (typeof schema.discriminator === 'object') {
76
+ collectRecord(data, (_a = schema.discriminator) === null || _a === void 0 ? void 0 : _a.mapping, collectSchema);
77
+ }
74
78
  });
75
79
  }
76
80
  function collectParameter(data, parameters) {
@@ -8,6 +8,7 @@ import YAML from 'yaml';
8
8
  import { createDerefProxy } from './deref-proxy';
9
9
  import { collectOpenApi } from '../collect/collector';
10
10
  import { transformOpenApi } from '../transform/transformer';
11
+ import { isNullish } from '../utils';
11
12
  export class OpenApiParser {
12
13
  constructor() {
13
14
  this._loadedDocuments = new Map();
@@ -58,7 +59,9 @@ export class OpenApiParser {
58
59
  if (key === '$ref')
59
60
  continue;
60
61
  const v = value[key];
61
- if (v && typeof v === 'object') {
62
+ if (isNullish(v))
63
+ continue;
64
+ if (typeof v === 'object') {
62
65
  if (Array.isArray(v)) {
63
66
  result[key] = yield Promise.all(v.map((v, index) => __awaiter(this, void 0, void 0, function* () {
64
67
  if (v && typeof v === 'object') {
@@ -73,6 +76,9 @@ export class OpenApiParser {
73
76
  result[key] = yield this.dereference(file, `${path}/${String(key)}`, v);
74
77
  }
75
78
  }
79
+ if (typeof v === 'string' && path.endsWith('/discriminator/mapping')) {
80
+ result[key] = yield this.resolveReference(file, { $ref: v });
81
+ }
76
82
  }
77
83
  return result;
78
84
  });
@@ -1,6 +1,6 @@
1
1
  import { determineSchemaAccessibility, determineSchemaKind, determineSchemaName, getCustomFields, getOpenApiObjectIdentifier, transformAdditionalProperties, transformSchemaProperties, } from './helpers';
2
2
  import { createOverwriteProxy } from '../utils';
3
- export function transformSchema(context, schema, isReference = false) {
3
+ export function transformSchema(context, schema) {
4
4
  var _a, _b;
5
5
  if (!schema) {
6
6
  throw new Error('Schema is required.');
@@ -30,12 +30,11 @@ export function transformSchema(context, schema, isReference = false) {
30
30
  kind = determineSchemaKind(schema);
31
31
  }
32
32
  }
33
- const ref = schema.$ref ? transformSchema(context, schema.$ref, true) : undefined;
34
33
  const id = context.idGenerator.generateId('schema');
35
34
  const nameInfo = determineSchemaName(schema, id);
36
- const result = {
35
+ const incompleteSchema = {
37
36
  $src: Object.assign(Object.assign({}, schema.$src), { component: schema }),
38
- $ref: ref,
37
+ $ref: undefined,
39
38
  id,
40
39
  name: nameInfo.name,
41
40
  isNameGenerated: nameInfo.isGenerated,
@@ -51,16 +50,25 @@ export function transformSchema(context, schema, isReference = false) {
51
50
  custom: getCustomFields(schema),
52
51
  not: schema.not ? transformSchema(context, schema.not) : undefined,
53
52
  const: schema.const,
53
+ discriminator: schema.discriminator
54
+ ? {
55
+ propertyName: typeof schema.discriminator === 'string' ? schema.discriminator : schema.discriminator.propertyName,
56
+ mapping: {},
57
+ }
58
+ : undefined,
59
+ inheritedSchemas: [],
54
60
  };
55
- context.incompleteSchemas.set(schemaSource, result);
61
+ context.incompleteSchemas.set(schemaSource, incompleteSchema);
62
+ if (schema.$ref) {
63
+ incompleteSchema.$ref = transformSchema(context, schema.$ref);
64
+ }
56
65
  const extensions = schemaTransformers[kind](schema, context);
57
- Object.assign(result, extensions);
66
+ const completeSchema = Object.assign(incompleteSchema, extensions);
67
+ resolveDescriminatorMapping(context, completeSchema);
58
68
  context.incompleteSchemas.delete(schemaSource);
59
- context.transformed.schemas.set(openApiObjectId, result);
60
- if (!isReference) {
61
- context.schemas.set(schemaSource, result);
62
- }
63
- return result;
69
+ context.transformed.schemas.set(openApiObjectId, completeSchema);
70
+ context.schemas.set(schemaSource, completeSchema);
71
+ return completeSchema;
64
72
  }
65
73
  const schemaTransformers = {
66
74
  oneOf: (schema, context) => {
@@ -135,3 +143,14 @@ const schemaTransformers = {
135
143
  null: () => ({ type: 'null' }),
136
144
  unknown: () => ({}),
137
145
  };
146
+ function resolveDescriminatorMapping(context, schema) {
147
+ const discriminator = schema.$src.component.discriminator;
148
+ if (!discriminator || typeof discriminator === 'string' || !discriminator.mapping)
149
+ return;
150
+ for (const key of Object.keys(discriminator.mapping)) {
151
+ const mappedSchemaRef = discriminator.mapping[key];
152
+ const mappedSchema = transformSchema(context, mappedSchemaRef);
153
+ schema.discriminator.mapping[key] = mappedSchema;
154
+ mappedSchema.inheritedSchemas.push(schema);
155
+ }
156
+ }