···11+// This file is auto-generated by @hey-api/openapi-ts
22+33+export type { CarDto, ClientOptions, GetCarsData, GetCarsResponse, GetCarsResponses, VehicleDto, VolvoDto } from './types.gen';
···11+// This file is auto-generated by @hey-api/openapi-ts
22+33+export type { CarDto, ClientOptions, GetCarsData, GetCarsResponse, GetCarsResponses, VehicleDto, VolvoDto } from './types.gen';
···2828 return;
2929};
30303131+/**
3232+ * Recursively finds discriminators in a schema, including nested allOf compositions.
3333+ * This is needed when a schema extends another schema via allOf, and that parent
3434+ * schema is itself an allOf composition with discriminators in inline schemas.
3535+ */
3636+const findDiscriminatorsInSchema = ({
3737+ context,
3838+ discriminators = [],
3939+ schema,
4040+}: {
4141+ context: Context;
4242+ discriminators?: Array<{
4343+ discriminator: NonNullable<SchemaObject['discriminator']>;
4444+ oneOf?: SchemaObject['oneOf'];
4545+ }>;
4646+ schema: SchemaObject;
4747+}): Array<{
4848+ discriminator: NonNullable<SchemaObject['discriminator']>;
4949+ oneOf?: SchemaObject['oneOf'];
5050+}> => {
5151+ // Check if this schema has a discriminator
5252+ if (schema.discriminator) {
5353+ discriminators.push({
5454+ discriminator: schema.discriminator,
5555+ oneOf: schema.oneOf,
5656+ });
5757+ }
5858+5959+ // If this schema is an allOf composition, recursively search in its components
6060+ if (schema.allOf) {
6161+ for (const compositionSchema of schema.allOf) {
6262+ let resolvedSchema: SchemaObject;
6363+ if ('$ref' in compositionSchema) {
6464+ resolvedSchema = context.resolveRef<SchemaObject>(
6565+ compositionSchema.$ref,
6666+ );
6767+ } else {
6868+ resolvedSchema = compositionSchema;
6969+ }
7070+7171+ findDiscriminatorsInSchema({
7272+ context,
7373+ discriminators,
7474+ schema: resolvedSchema,
7575+ });
7676+ }
7777+ }
7878+7979+ return discriminators;
8080+};
8181+8282+/**
8383+ * Gets all discriminator values for a schema and its children in the inheritance hierarchy.
8484+ * For intermediate schemas (those that are extended by others), returns a union of all values.
8585+ */
8686+const getAllDiscriminatorValues = ({
8787+ context,
8888+ discriminator,
8989+ schemaRef,
9090+}: {
9191+ context: Context;
9292+ discriminator: NonNullable<SchemaObject['discriminator']>;
9393+ schemaRef: string;
9494+}): Array<string> => {
9595+ const values: Array<string> = [];
9696+9797+ // Check each entry in the discriminator mapping
9898+ for (const [value, mappedSchemaRef] of Object.entries(
9999+ discriminator.mapping || {},
100100+ )) {
101101+ if (mappedSchemaRef === schemaRef) {
102102+ // This is the current schema's own value
103103+ values.push(value);
104104+ continue;
105105+ }
106106+107107+ // Check if the mapped schema extends the current schema
108108+ const mappedSchema = context.resolveRef<SchemaObject>(mappedSchemaRef);
109109+ if (mappedSchema.allOf) {
110110+ for (const item of mappedSchema.allOf) {
111111+ if ('$ref' in item && item.$ref === schemaRef) {
112112+ // This schema extends the current schema, add its value
113113+ values.push(value);
114114+ break;
115115+ }
116116+ }
117117+ }
118118+ }
119119+120120+ return values;
121121+};
122122+31123const parseSchemaJsDoc = ({
32124 irSchema,
33125 schema,
···307399308400 const compositionSchemas = schema.allOf;
309401402402+ // Collect discriminator information to add after all compositions are processed
403403+ type DiscriminatorInfo = {
404404+ discriminator: NonNullable<SchemaObject['discriminator']>;
405405+ isRequired: boolean;
406406+ values: ReadonlyArray<string>;
407407+ };
408408+ const discriminatorsToAdd: Array<DiscriminatorInfo> = [];
409409+ const addedDiscriminators = new Set<string>();
410410+310411 for (const compositionSchema of compositionSchemas) {
311412 const originalInAllOf = state.inAllOf;
312413 // Don't propagate inAllOf flag to $ref schemas to avoid issues with reusable components
···339440 if ('$ref' in compositionSchema) {
340441 const ref = context.resolveRef<SchemaObject>(compositionSchema.$ref);
341442 // `$ref` should be passed from the root `parseSchema()` call
342342- if (ref.discriminator && state.$ref) {
343343- const values = discriminatorValues(
344344- state.$ref,
345345- ref.discriminator.mapping,
346346- // If the ref has oneOf, we only use the schema name as the value
347347- // only if current schema is part of the oneOf. Else it is extending
348348- // the ref schema
349349- ref.oneOf
350350- ? () => ref.oneOf!.some((o) => '$ref' in o && o.$ref === state.$ref)
351351- : undefined,
352352- );
443443+ if (state.$ref) {
444444+ // Find all discriminators in the referenced schema, including nested allOf compositions
445445+ const discriminators = findDiscriminatorsInSchema({
446446+ context,
447447+ schema: ref,
448448+ });
353449354354- if (values.length > 0) {
355355- const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map(
356356- (value) => ({
357357- const: value,
358358- type: 'string',
359359- }),
450450+ // Process each discriminator found
451451+ for (const { discriminator, oneOf } of discriminators) {
452452+ // Skip if we've already collected this discriminator property
453453+ if (addedDiscriminators.has(discriminator.propertyName)) {
454454+ continue;
455455+ }
456456+457457+ const values = discriminatorValues(
458458+ state.$ref,
459459+ discriminator.mapping,
460460+ // If the ref has oneOf, we only use the schema name as the value
461461+ // only if current schema is part of the oneOf. Else it is extending
462462+ // the ref schema
463463+ oneOf
464464+ ? () => oneOf.some((o) => '$ref' in o && o.$ref === state.$ref)
465465+ : undefined,
360466 );
361361- const irDiscriminatorSchema: IR.SchemaObject = {
362362- properties: {
363363- [ref.discriminator.propertyName]:
364364- valueSchemas.length > 1
365365- ? {
366366- items: valueSchemas,
367367- logicalOperator: 'or',
368368- }
369369- : valueSchemas[0]!,
370370- },
371371- type: 'object',
372372- };
373373- if (ref.required?.includes(ref.discriminator.propertyName)) {
374374- irDiscriminatorSchema.required = [ref.discriminator.propertyName];
467467+468468+ if (values.length > 0) {
469469+ // Check if the discriminator property is required in any of the discriminator schemas
470470+ const isRequired = discriminators.some(
471471+ (d) =>
472472+ d.discriminator.propertyName === discriminator.propertyName &&
473473+ // Check in the ref's required array or in the allOf components
474474+ (ref.required?.includes(d.discriminator.propertyName) ||
475475+ (ref.allOf &&
476476+ ref.allOf.some((item) => {
477477+ const resolvedItem =
478478+ '$ref' in item
479479+ ? context.resolveRef<SchemaObject>(item.$ref)
480480+ : item;
481481+ return resolvedItem.required?.includes(
482482+ d.discriminator.propertyName,
483483+ );
484484+ }))),
485485+ );
486486+487487+ discriminatorsToAdd.push({
488488+ discriminator,
489489+ isRequired,
490490+ values,
491491+ });
492492+ addedDiscriminators.add(discriminator.propertyName);
493493+ }
494494+ }
495495+ }
496496+ }
497497+ }
498498+499499+ // Now add discriminators after all compositions have been processed
500500+ for (const { discriminator, isRequired, values } of discriminatorsToAdd) {
501501+ // Get all discriminator values including children for union types
502502+ const allValues = getAllDiscriminatorValues({
503503+ context,
504504+ discriminator,
505505+ schemaRef: state.$ref!,
506506+ });
507507+508508+ // Use allValues if we found children, otherwise use the original values
509509+ const finalValues = allValues.length > 0 ? allValues : values;
510510+511511+ const valueSchemas: ReadonlyArray<IR.SchemaObject> = finalValues.map(
512512+ (value) => ({
513513+ const: value,
514514+ type: 'string',
515515+ }),
516516+ );
517517+518518+ const discriminatorProperty: IR.SchemaObject =
519519+ valueSchemas.length > 1
520520+ ? {
521521+ items: valueSchemas,
522522+ logicalOperator: 'or',
375523 }
376376- schemaItems.push(irDiscriminatorSchema);
524524+ : valueSchemas[0]!;
525525+526526+ // Find the inline schema (non-$ref) to merge the discriminator property into
527527+ // The inline schema should be the last non-$ref item in schemaItems
528528+ let inlineSchema: IR.SchemaObject | undefined;
529529+ for (let i = schemaItems.length - 1; i >= 0; i--) {
530530+ const item = schemaItems[i]!;
531531+ // Check if this is not a $ref schema by looking for properties or checking if it came from an inline schema
532532+ if (item.type === 'object' || item.properties) {
533533+ inlineSchema = item;
534534+ break;
535535+ }
536536+ }
537537+538538+ // If we found an inline schema, add the discriminator property to it
539539+ if (inlineSchema) {
540540+ if (!inlineSchema.properties) {
541541+ inlineSchema.properties = {};
542542+ }
543543+ inlineSchema.properties[discriminator.propertyName] =
544544+ discriminatorProperty;
545545+546546+ if (isRequired) {
547547+ if (!inlineSchema.required) {
548548+ inlineSchema.required = [];
549549+ }
550550+ if (!inlineSchema.required.includes(discriminator.propertyName)) {
551551+ inlineSchema.required = [
552552+ ...inlineSchema.required,
553553+ discriminator.propertyName,
554554+ ];
377555 }
378556 }
557557+ } else {
558558+ // Fallback: create a separate discriminator schema if no inline schema found
559559+ const irDiscriminatorSchema: IR.SchemaObject = {
560560+ properties: {
561561+ [discriminator.propertyName]: discriminatorProperty,
562562+ },
563563+ type: 'object',
564564+ };
565565+566566+ if (isRequired) {
567567+ irDiscriminatorSchema.required = [discriminator.propertyName];
568568+ }
569569+ schemaItems.push(irDiscriminatorSchema);
379570 }
380571 }
381572
···3232 return [];
3333};
34343535+/**
3636+ * Recursively finds discriminators in a schema, including nested allOf compositions.
3737+ * This is needed when a schema extends another schema via allOf, and that parent
3838+ * schema is itself an allOf composition with discriminators in inline schemas.
3939+ */
4040+const findDiscriminatorsInSchema = ({
4141+ context,
4242+ discriminators = [],
4343+ schema,
4444+}: {
4545+ context: Context;
4646+ discriminators?: Array<{
4747+ discriminator: NonNullable<SchemaObject['discriminator']>;
4848+ oneOf?: SchemaObject['oneOf'];
4949+ }>;
5050+ schema: SchemaObject;
5151+}): Array<{
5252+ discriminator: NonNullable<SchemaObject['discriminator']>;
5353+ oneOf?: SchemaObject['oneOf'];
5454+}> => {
5555+ // Check if this schema has a discriminator
5656+ if (schema.discriminator) {
5757+ discriminators.push({
5858+ discriminator: schema.discriminator,
5959+ oneOf: schema.oneOf,
6060+ });
6161+ }
6262+6363+ // If this schema is an allOf composition, recursively search in its components
6464+ if (schema.allOf) {
6565+ for (const compositionSchema of schema.allOf) {
6666+ let resolvedSchema: SchemaObject;
6767+ if (compositionSchema.$ref) {
6868+ resolvedSchema = context.resolveRef<SchemaObject>(
6969+ compositionSchema.$ref,
7070+ );
7171+ } else {
7272+ resolvedSchema = compositionSchema;
7373+ }
7474+7575+ findDiscriminatorsInSchema({
7676+ context,
7777+ discriminators,
7878+ schema: resolvedSchema,
7979+ });
8080+ }
8181+ }
8282+8383+ return discriminators;
8484+};
8585+8686+/**
8787+ * Gets all discriminator values for a schema and its children in the inheritance hierarchy.
8888+ * For intermediate schemas (those that are extended by others), returns a union of all values.
8989+ */
9090+const getAllDiscriminatorValues = ({
9191+ context,
9292+ discriminator,
9393+ schemaRef,
9494+}: {
9595+ context: Context;
9696+ discriminator: NonNullable<SchemaObject['discriminator']>;
9797+ schemaRef: string;
9898+}): Array<string> => {
9999+ const values: Array<string> = [];
100100+101101+ // Check each entry in the discriminator mapping
102102+ for (const [value, mappedSchemaRef] of Object.entries(
103103+ discriminator.mapping || {},
104104+ )) {
105105+ if (mappedSchemaRef === schemaRef) {
106106+ // This is the current schema's own value
107107+ values.push(value);
108108+ continue;
109109+ }
110110+111111+ // Check if the mapped schema extends the current schema
112112+ const mappedSchema = context.resolveRef<SchemaObject>(mappedSchemaRef);
113113+ if (mappedSchema.allOf) {
114114+ for (const item of mappedSchema.allOf) {
115115+ if (item.$ref && item.$ref === schemaRef) {
116116+ // This schema extends the current schema, add its value
117117+ values.push(value);
118118+ break;
119119+ }
120120+ }
121121+ }
122122+ }
123123+124124+ return values;
125125+};
126126+35127const parseSchemaJsDoc = ({
36128 irSchema,
37129 schema,
···389481390482 const compositionSchemas = schema.allOf;
391483484484+ // Collect discriminator information to add after all compositions are processed
485485+ type DiscriminatorInfo = {
486486+ discriminator: NonNullable<SchemaObject['discriminator']>;
487487+ isRequired: boolean;
488488+ values: ReadonlyArray<string>;
489489+ };
490490+ const discriminatorsToAdd: Array<DiscriminatorInfo> = [];
491491+ const addedDiscriminators = new Set<string>();
492492+392493 for (const compositionSchema of compositionSchemas) {
393494 const originalInAllOf = state.inAllOf;
394495 // Don't propagate inAllOf flag to $ref schemas to avoid issues with reusable components
···421522 if (compositionSchema.$ref) {
422523 const ref = context.resolveRef<SchemaObject>(compositionSchema.$ref);
423524 // `$ref` should be passed from the root `parseSchema()` call
424424- if (ref.discriminator && state.$ref) {
425425- const values = discriminatorValues(
426426- state.$ref,
427427- ref.discriminator.mapping,
428428- // If the ref has oneOf, we only use the schema name as the value
429429- // only if current schema is part of the oneOf. Else it is extending
430430- // the ref schema
431431- ref.oneOf
432432- ? () => ref.oneOf!.some((o) => '$ref' in o && o.$ref === state.$ref)
433433- : undefined,
434434- );
435435- if (values.length > 0) {
436436- const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map(
437437- (value) => ({
438438- const: value,
439439- type: 'string',
440440- }),
525525+ if (state.$ref) {
526526+ // Find all discriminators in the referenced schema, including nested allOf compositions
527527+ const discriminators = findDiscriminatorsInSchema({
528528+ context,
529529+ schema: ref,
530530+ });
531531+532532+ // Process each discriminator found
533533+ for (const { discriminator, oneOf } of discriminators) {
534534+ // Skip if we've already collected this discriminator property
535535+ if (addedDiscriminators.has(discriminator.propertyName)) {
536536+ continue;
537537+ }
538538+539539+ const values = discriminatorValues(
540540+ state.$ref,
541541+ discriminator.mapping,
542542+ // If the ref has oneOf, we only use the schema name as the value
543543+ // only if current schema is part of the oneOf. Else it is extending
544544+ // the ref schema
545545+ oneOf
546546+ ? () => oneOf.some((o) => '$ref' in o && o.$ref === state.$ref)
547547+ : undefined,
441548 );
442442- const irDiscriminatorSchema: IR.SchemaObject = {
443443- properties: {
444444- [ref.discriminator.propertyName]:
445445- valueSchemas.length > 1
446446- ? {
447447- items: valueSchemas,
448448- logicalOperator: 'or',
449449- }
450450- : valueSchemas[0]!,
451451- },
452452- type: 'object',
453453- };
454454- if (ref.required?.includes(ref.discriminator.propertyName)) {
455455- irDiscriminatorSchema.required = [ref.discriminator.propertyName];
549549+550550+ if (values.length > 0) {
551551+ // Check if the discriminator property is required in any of the discriminator schemas
552552+ const isRequired = discriminators.some(
553553+ (d) =>
554554+ d.discriminator.propertyName === discriminator.propertyName &&
555555+ // Check in the ref's required array or in the allOf components
556556+ (ref.required?.includes(d.discriminator.propertyName) ||
557557+ (ref.allOf &&
558558+ ref.allOf.some((item) => {
559559+ const resolvedItem = item.$ref
560560+ ? context.resolveRef<SchemaObject>(item.$ref)
561561+ : item;
562562+ return resolvedItem.required?.includes(
563563+ d.discriminator.propertyName,
564564+ );
565565+ }))),
566566+ );
567567+568568+ discriminatorsToAdd.push({
569569+ discriminator,
570570+ isRequired,
571571+ values,
572572+ });
573573+ addedDiscriminators.add(discriminator.propertyName);
574574+ }
575575+ }
576576+ }
577577+ }
578578+ }
579579+580580+ // Now add discriminators after all compositions have been processed
581581+ for (const { discriminator, isRequired, values } of discriminatorsToAdd) {
582582+ // Get all discriminator values including children for union types
583583+ const allValues = getAllDiscriminatorValues({
584584+ context,
585585+ discriminator,
586586+ schemaRef: state.$ref!,
587587+ });
588588+589589+ // Use allValues if we found children, otherwise use the original values
590590+ const finalValues = allValues.length > 0 ? allValues : values;
591591+592592+ const valueSchemas: ReadonlyArray<IR.SchemaObject> = finalValues.map(
593593+ (value) => ({
594594+ const: value,
595595+ type: 'string',
596596+ }),
597597+ );
598598+599599+ const discriminatorProperty: IR.SchemaObject =
600600+ valueSchemas.length > 1
601601+ ? {
602602+ items: valueSchemas,
603603+ logicalOperator: 'or',
456604 }
457457- schemaItems.push(irDiscriminatorSchema);
605605+ : valueSchemas[0]!;
606606+607607+ // Find the inline schema (non-$ref) to merge the discriminator property into
608608+ // The inline schema should be the last non-$ref item in schemaItems
609609+ let inlineSchema: IR.SchemaObject | undefined;
610610+ for (let i = schemaItems.length - 1; i >= 0; i--) {
611611+ const item = schemaItems[i]!;
612612+ // Check if this is not a $ref schema by looking for properties or checking if it came from an inline schema
613613+ if (item.type === 'object' || item.properties) {
614614+ inlineSchema = item;
615615+ break;
616616+ }
617617+ }
618618+619619+ // If we found an inline schema, add the discriminator property to it
620620+ if (inlineSchema) {
621621+ if (!inlineSchema.properties) {
622622+ inlineSchema.properties = {};
623623+ }
624624+ inlineSchema.properties[discriminator.propertyName] =
625625+ discriminatorProperty;
626626+627627+ if (isRequired) {
628628+ if (!inlineSchema.required) {
629629+ inlineSchema.required = [];
630630+ }
631631+ if (!inlineSchema.required.includes(discriminator.propertyName)) {
632632+ inlineSchema.required = [
633633+ ...inlineSchema.required,
634634+ discriminator.propertyName,
635635+ ];
458636 }
459637 }
638638+ } else {
639639+ // Fallback: create a separate discriminator schema if no inline schema found
640640+ const irDiscriminatorSchema: IR.SchemaObject = {
641641+ properties: {
642642+ [discriminator.propertyName]: discriminatorProperty,
643643+ },
644644+ type: 'object',
645645+ };
646646+647647+ if (isRequired) {
648648+ irDiscriminatorSchema.required = [discriminator.propertyName];
649649+ }
650650+ schemaItems.push(irDiscriminatorSchema);
460651 }
461652 }
462653