@hey-api/shared 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5,6 +5,7 @@ import ts from "typescript";
5
5
  import { sync } from "cross-spawn";
6
6
  import * as semver from "semver";
7
7
  import { getResolvedInput, sendRequest } from "@hey-api/json-schema-ref-parser";
8
+ import { fromRef, ref } from "@hey-api/codegen-core";
8
9
  import { EOL } from "node:os";
9
10
 
10
11
  //#region src/tsConfig.ts
@@ -709,7 +710,8 @@ function getParser(userConfig) {
709
710
  case: "preserve",
710
711
  name: "{{name}}"
711
712
  }
712
- }
713
+ },
714
+ schemaName: void 0
713
715
  },
714
716
  validate_EXPERIMENTAL: false
715
717
  },
@@ -763,7 +765,8 @@ function getParser(userConfig) {
763
765
  })
764
766
  },
765
767
  value: fields$1.readWrite
766
- })
768
+ }),
769
+ schemaName: fields$1.schemaName !== void 0 ? fields$1.schemaName : defaultValue$1.schemaName
767
770
  }) },
768
771
  value: fields.transforms
769
772
  }),
@@ -1384,9 +1387,10 @@ async function getSpec({ fetchOptions, inputPath, timeout, watch }) {
1384
1387
  };
1385
1388
  response = request.response;
1386
1389
  } catch (error) {
1390
+ const message = error instanceof Error ? error.message : String(error);
1387
1391
  return {
1388
1392
  error: "not-ok",
1389
- response: new Response(error instanceof Error ? error.message : String(error))
1393
+ response: new Response(message, { status: 500 })
1390
1394
  };
1391
1395
  }
1392
1396
  if (!response.ok && watch.isHeadMethodSupported) return {
@@ -1432,9 +1436,10 @@ async function getSpec({ fetchOptions, inputPath, timeout, watch }) {
1432
1436
  };
1433
1437
  response = request.response;
1434
1438
  } catch (error) {
1439
+ const message = error instanceof Error ? error.message : String(error);
1435
1440
  return {
1436
1441
  error: "not-ok",
1437
- response: new Response(error instanceof Error ? error.message : String(error))
1442
+ response: new Response(message, { status: 500 })
1438
1443
  };
1439
1444
  }
1440
1445
  if (!response.ok) return {
@@ -2272,6 +2277,112 @@ var IntentContext = class {
2272
2277
  }
2273
2278
  };
2274
2279
 
2280
+ //#endregion
2281
+ //#region src/ir/schema-processor.ts
2282
+ function createSchemaProcessor() {
2283
+ const emitted = /* @__PURE__ */ new Set();
2284
+ let contextTags;
2285
+ let contextAnchor;
2286
+ return {
2287
+ get context() {
2288
+ return {
2289
+ anchor: contextAnchor,
2290
+ tags: contextTags
2291
+ };
2292
+ },
2293
+ hasEmitted(path$1) {
2294
+ return emitted.has(pathToJsonPointer(path$1));
2295
+ },
2296
+ markEmitted(path$1) {
2297
+ const pointer = pathToJsonPointer(path$1);
2298
+ if (emitted.has(pointer)) return false;
2299
+ emitted.add(pointer);
2300
+ return true;
2301
+ },
2302
+ withContext(ctx, fn) {
2303
+ const prevTags = contextTags;
2304
+ const prevAnchor = contextAnchor;
2305
+ contextTags = ctx.tags;
2306
+ contextAnchor = ctx.anchor;
2307
+ try {
2308
+ return fn();
2309
+ } finally {
2310
+ contextTags = prevTags;
2311
+ contextAnchor = prevAnchor;
2312
+ }
2313
+ }
2314
+ };
2315
+ }
2316
+
2317
+ //#endregion
2318
+ //#region src/ir/schema-walker.ts
2319
+ /**
2320
+ * Create a schema walker from a visitor.
2321
+ *
2322
+ * The walker handles:
2323
+ * - Dispatch order ($ref → type → items → fallback)
2324
+ * - Deduplication of union/intersection schemas
2325
+ * - Path tracking for child schemas
2326
+ */
2327
+ function createSchemaWalker(visitor) {
2328
+ const walk$1 = (schema, ctx) => {
2329
+ if (visitor.intercept) {
2330
+ const intercepted = visitor.intercept(schema, ctx, walk$1);
2331
+ if (intercepted !== void 0) return intercepted;
2332
+ }
2333
+ if (schema.$ref) return visitor.reference(schema.$ref, schema, ctx);
2334
+ if (schema.type) {
2335
+ let result = visitTyped(schema, ctx, visitor, walk$1);
2336
+ if (visitor.postProcess) result = visitor.postProcess(result, schema, ctx);
2337
+ return result;
2338
+ }
2339
+ if (schema.items) {
2340
+ const deduplicated = deduplicateSchema({ schema });
2341
+ if (!deduplicated.items) return walk$1(deduplicated, ctx);
2342
+ const itemResults = deduplicated.items.map((item, index) => walk$1(item, {
2343
+ ...ctx,
2344
+ path: ref([
2345
+ ...fromRef(ctx.path),
2346
+ "items",
2347
+ index
2348
+ ])
2349
+ }));
2350
+ return deduplicated.logicalOperator === "and" ? visitor.intersection(itemResults, deduplicated.items, schema, ctx) : visitor.union(itemResults, deduplicated.items, schema, ctx);
2351
+ }
2352
+ return visitor.unknown({ type: "unknown" }, ctx);
2353
+ };
2354
+ return walk$1;
2355
+ }
2356
+ /**
2357
+ * Dispatch to the appropriate visitor method based on schema type.
2358
+ */
2359
+ function visitTyped(schema, ctx, visitor, walk$1) {
2360
+ switch (schema.type) {
2361
+ case "array": return visitor.array(schema, ctx, walk$1);
2362
+ case "boolean": return visitor.boolean(schema, ctx);
2363
+ case "enum": return visitor.enum(schema, ctx, walk$1);
2364
+ case "integer": return visitor.integer(schema, ctx);
2365
+ case "never": return visitor.never(schema, ctx);
2366
+ case "null": return visitor.null(schema, ctx);
2367
+ case "number": return visitor.number(schema, ctx);
2368
+ case "object": return visitor.object(schema, ctx, walk$1);
2369
+ case "string": return visitor.string(schema, ctx);
2370
+ case "tuple": return visitor.tuple(schema, ctx, walk$1);
2371
+ case "undefined": return visitor.undefined(schema, ctx);
2372
+ case "unknown": return visitor.unknown(schema, ctx);
2373
+ case "void": return visitor.void(schema, ctx);
2374
+ }
2375
+ }
2376
+ /**
2377
+ * Helper to create a child context with an extended path.
2378
+ */
2379
+ function childContext(ctx, ...segments) {
2380
+ return {
2381
+ ...ctx,
2382
+ path: ref([...fromRef(ctx.path), ...segments])
2383
+ };
2384
+ }
2385
+
2275
2386
  //#endregion
2276
2387
  //#region src/openApi/shared/utils/filter.ts
2277
2388
  const namespaceNeedle = "/";
@@ -2841,7 +2952,8 @@ const childSchemaRelationships = [
2841
2952
  ["patternProperties", "objectMap"],
2842
2953
  ["properties", "objectMap"],
2843
2954
  ["propertyNames", "single"],
2844
- ["then", "single"]
2955
+ ["then", "single"],
2956
+ ["unevaluatedProperties", "single"]
2845
2957
  ];
2846
2958
 
2847
2959
  //#endregion
@@ -3444,7 +3556,8 @@ const schemaKeys = new Set([
3444
3556
  "oneOf",
3445
3557
  "patternProperties",
3446
3558
  "properties",
3447
- "schema"
3559
+ "schema",
3560
+ "unevaluatedProperties"
3448
3561
  ]);
3449
3562
  const getComponentContext = (path$1) => {
3450
3563
  if (path$1.length === 3 && path$1[0] === "components") {
@@ -3961,11 +4074,56 @@ const readWriteTransform = ({ config, logger, spec }) => {
3961
4074
  });
3962
4075
  };
3963
4076
 
4077
+ //#endregion
4078
+ //#region src/openApi/shared/transforms/schemas.ts
4079
+ /**
4080
+ * Recursively walks the entire spec object and replaces all $ref strings
4081
+ * according to the provided rename mapping.
4082
+ */
4083
+ const rewriteRefs = (node, renameMap) => {
4084
+ if (node instanceof Array) node.forEach((item) => rewriteRefs(item, renameMap));
4085
+ else if (node && typeof node === "object") for (const [key, value] of Object.entries(node)) if (key === "$ref" && typeof value === "string" && value in renameMap) node[key] = renameMap[value];
4086
+ else rewriteRefs(value, renameMap);
4087
+ };
4088
+ /**
4089
+ * Renames schema component keys and updates all $ref pointers throughout
4090
+ * the spec. Handles collisions by skipping renames when the target name
4091
+ * already exists or conflicts with another rename.
4092
+ */
4093
+ const schemaNameTransform = ({ config, spec }) => {
4094
+ if (!config) return;
4095
+ const schemasObj = getSchemasObject(spec);
4096
+ if (!schemasObj) return;
4097
+ const schemasPointerNamespace = specToSchemasPointerNamespace(spec);
4098
+ if (!schemasPointerNamespace) return;
4099
+ const renameMap = {};
4100
+ const newNames = /* @__PURE__ */ new Set();
4101
+ const namingConfig = { name: config };
4102
+ for (const oldName of Object.keys(schemasObj)) {
4103
+ const newName = applyNaming(oldName, namingConfig);
4104
+ if (newName === oldName || newName in schemasObj || newNames.has(newName)) continue;
4105
+ renameMap[`${schemasPointerNamespace}${oldName}`] = `${schemasPointerNamespace}${newName}`;
4106
+ newNames.add(newName);
4107
+ }
4108
+ for (const [oldPointer, newPointer] of Object.entries(renameMap)) {
4109
+ const oldName = oldPointer.slice(schemasPointerNamespace.length);
4110
+ const newName = newPointer.slice(schemasPointerNamespace.length);
4111
+ const schema = schemasObj[oldName];
4112
+ delete schemasObj[oldName];
4113
+ schemasObj[newName] = schema;
4114
+ }
4115
+ if (Object.keys(renameMap).length > 0) rewriteRefs(spec, renameMap);
4116
+ };
4117
+
3964
4118
  //#endregion
3965
4119
  //#region src/openApi/shared/transforms/index.ts
3966
4120
  const transformOpenApiSpec = ({ context }) => {
3967
4121
  const { logger } = context;
3968
4122
  const eventTransformOpenApiSpec = logger.timeEvent("transform-openapi-spec");
4123
+ if (context.config.parser.transforms.schemaName) schemaNameTransform({
4124
+ config: context.config.parser.transforms.schemaName,
4125
+ spec: context.spec
4126
+ });
3969
4127
  if (context.config.parser.transforms.enums.enabled) enumsTransform({
3970
4128
  config: context.config.parser.transforms.enums,
3971
4129
  spec: context.spec
@@ -4132,6 +4290,64 @@ function getPaginationKeywordsRegExp(pagination) {
4132
4290
 
4133
4291
  //#endregion
4134
4292
  //#region src/openApi/shared/utils/discriminator.ts
4293
+ /**
4294
+ * Converts a string discriminator mapping value to the appropriate type based on
4295
+ * the actual property type in the schema.
4296
+ *
4297
+ * OpenAPI discriminator mappings always use string keys, but the actual discriminator
4298
+ * property may be a boolean, number, or integer. This function converts the string
4299
+ * key to the correct runtime value and IR type.
4300
+ */
4301
+ const convertDiscriminatorValue = (value, propertyType) => {
4302
+ switch (propertyType) {
4303
+ case "boolean": {
4304
+ const lowerValue = value.toLowerCase();
4305
+ if (lowerValue !== "true" && lowerValue !== "false") {
4306
+ console.warn("🚨", `non-boolean discriminator mapping value "${value}" for boolean property, falling back to string`);
4307
+ return {
4308
+ const: value,
4309
+ type: "string"
4310
+ };
4311
+ }
4312
+ return {
4313
+ const: lowerValue === "true",
4314
+ type: "boolean"
4315
+ };
4316
+ }
4317
+ case "integer": {
4318
+ const parsed = parseInt(value, 10);
4319
+ if (Number.isNaN(parsed)) {
4320
+ console.warn("🚨", `non-numeric discriminator mapping value "${value}" for integer property, falling back to string`);
4321
+ return {
4322
+ const: value,
4323
+ type: "string"
4324
+ };
4325
+ }
4326
+ return {
4327
+ const: parsed,
4328
+ type: "integer"
4329
+ };
4330
+ }
4331
+ case "number": {
4332
+ const parsed = parseFloat(value);
4333
+ if (Number.isNaN(parsed)) {
4334
+ console.warn("🚨", `non-numeric discriminator mapping value "${value}" for number property, falling back to string`);
4335
+ return {
4336
+ const: value,
4337
+ type: "string"
4338
+ };
4339
+ }
4340
+ return {
4341
+ const: parsed,
4342
+ type: "number"
4343
+ };
4344
+ }
4345
+ default: return {
4346
+ const: value,
4347
+ type: "string"
4348
+ };
4349
+ }
4350
+ };
4135
4351
  const discriminatorValues = ($ref, mapping, shouldUseRefAsValue) => {
4136
4352
  const values = [];
4137
4353
  for (const name in mapping) if (mapping[name] === $ref) values.push(name);
@@ -4263,20 +4479,20 @@ const parseAllOf$2 = ({ context, schema, state }) => {
4263
4479
  else irCompositionSchema.required = schema.required;
4264
4480
  schemaItems.push(irCompositionSchema);
4265
4481
  if (compositionSchema.$ref) {
4266
- const ref = context.resolveRef(compositionSchema.$ref);
4267
- if (ref.discriminator && state.$ref) {
4482
+ const ref$1 = context.resolveRef(compositionSchema.$ref);
4483
+ if (ref$1.discriminator && state.$ref) {
4268
4484
  const valueSchemas = discriminatorValues(state.$ref).map((value) => ({
4269
4485
  const: value,
4270
4486
  type: "string"
4271
4487
  }));
4272
4488
  const irDiscriminatorSchema = {
4273
- properties: { [ref.discriminator]: valueSchemas.length > 1 ? {
4489
+ properties: { [ref$1.discriminator]: valueSchemas.length > 1 ? {
4274
4490
  items: valueSchemas,
4275
4491
  logicalOperator: "or"
4276
4492
  } : valueSchemas[0] },
4277
4493
  type: "object"
4278
4494
  };
4279
- if (ref.required?.includes(ref.discriminator)) irDiscriminatorSchema.required = [ref.discriminator];
4495
+ if (ref$1.required?.includes(ref$1.discriminator)) irDiscriminatorSchema.required = [ref$1.discriminator];
4280
4496
  schemaItems.push(irDiscriminatorSchema);
4281
4497
  }
4282
4498
  }
@@ -4542,19 +4758,19 @@ const isPaginationType$2 = (schemaType) => schemaType === "boolean" || schemaTyp
4542
4758
  const paginationField$2 = ({ context, name, schema }) => {
4543
4759
  if (getPaginationKeywordsRegExp(context.config.parser.pagination).test(name)) return true;
4544
4760
  if ("$ref" in schema) {
4545
- const ref = context.resolveRef(schema.$ref ?? "");
4546
- if ("in" in ref && ref.in) return paginationField$2({
4761
+ const ref$1 = context.resolveRef(schema.$ref ?? "");
4762
+ if ("in" in ref$1 && ref$1.in) return paginationField$2({
4547
4763
  context,
4548
4764
  name,
4549
- schema: "schema" in ref ? ref.schema : {
4550
- ...ref,
4765
+ schema: "schema" in ref$1 ? ref$1.schema : {
4766
+ ...ref$1,
4551
4767
  in: void 0
4552
4768
  }
4553
4769
  });
4554
4770
  return paginationField$2({
4555
4771
  context,
4556
4772
  name,
4557
- schema: ref
4773
+ schema: ref$1
4558
4774
  });
4559
4775
  }
4560
4776
  if ("in" in schema) {
@@ -5275,6 +5491,29 @@ const getSchemaType = ({ schema }) => {
5275
5491
  if (schema.properties) return "object";
5276
5492
  };
5277
5493
  /**
5494
+ * Finds the type of a discriminator property by looking it up in the provided schemas.
5495
+ * Searches through properties and allOf chains to find the property definition.
5496
+ */
5497
+ const findDiscriminatorPropertyType$1 = ({ context, propertyName, schemas }) => {
5498
+ for (const schema of schemas) {
5499
+ const resolved = "$ref" in schema ? context.resolveRef(schema.$ref) : schema;
5500
+ const property = resolved.properties?.[propertyName];
5501
+ if (property) {
5502
+ const resolvedProperty = "$ref" in property ? context.resolveRef(property.$ref) : property;
5503
+ if (resolvedProperty.type === "boolean" || resolvedProperty.type === "integer" || resolvedProperty.type === "number") return resolvedProperty.type;
5504
+ }
5505
+ if (resolved.allOf) {
5506
+ const foundType = findDiscriminatorPropertyType$1({
5507
+ context,
5508
+ propertyName,
5509
+ schemas: resolved.allOf
5510
+ });
5511
+ if (foundType !== "string") return foundType;
5512
+ }
5513
+ }
5514
+ return "string";
5515
+ };
5516
+ /**
5278
5517
  * Recursively finds discriminators in a schema, including nested allOf compositions.
5279
5518
  * This is needed when a schema extends another schema via allOf, and that parent
5280
5519
  * schema is itself an allOf composition with discriminators in inline schemas.
@@ -5412,7 +5651,6 @@ const parseAllOf$1 = ({ context, schema, state }) => {
5412
5651
  const schemaType = getSchemaType({ schema });
5413
5652
  const compositionSchemas = schema.allOf;
5414
5653
  const discriminatorsToAdd = [];
5415
- const addedDiscriminators = /* @__PURE__ */ new Set();
5416
5654
  for (const compositionSchema of compositionSchemas) {
5417
5655
  const originalInAllOf = state.inAllOf;
5418
5656
  if (!("$ref" in compositionSchema)) state.inAllOf = true;
@@ -5427,26 +5665,28 @@ const parseAllOf$1 = ({ context, schema, state }) => {
5427
5665
  else irCompositionSchema.required = schema.required;
5428
5666
  schemaItems.push(irCompositionSchema);
5429
5667
  if ("$ref" in compositionSchema) {
5430
- const ref = context.resolveRef(compositionSchema.$ref);
5668
+ const ref$1 = context.resolveRef(compositionSchema.$ref);
5431
5669
  if (state.$ref) {
5432
5670
  const discriminators = findDiscriminatorsInSchema$1({
5433
5671
  context,
5434
- schema: ref
5672
+ schema: ref$1
5435
5673
  });
5436
5674
  for (const { discriminator, oneOf } of discriminators) {
5437
- if (addedDiscriminators.has(discriminator.propertyName)) continue;
5438
5675
  const values = discriminatorValues(state.$ref, discriminator.mapping, oneOf ? () => oneOf.some((o) => "$ref" in o && o.$ref === state.$ref) : void 0);
5439
- if (values.length > 0) {
5440
- const isRequired = discriminators.some((d) => d.discriminator.propertyName === discriminator.propertyName && (ref.required?.includes(d.discriminator.propertyName) || ref.allOf && ref.allOf.some((item) => {
5441
- return ("$ref" in item ? context.resolveRef(item.$ref) : item).required?.includes(d.discriminator.propertyName);
5442
- })));
5443
- discriminatorsToAdd.push({
5444
- discriminator,
5445
- isRequired,
5446
- values
5447
- });
5448
- addedDiscriminators.add(discriminator.propertyName);
5449
- }
5676
+ if (values.length === 0) continue;
5677
+ const isExplicitMapping = discriminator.mapping !== void 0 && Object.values(discriminator.mapping).includes(state.$ref);
5678
+ const existingIndex = discriminatorsToAdd.findIndex((d) => d.discriminator.propertyName === discriminator.propertyName);
5679
+ if (existingIndex !== -1) if (isExplicitMapping && !discriminatorsToAdd[existingIndex].isExplicitMapping) discriminatorsToAdd.splice(existingIndex, 1);
5680
+ else continue;
5681
+ const isRequired = discriminators.some((d) => d.discriminator.propertyName === discriminator.propertyName && (ref$1.required?.includes(d.discriminator.propertyName) || ref$1.allOf && ref$1.allOf.some((item) => {
5682
+ return ("$ref" in item ? context.resolveRef(item.$ref) : item).required?.includes(d.discriminator.propertyName);
5683
+ })));
5684
+ discriminatorsToAdd.push({
5685
+ discriminator,
5686
+ isExplicitMapping,
5687
+ isRequired,
5688
+ values
5689
+ });
5450
5690
  }
5451
5691
  }
5452
5692
  }
@@ -5456,10 +5696,13 @@ const parseAllOf$1 = ({ context, schema, state }) => {
5456
5696
  discriminator,
5457
5697
  schemaRef: state.$ref
5458
5698
  });
5459
- const valueSchemas = (allValues.length > 0 ? allValues : values).map((value) => ({
5460
- const: value,
5461
- type: "string"
5462
- }));
5699
+ const finalValues = allValues.length > 0 ? allValues : values;
5700
+ const propertyType = findDiscriminatorPropertyType$1({
5701
+ context,
5702
+ propertyName: discriminator.propertyName,
5703
+ schemas: compositionSchemas
5704
+ });
5705
+ const valueSchemas = finalValues.map((value) => convertDiscriminatorValue(value, propertyType));
5463
5706
  const discriminatorProperty = valueSchemas.length > 1 ? {
5464
5707
  items: valueSchemas,
5465
5708
  logicalOperator: "or"
@@ -5557,6 +5800,11 @@ const parseAnyOf$1 = ({ context, schema, state }) => {
5557
5800
  const schemaItems = [];
5558
5801
  const schemaType = getSchemaType({ schema });
5559
5802
  const compositionSchemas = schema.anyOf;
5803
+ const discriminatorPropertyType = schema.discriminator ? findDiscriminatorPropertyType$1({
5804
+ context,
5805
+ propertyName: schema.discriminator.propertyName,
5806
+ schemas: compositionSchemas
5807
+ }) : void 0;
5560
5808
  for (const compositionSchema of compositionSchemas) {
5561
5809
  let irCompositionSchema = schemaToIrSchema$1({
5562
5810
  context,
@@ -5564,10 +5812,7 @@ const parseAnyOf$1 = ({ context, schema, state }) => {
5564
5812
  state
5565
5813
  });
5566
5814
  if (schema.discriminator && irCompositionSchema.$ref != null) {
5567
- const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => ({
5568
- const: value,
5569
- type: "string"
5570
- }));
5815
+ const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => convertDiscriminatorValue(value, discriminatorPropertyType));
5571
5816
  irCompositionSchema = {
5572
5817
  items: [{
5573
5818
  properties: { [schema.discriminator.propertyName]: valueSchemas.length > 1 ? {
@@ -5641,6 +5886,11 @@ const parseOneOf$1 = ({ context, schema, state }) => {
5641
5886
  let schemaItems = [];
5642
5887
  const schemaType = getSchemaType({ schema });
5643
5888
  const compositionSchemas = schema.oneOf;
5889
+ const discriminatorPropertyType = schema.discriminator ? findDiscriminatorPropertyType$1({
5890
+ context,
5891
+ propertyName: schema.discriminator.propertyName,
5892
+ schemas: compositionSchemas
5893
+ }) : void 0;
5644
5894
  for (const compositionSchema of compositionSchemas) {
5645
5895
  let irCompositionSchema = schemaToIrSchema$1({
5646
5896
  context,
@@ -5648,10 +5898,7 @@ const parseOneOf$1 = ({ context, schema, state }) => {
5648
5898
  state
5649
5899
  });
5650
5900
  if (schema.discriminator && irCompositionSchema.$ref != null) {
5651
- const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => ({
5652
- const: value,
5653
- type: "string"
5654
- }));
5901
+ const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => convertDiscriminatorValue(value, discriminatorPropertyType));
5655
5902
  irCompositionSchema = {
5656
5903
  items: [{
5657
5904
  properties: { [schema.discriminator.propertyName]: valueSchemas.length > 1 ? {
@@ -5878,12 +6125,12 @@ const isPaginationType$1 = (schemaType) => schemaType === "boolean" || schemaTyp
5878
6125
  const paginationField$1 = ({ context, name, schema }) => {
5879
6126
  if (getPaginationKeywordsRegExp(context.config.parser.pagination).test(name)) return true;
5880
6127
  if ("$ref" in schema) {
5881
- const ref = context.resolveRef(schema.$ref);
5882
- if ("content" in ref || "in" in ref) {
6128
+ const ref$1 = context.resolveRef(schema.$ref);
6129
+ if ("content" in ref$1 || "in" in ref$1) {
5883
6130
  let refSchema;
5884
- if ("in" in ref) refSchema = ref.schema;
6131
+ if ("in" in ref$1) refSchema = ref$1.schema;
5885
6132
  if (!refSchema) {
5886
- const contents = mediaTypeObjects$1({ content: ref.content });
6133
+ const contents = mediaTypeObjects$1({ content: ref$1.content });
5887
6134
  const content = contents.find((content$1) => content$1.type === "json") || contents[0];
5888
6135
  if (content?.schema) refSchema = content.schema;
5889
6136
  }
@@ -5897,7 +6144,7 @@ const paginationField$1 = ({ context, name, schema }) => {
5897
6144
  return paginationField$1({
5898
6145
  context,
5899
6146
  name,
5900
- schema: ref
6147
+ schema: ref$1
5901
6148
  });
5902
6149
  }
5903
6150
  for (const name$1 in schema.properties) if (getPaginationKeywordsRegExp(context.config.parser.pagination).test(name$1)) {
@@ -6572,6 +6819,31 @@ const getSchemaTypes = ({ schema }) => {
6572
6819
  return [];
6573
6820
  };
6574
6821
  /**
6822
+ * Finds the type of a discriminator property by looking it up in the provided schemas.
6823
+ * Searches through properties and allOf chains to find the property definition.
6824
+ */
6825
+ const findDiscriminatorPropertyType = ({ context, propertyName, schemas }) => {
6826
+ for (const schema of schemas) {
6827
+ const resolved = schema.$ref ? context.resolveRef(schema.$ref) : schema;
6828
+ const property = resolved.properties?.[propertyName];
6829
+ if (property === true) continue;
6830
+ if (property) {
6831
+ const resolvedProperty = property.$ref ? context.resolveRef(property.$ref) : property;
6832
+ const propertyTypes = Array.isArray(resolvedProperty.type) ? resolvedProperty.type : resolvedProperty.type ? [resolvedProperty.type] : [];
6833
+ for (const propType of propertyTypes) if (propType === "boolean" || propType === "integer" || propType === "number") return propType;
6834
+ }
6835
+ if (resolved.allOf) {
6836
+ const foundType = findDiscriminatorPropertyType({
6837
+ context,
6838
+ propertyName,
6839
+ schemas: resolved.allOf
6840
+ });
6841
+ if (foundType !== "string") return foundType;
6842
+ }
6843
+ }
6844
+ return "string";
6845
+ };
6846
+ /**
6575
6847
  * Recursively finds discriminators in a schema, including nested allOf compositions.
6576
6848
  * This is needed when a schema extends another schema via allOf, and that parent
6577
6849
  * schema is itself an allOf composition with discriminators in inline schemas.
@@ -6629,6 +6901,7 @@ const parseSchemaMeta = ({ irSchema, schema }) => {
6629
6901
  if (schema.exclusiveMaximum !== void 0) irSchema.exclusiveMaximum = schema.exclusiveMaximum;
6630
6902
  if (schema.exclusiveMinimum !== void 0) irSchema.exclusiveMinimum = schema.exclusiveMinimum;
6631
6903
  if (schema.format) irSchema.format = schema.format;
6904
+ else if (schema.contentMediaType && isMediaTypeFileLike({ mediaType: schema.contentMediaType })) irSchema.format = "binary";
6632
6905
  if (schema.maximum !== void 0) irSchema.maximum = schema.maximum;
6633
6906
  if (schema.maxItems !== void 0) irSchema.maxItems = schema.maxItems;
6634
6907
  if (schema.maxLength !== void 0) irSchema.maxLength = schema.maxLength;
@@ -6755,7 +7028,6 @@ const parseAllOf = ({ context, schema, state }) => {
6755
7028
  const schemaTypes = getSchemaTypes({ schema });
6756
7029
  const compositionSchemas = schema.allOf;
6757
7030
  const discriminatorsToAdd = [];
6758
- const addedDiscriminators = /* @__PURE__ */ new Set();
6759
7031
  for (const compositionSchema of compositionSchemas) {
6760
7032
  const originalInAllOf = state.inAllOf;
6761
7033
  if (!("$ref" in compositionSchema)) state.inAllOf = true;
@@ -6770,26 +7042,28 @@ const parseAllOf = ({ context, schema, state }) => {
6770
7042
  else irCompositionSchema.required = schema.required;
6771
7043
  schemaItems.push(irCompositionSchema);
6772
7044
  if (compositionSchema.$ref) {
6773
- const ref = context.resolveRef(compositionSchema.$ref);
7045
+ const ref$1 = context.resolveRef(compositionSchema.$ref);
6774
7046
  if (state.$ref) {
6775
7047
  const discriminators = findDiscriminatorsInSchema({
6776
7048
  context,
6777
- schema: ref
7049
+ schema: ref$1
6778
7050
  });
6779
7051
  for (const { discriminator, oneOf } of discriminators) {
6780
- if (addedDiscriminators.has(discriminator.propertyName)) continue;
6781
7052
  const values = discriminatorValues(state.$ref, discriminator.mapping, oneOf ? () => oneOf.some((o) => "$ref" in o && o.$ref === state.$ref) : void 0);
6782
- if (values.length > 0) {
6783
- const isRequired = discriminators.some((d) => d.discriminator.propertyName === discriminator.propertyName && (ref.required?.includes(d.discriminator.propertyName) || ref.allOf && ref.allOf.some((item) => {
6784
- return (item.$ref ? context.resolveRef(item.$ref) : item).required?.includes(d.discriminator.propertyName);
6785
- })));
6786
- discriminatorsToAdd.push({
6787
- discriminator,
6788
- isRequired,
6789
- values
6790
- });
6791
- addedDiscriminators.add(discriminator.propertyName);
6792
- }
7053
+ if (values.length === 0) continue;
7054
+ const isExplicitMapping = discriminator.mapping !== void 0 && Object.values(discriminator.mapping).includes(state.$ref);
7055
+ const existingIndex = discriminatorsToAdd.findIndex((d) => d.discriminator.propertyName === discriminator.propertyName);
7056
+ if (existingIndex !== -1) if (isExplicitMapping && !discriminatorsToAdd[existingIndex].isExplicitMapping) discriminatorsToAdd.splice(existingIndex, 1);
7057
+ else continue;
7058
+ const isRequired = discriminators.some((d) => d.discriminator.propertyName === discriminator.propertyName && (ref$1.required?.includes(d.discriminator.propertyName) || ref$1.allOf && ref$1.allOf.some((item) => {
7059
+ return (item.$ref ? context.resolveRef(item.$ref) : item).required?.includes(d.discriminator.propertyName);
7060
+ })));
7061
+ discriminatorsToAdd.push({
7062
+ discriminator,
7063
+ isExplicitMapping,
7064
+ isRequired,
7065
+ values
7066
+ });
6793
7067
  }
6794
7068
  }
6795
7069
  }
@@ -6799,10 +7073,13 @@ const parseAllOf = ({ context, schema, state }) => {
6799
7073
  discriminator,
6800
7074
  schemaRef: state.$ref
6801
7075
  });
6802
- const valueSchemas = (allValues.length > 0 ? allValues : values).map((value) => ({
6803
- const: value,
6804
- type: "string"
6805
- }));
7076
+ const finalValues = allValues.length > 0 ? allValues : values;
7077
+ const propertyType = findDiscriminatorPropertyType({
7078
+ context,
7079
+ propertyName: discriminator.propertyName,
7080
+ schemas: compositionSchemas
7081
+ });
7082
+ const valueSchemas = finalValues.map((value) => convertDiscriminatorValue(value, propertyType));
6806
7083
  const discriminatorProperty = valueSchemas.length > 1 ? {
6807
7084
  items: valueSchemas,
6808
7085
  logicalOperator: "or"
@@ -6902,6 +7179,11 @@ const parseAnyOf = ({ context, schema, state }) => {
6902
7179
  const schemaItems = [];
6903
7180
  const schemaTypes = getSchemaTypes({ schema });
6904
7181
  const compositionSchemas = schema.anyOf;
7182
+ const discriminatorPropertyType = schema.discriminator ? findDiscriminatorPropertyType({
7183
+ context,
7184
+ propertyName: schema.discriminator.propertyName,
7185
+ schemas: compositionSchemas
7186
+ }) : void 0;
6905
7187
  for (const compositionSchema of compositionSchemas) {
6906
7188
  let irCompositionSchema = schemaToIrSchema({
6907
7189
  context,
@@ -6909,10 +7191,7 @@ const parseAnyOf = ({ context, schema, state }) => {
6909
7191
  state
6910
7192
  });
6911
7193
  if (schema.discriminator && irCompositionSchema.$ref != null) {
6912
- const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => ({
6913
- const: value,
6914
- type: "string"
6915
- }));
7194
+ const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => convertDiscriminatorValue(value, discriminatorPropertyType));
6916
7195
  irCompositionSchema = {
6917
7196
  items: [{
6918
7197
  properties: { [schema.discriminator.propertyName]: valueSchemas.length > 1 ? {
@@ -6989,6 +7268,11 @@ const parseOneOf = ({ context, schema, state }) => {
6989
7268
  let schemaItems = [];
6990
7269
  const schemaTypes = getSchemaTypes({ schema });
6991
7270
  const compositionSchemas = schema.oneOf;
7271
+ const discriminatorPropertyType = schema.discriminator ? findDiscriminatorPropertyType({
7272
+ context,
7273
+ propertyName: schema.discriminator.propertyName,
7274
+ schemas: compositionSchemas
7275
+ }) : void 0;
6992
7276
  for (const compositionSchema of compositionSchemas) {
6993
7277
  let irCompositionSchema = schemaToIrSchema({
6994
7278
  context,
@@ -6996,10 +7280,7 @@ const parseOneOf = ({ context, schema, state }) => {
6996
7280
  state
6997
7281
  });
6998
7282
  if (schema.discriminator && irCompositionSchema.$ref != null) {
6999
- const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => ({
7000
- const: value,
7001
- type: "string"
7002
- }));
7283
+ const valueSchemas = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping).map((value) => convertDiscriminatorValue(value, discriminatorPropertyType));
7003
7284
  irCompositionSchema = {
7004
7285
  items: [{
7005
7286
  properties: { [schema.discriminator.propertyName]: valueSchemas.length > 1 ? {
@@ -7227,6 +7508,14 @@ const schemaToIrSchema = ({ context, schema, state }) => {
7227
7508
  schema,
7228
7509
  state
7229
7510
  });
7511
+ if (schema.contentMediaType && isMediaTypeFileLike({ mediaType: schema.contentMediaType })) return parseType({
7512
+ context,
7513
+ schema: {
7514
+ ...schema,
7515
+ type: "string"
7516
+ },
7517
+ state
7518
+ });
7230
7519
  return parseUnknown({
7231
7520
  context,
7232
7521
  schema
@@ -7251,12 +7540,12 @@ const isPaginationType = (schemaTypes) => schemaTypes.includes("boolean") || sch
7251
7540
  const paginationField = ({ context, name, schema }) => {
7252
7541
  if (getPaginationKeywordsRegExp(context.config.parser.pagination).test(name)) return true;
7253
7542
  if (schema.$ref) {
7254
- const ref = context.resolveRef(schema.$ref);
7255
- if ("content" in ref || "in" in ref) {
7543
+ const ref$1 = context.resolveRef(schema.$ref);
7544
+ if ("content" in ref$1 || "in" in ref$1) {
7256
7545
  let refSchema;
7257
- if ("in" in ref) refSchema = ref.schema;
7546
+ if ("in" in ref$1) refSchema = ref$1.schema;
7258
7547
  if (!refSchema) {
7259
- const contents = mediaTypeObjects({ content: ref.content });
7548
+ const contents = mediaTypeObjects({ content: ref$1.content });
7260
7549
  const content = contents.find((content$1) => content$1.type === "json") || contents[0];
7261
7550
  if (content?.schema) refSchema = content.schema;
7262
7551
  }
@@ -7270,7 +7559,7 @@ const paginationField = ({ context, name, schema }) => {
7270
7559
  return paginationField({
7271
7560
  context,
7272
7561
  name,
7273
- schema: ref
7562
+ schema: ref$1
7274
7563
  });
7275
7564
  }
7276
7565
  for (const name$1 in schema.properties) if (getPaginationKeywordsRegExp(context.config.parser.pagination).test(name$1)) {
@@ -8080,19 +8369,43 @@ const OperationPath = {
8080
8369
 
8081
8370
  //#endregion
8082
8371
  //#region src/openApi/shared/utils/patch.ts
8083
- function patchOpenApiSpec({ patchOptions, spec: _spec }) {
8372
+ async function patchOpenApiSpec({ patchOptions, spec: _spec }) {
8084
8373
  if (!patchOptions) return;
8085
8374
  const spec = _spec;
8375
+ if (typeof patchOptions === "function") {
8376
+ await patchOptions(spec);
8377
+ return;
8378
+ }
8379
+ if (patchOptions.input) await patchOptions.input(spec);
8086
8380
  if ("swagger" in spec) {
8087
8381
  if (patchOptions.version && spec.swagger) spec.swagger = typeof patchOptions.version === "string" ? patchOptions.version : patchOptions.version(spec.swagger);
8088
8382
  if (patchOptions.meta && spec.info) patchOptions.meta(spec.info);
8089
- if (patchOptions.schemas && spec.definitions) for (const key in patchOptions.schemas) {
8383
+ if (patchOptions.schemas && spec.definitions) if (typeof patchOptions.schemas === "function") {
8384
+ for (const [key, schema] of Object.entries(spec.definitions)) if (schema && typeof schema === "object") await patchOptions.schemas(key, schema);
8385
+ } else for (const key in patchOptions.schemas) {
8090
8386
  const schema = spec.definitions[key];
8091
8387
  if (!schema || typeof schema !== "object") continue;
8092
8388
  const patchFn = patchOptions.schemas[key];
8093
- patchFn(schema);
8389
+ await patchFn(schema);
8390
+ }
8391
+ if (patchOptions.operations && spec.paths) if (typeof patchOptions.operations === "function") for (const [path$1, pathItem] of Object.entries(spec.paths)) {
8392
+ if (!pathItem || typeof pathItem !== "object") continue;
8393
+ for (const method of [
8394
+ "get",
8395
+ "put",
8396
+ "post",
8397
+ "delete",
8398
+ "options",
8399
+ "head",
8400
+ "patch",
8401
+ "trace"
8402
+ ]) {
8403
+ const operation = pathItem[method];
8404
+ if (!operation || typeof operation !== "object") continue;
8405
+ await patchOptions.operations(method, path$1, operation);
8406
+ }
8094
8407
  }
8095
- if (patchOptions.operations && spec.paths) for (const key in patchOptions.operations) {
8408
+ else for (const key in patchOptions.operations) {
8096
8409
  const [method, path$1] = key.split(" ");
8097
8410
  if (!method || !path$1) continue;
8098
8411
  const pathItem = spec.paths[path$1];
@@ -8100,18 +8413,20 @@ function patchOpenApiSpec({ patchOptions, spec: _spec }) {
8100
8413
  const operation = pathItem[method.toLocaleLowerCase()] || pathItem[method.toLocaleUpperCase()];
8101
8414
  if (!operation || typeof operation !== "object") continue;
8102
8415
  const patchFn = patchOptions.operations[key];
8103
- patchFn(operation);
8416
+ await patchFn(operation);
8104
8417
  }
8105
8418
  return;
8106
8419
  }
8107
8420
  if (patchOptions.version && spec.openapi) spec.openapi = typeof patchOptions.version === "string" ? patchOptions.version : patchOptions.version(spec.openapi);
8108
8421
  if (patchOptions.meta && spec.info) patchOptions.meta(spec.info);
8109
8422
  if (spec.components) {
8110
- if (patchOptions.schemas && spec.components.schemas) for (const key in patchOptions.schemas) {
8423
+ if (patchOptions.schemas && spec.components.schemas) if (typeof patchOptions.schemas === "function") {
8424
+ for (const [key, schema] of Object.entries(spec.components.schemas)) if (schema && typeof schema === "object") await patchOptions.schemas(key, schema);
8425
+ } else for (const key in patchOptions.schemas) {
8111
8426
  const schema = spec.components.schemas[key];
8112
8427
  if (!schema || typeof schema !== "object") continue;
8113
8428
  const patchFn = patchOptions.schemas[key];
8114
- patchFn(schema);
8429
+ await patchFn(schema);
8115
8430
  }
8116
8431
  if (patchOptions.parameters && spec.components.parameters) for (const key in patchOptions.parameters) {
8117
8432
  const schema = spec.components.parameters[key];
@@ -8132,7 +8447,24 @@ function patchOpenApiSpec({ patchOptions, spec: _spec }) {
8132
8447
  patchFn(schema);
8133
8448
  }
8134
8449
  }
8135
- if (patchOptions.operations && spec.paths) for (const key in patchOptions.operations) {
8450
+ if (patchOptions.operations && spec.paths) if (typeof patchOptions.operations === "function") for (const [path$1, pathItem] of Object.entries(spec.paths)) {
8451
+ if (!pathItem || typeof pathItem !== "object") continue;
8452
+ for (const method of [
8453
+ "get",
8454
+ "put",
8455
+ "post",
8456
+ "delete",
8457
+ "options",
8458
+ "head",
8459
+ "patch",
8460
+ "trace"
8461
+ ]) {
8462
+ const operation = pathItem[method];
8463
+ if (!operation || typeof operation !== "object") continue;
8464
+ await patchOptions.operations(method, path$1, operation);
8465
+ }
8466
+ }
8467
+ else for (const key in patchOptions.operations) {
8136
8468
  const [method, path$1] = key.split(" ");
8137
8469
  if (!method || !path$1) continue;
8138
8470
  const pathItem = spec.paths[path$1];
@@ -8140,47 +8472,10 @@ function patchOpenApiSpec({ patchOptions, spec: _spec }) {
8140
8472
  const operation = pathItem[method.toLocaleLowerCase()] || pathItem[method.toLocaleUpperCase()];
8141
8473
  if (!operation || typeof operation !== "object") continue;
8142
8474
  const patchFn = patchOptions.operations[key];
8143
- patchFn(operation);
8475
+ await patchFn(operation);
8144
8476
  }
8145
8477
  }
8146
8478
 
8147
- //#endregion
8148
- //#region src/plugins/schema-processor.ts
8149
- function createSchemaProcessor() {
8150
- const emitted = /* @__PURE__ */ new Set();
8151
- let contextTags;
8152
- let contextAnchor;
8153
- return {
8154
- get context() {
8155
- return {
8156
- anchor: contextAnchor,
8157
- tags: contextTags
8158
- };
8159
- },
8160
- hasEmitted(path$1) {
8161
- return emitted.has(pathToJsonPointer(path$1));
8162
- },
8163
- markEmitted(path$1) {
8164
- const pointer = pathToJsonPointer(path$1);
8165
- if (emitted.has(pointer)) return false;
8166
- emitted.add(pointer);
8167
- return true;
8168
- },
8169
- withContext(ctx, fn) {
8170
- const prevTags = contextTags;
8171
- const prevAnchor = contextAnchor;
8172
- contextTags = ctx.tags;
8173
- contextAnchor = ctx.anchor;
8174
- try {
8175
- return fn();
8176
- } finally {
8177
- contextTags = prevTags;
8178
- contextAnchor = prevAnchor;
8179
- }
8180
- }
8181
- };
8182
- }
8183
-
8184
8479
  //#endregion
8185
8480
  //#region src/plugins/shared/utils/config.ts
8186
8481
  const definePluginConfig = (defaultConfig) => (userConfig) => ({
@@ -8217,6 +8512,19 @@ const utils = {
8217
8512
  toCase
8218
8513
  };
8219
8514
 
8515
+ //#endregion
8516
+ //#region src/utils/header.ts
8517
+ /**
8518
+ * Converts an {@link OutputHeader} value to a string prefix for file content.
8519
+ */
8520
+ function outputHeaderToPrefix(header, project) {
8521
+ let lines = typeof header === "function" ? header({ project }) : header;
8522
+ if (lines === null || lines === void 0) return "";
8523
+ lines = typeof lines === "string" ? lines.split(/\r?\n/) : lines.flatMap((line) => line.split(/\r?\n/));
8524
+ const content = lines.join("\n");
8525
+ return content ? `${content}\n\n` : "";
8526
+ }
8527
+
8220
8528
  //#endregion
8221
8529
  //#region src/utils/path.ts
8222
8530
  /**
@@ -8322,5 +8630,5 @@ function pathToName(path$1, options) {
8322
8630
  }
8323
8631
 
8324
8632
  //#endregion
8325
- export { ConfigError, ConfigValidationError, Context, HeyApiError, IntentContext, JobError, MinHeap, OperationPath, OperationStrategy, PluginInstance, addItemsToSchema, applyNaming, buildGraph, checkNodeVersion, compileInputPath, createOperationKey, createSchemaProcessor, debugTools, deduplicateSchema, defaultPaginationKeywords, definePluginConfig, dependencyFactory, encodeJsonPointerSegment, ensureDirSync, escapeComment, findPackageJson, findTsConfigPath, getInput, getLogs, getParser, getSpec, hasOperationDataRequired, hasParameterGroupObjectRequired, hasParametersObjectRequired, heyApiRegistryBaseUrl, inputToApiRegistry, isTopLevelComponent, jsonPointerToPath, loadPackageJson, loadTsConfig, logCrashReport, logInputPaths, mappers, normalizeJsonPointer, openGitHubIssueWithCrashReport, operationPagination, operationResponsesMap, parameterWithPagination, parseOpenApiSpec, parseUrl, parseV2_0_X, parseV3_0_X, parseV3_1_X, patchOpenApiSpec, pathToJsonPointer, pathToName, postprocessOutput, printCliIntro, printCrashReport, refToName, resolveNaming, resolveRef, resolveSource, satisfies, shouldReportCrash, statusCodeToGroup, toCase, utils, valueToObject };
8633
+ export { ConfigError, ConfigValidationError, Context, HeyApiError, IntentContext, JobError, MinHeap, OperationPath, OperationStrategy, PluginInstance, addItemsToSchema, applyNaming, buildGraph, checkNodeVersion, childContext, compileInputPath, createOperationKey, createSchemaProcessor, createSchemaWalker, debugTools, deduplicateSchema, defaultPaginationKeywords, definePluginConfig, dependencyFactory, encodeJsonPointerSegment, ensureDirSync, escapeComment, findPackageJson, findTsConfigPath, getInput, getLogs, getParser, getSpec, hasOperationDataRequired, hasParameterGroupObjectRequired, hasParametersObjectRequired, heyApiRegistryBaseUrl, inputToApiRegistry, isTopLevelComponent, jsonPointerToPath, loadPackageJson, loadTsConfig, logCrashReport, logInputPaths, mappers, normalizeJsonPointer, openGitHubIssueWithCrashReport, operationPagination, operationResponsesMap, outputHeaderToPrefix, parameterWithPagination, parseOpenApiSpec, parseUrl, parseV2_0_X, parseV3_0_X, parseV3_1_X, patchOpenApiSpec, pathToJsonPointer, pathToName, postprocessOutput, printCliIntro, printCrashReport, refToName, resolveNaming, resolveRef, resolveSource, satisfies, shouldReportCrash, statusCodeToGroup, toCase, utils, valueToObject };
8326
8634
  //# sourceMappingURL=index.mjs.map