zenko 0.1.9 → 0.1.10-beta.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/cli.mjs CHANGED
@@ -1,12 +1,10 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env bun
2
2
 
3
3
  // src/cli.ts
4
- import * as fs from "fs";
5
- import * as path from "path";
6
- import { pathToFileURL } from "url";
7
- import { load } from "js-yaml";
4
+ import * as path2 from "path";
5
+ import { mkdir } from "fs/promises";
8
6
 
9
- // src/utils/topological-sort.ts
7
+ // ../zenko-core/src/utils/topological-sort.ts
10
8
  function topologicalSort(schemas) {
11
9
  const visited = /* @__PURE__ */ new Set();
12
10
  const visiting = /* @__PURE__ */ new Set();
@@ -55,7 +53,7 @@ function extractRefName(ref) {
55
53
  return ref.split("/").pop() || "Unknown";
56
54
  }
57
55
 
58
- // src/utils/property-name.ts
56
+ // ../zenko-core/src/utils/property-name.ts
59
57
  function isValidJSIdentifier(name) {
60
58
  if (!name) return false;
61
59
  const firstChar = name.at(0);
@@ -135,7 +133,7 @@ function formatPropertyName(name) {
135
133
  return isValidJSIdentifier(name) ? name : `"${name}"`;
136
134
  }
137
135
 
138
- // src/utils/string-utils.ts
136
+ // ../zenko-core/src/utils/string-utils.ts
139
137
  function toCamelCase(str) {
140
138
  return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
141
139
  }
@@ -143,7 +141,7 @@ function capitalize(str) {
143
141
  return str.charAt(0).toUpperCase() + str.slice(1);
144
142
  }
145
143
 
146
- // src/utils/http-status.ts
144
+ // ../zenko-core/src/utils/http-status.ts
147
145
  var statusNameMap = {
148
146
  "400": "badRequest",
149
147
  "401": "unauthorized",
@@ -209,7 +207,7 @@ function isErrorStatus(status) {
209
207
  return code >= 400;
210
208
  }
211
209
 
212
- // src/utils/tree-shaking.ts
210
+ // ../zenko-core/src/utils/tree-shaking.ts
213
211
  function analyzeZenkoUsage(operations) {
214
212
  const usage = {
215
213
  usesHeaderFn: false,
@@ -249,7 +247,7 @@ function hasAnyErrors(errors) {
249
247
  return Boolean(errors && Object.keys(errors).length > 0);
250
248
  }
251
249
 
252
- // src/utils/collect-inline-types.ts
250
+ // ../zenko-core/src/utils/collect-inline-types.ts
253
251
  function collectInlineRequestTypes(operations, spec) {
254
252
  const requestTypesToGenerate = /* @__PURE__ */ new Map();
255
253
  const operationLookup = /* @__PURE__ */ new Map();
@@ -326,8 +324,186 @@ function collectInlineResponseTypes(operations, spec) {
326
324
  }
327
325
  return responseTypesToGenerate;
328
326
  }
327
+ function collectInlineErrorTypes(operations, spec) {
328
+ const errorTypesToGenerate = /* @__PURE__ */ new Map();
329
+ const operationLookup = /* @__PURE__ */ new Map();
330
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
331
+ for (const [, operation] of Object.entries(pathItem)) {
332
+ const op = operation;
333
+ if (op.operationId) {
334
+ operationLookup.set(op.operationId, op);
335
+ }
336
+ }
337
+ }
338
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
339
+ for (const [, operation] of Object.entries(pathItem)) {
340
+ const op = operation;
341
+ if (op.operationId) {
342
+ operationLookup.set(op.operationId, op);
343
+ }
344
+ }
345
+ }
346
+ for (const op of operations) {
347
+ const operation = operationLookup.get(op.operationId);
348
+ if (!operation) continue;
349
+ const responses = operation.responses || {};
350
+ for (const [statusCode, response] of Object.entries(responses)) {
351
+ if (isErrorStatus(statusCode) && response.content) {
352
+ const content = response.content;
353
+ const jsonContent = content["application/json"];
354
+ if (jsonContent && jsonContent.schema) {
355
+ const schema = jsonContent.schema;
356
+ const identifier = mapStatusToIdentifier(statusCode);
357
+ const typeName = `${capitalize(toCamelCase(op.operationId))}${capitalize(identifier)}`;
358
+ if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
359
+ errorTypesToGenerate.set(typeName, schema);
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+ return errorTypesToGenerate;
366
+ }
367
+
368
+ // ../zenko-core/src/utils/collect-referenced-schemas.ts
369
+ function findContentType(content) {
370
+ const contentTypes = Object.keys(content);
371
+ if (contentTypes.includes("application/json")) {
372
+ return "application/json";
373
+ }
374
+ const CONTENT_TYPE_MAP2 = {
375
+ "application/json": "unknown",
376
+ "text/csv": "string",
377
+ "text/plain": "string",
378
+ "application/octet-stream": "unknown",
379
+ "application/pdf": "unknown"
380
+ };
381
+ for (const contentType of contentTypes) {
382
+ if (contentType in CONTENT_TYPE_MAP2) {
383
+ return contentType;
384
+ }
385
+ }
386
+ return contentTypes[0] || "";
387
+ }
388
+ function resolveParameter(parameter, spec) {
389
+ if (!parameter) return void 0;
390
+ if (parameter.$ref) {
391
+ const refName = extractRefName(parameter.$ref);
392
+ const resolved = spec.components?.parameters?.[refName];
393
+ if (!resolved) return void 0;
394
+ const { $ref, ...overrides } = parameter;
395
+ return {
396
+ ...resolved,
397
+ ...overrides
398
+ };
399
+ }
400
+ return parameter;
401
+ }
402
+ function collectReferencedSchemas(operations, spec) {
403
+ const referenced = /* @__PURE__ */ new Set();
404
+ const operationLookup = /* @__PURE__ */ new Map();
405
+ for (const [, pathItem] of Object.entries(spec.paths || {})) {
406
+ for (const [, operation] of Object.entries(pathItem)) {
407
+ const op = operation;
408
+ if (op.operationId) {
409
+ operationLookup.set(op.operationId, op);
410
+ }
411
+ }
412
+ }
413
+ for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
414
+ for (const [, operation] of Object.entries(pathItem)) {
415
+ const op = operation;
416
+ if (op.operationId) {
417
+ operationLookup.set(op.operationId, op);
418
+ }
419
+ }
420
+ }
421
+ for (const op of operations) {
422
+ const rawOperation = operationLookup.get(op.operationId);
423
+ if (!rawOperation) continue;
424
+ const requestBody = rawOperation.requestBody?.content?.["application/json"]?.schema;
425
+ if (requestBody?.$ref) {
426
+ const refName = extractRefName(requestBody.$ref);
427
+ referenced.add(refName);
428
+ } else if (requestBody) {
429
+ const deps = extractDependencies(requestBody);
430
+ for (const dep of deps) {
431
+ if (spec.components?.schemas?.[dep]) {
432
+ referenced.add(dep);
433
+ }
434
+ }
435
+ }
436
+ const responses = rawOperation.responses || {};
437
+ for (const [, response] of Object.entries(responses)) {
438
+ const content = response?.content;
439
+ if (!content) continue;
440
+ const contentType = findContentType(content);
441
+ const responseSchema = content[contentType]?.schema;
442
+ if (responseSchema?.$ref) {
443
+ const refName = extractRefName(responseSchema.$ref);
444
+ referenced.add(refName);
445
+ } else if (responseSchema) {
446
+ const deps = extractDependencies(responseSchema);
447
+ for (const dep of deps) {
448
+ if (spec.components?.schemas?.[dep]) {
449
+ referenced.add(dep);
450
+ }
451
+ }
452
+ }
453
+ }
454
+ for (const param of op.queryParams) {
455
+ if (param.schema?.$ref) {
456
+ const refName = extractRefName(param.schema.$ref);
457
+ referenced.add(refName);
458
+ }
459
+ if (param.schema?.items?.$ref) {
460
+ const refName = extractRefName(param.schema.items.$ref);
461
+ referenced.add(refName);
462
+ }
463
+ }
464
+ for (const header of op.requestHeaders || []) {
465
+ if (header.schema?.$ref) {
466
+ const refName = extractRefName(header.schema.$ref);
467
+ referenced.add(refName);
468
+ }
469
+ if (header.schema?.items?.$ref) {
470
+ const refName = extractRefName(header.schema.items.$ref);
471
+ referenced.add(refName);
472
+ }
473
+ }
474
+ const parameters = rawOperation.parameters || [];
475
+ for (const param of parameters) {
476
+ const resolvedParam = resolveParameter(param, spec);
477
+ if (resolvedParam?.schema?.$ref) {
478
+ const refName = extractRefName(resolvedParam.schema.$ref);
479
+ referenced.add(refName);
480
+ }
481
+ if (resolvedParam?.schema?.items?.$ref) {
482
+ const refName = extractRefName(resolvedParam.schema.items.$ref);
483
+ referenced.add(refName);
484
+ }
485
+ }
486
+ }
487
+ const visited = /* @__PURE__ */ new Set();
488
+ const toVisit = Array.from(referenced);
489
+ while (toVisit.length > 0) {
490
+ const schemaName = toVisit.pop();
491
+ if (visited.has(schemaName)) continue;
492
+ visited.add(schemaName);
493
+ const schema = spec.components?.schemas?.[schemaName];
494
+ if (!schema) continue;
495
+ const dependencies = extractDependencies(schema);
496
+ for (const dep of dependencies) {
497
+ if (spec.components?.schemas?.[dep] && !visited.has(dep)) {
498
+ referenced.add(dep);
499
+ toVisit.push(dep);
500
+ }
501
+ }
502
+ }
503
+ return referenced;
504
+ }
329
505
 
330
- // src/utils/generate-helper-file.ts
506
+ // ../zenko-core/src/utils/generate-helper-file.ts
331
507
  function generateHelperFile() {
332
508
  const output = [];
333
509
  output.push("// Generated helper types for Zenko");
@@ -369,11 +545,11 @@ function generateHelperFile() {
369
545
  return output.join("\n");
370
546
  }
371
547
 
372
- // src/zenko.ts
548
+ // ../zenko-core/src/zenko.ts
373
549
  function generateWithMetadata(spec, options = {}) {
374
550
  const output = [];
375
551
  const generatedTypes = /* @__PURE__ */ new Set();
376
- const { strictDates = false, strictNumeric = false } = options;
552
+ const { strictDates = false, strictNumeric = false, operationIds } = options;
377
553
  const typesConfig = normalizeTypesConfig(options.types);
378
554
  const schemaOptions = {
379
555
  strictDates,
@@ -387,13 +563,26 @@ function generateWithMetadata(spec, options = {}) {
387
563
  nameMap.set(name, toCamelCase(name));
388
564
  }
389
565
  }
390
- const operations = parseOperations(spec, nameMap);
566
+ let operations = parseOperations(spec, nameMap);
567
+ if (operationIds && operationIds.length > 0) {
568
+ const selectedIds = new Set(operationIds);
569
+ operations = operations.filter((op) => selectedIds.has(op.operationId));
570
+ }
391
571
  appendHelperTypesImport(output, typesConfig, operations);
392
572
  output.push("");
393
573
  if (spec.components?.schemas) {
394
574
  output.push("// Generated Zod Schemas");
395
575
  output.push("");
396
- const sortedSchemas = topologicalSort(spec.components.schemas);
576
+ let schemasToGenerate;
577
+ if (operationIds && operationIds.length > 0) {
578
+ const referencedSchemas = collectReferencedSchemas(operations, spec);
579
+ schemasToGenerate = Array.from(referencedSchemas);
580
+ } else {
581
+ schemasToGenerate = Object.keys(spec.components.schemas);
582
+ }
583
+ const sortedSchemas = topologicalSort(spec.components.schemas).filter(
584
+ (name) => schemasToGenerate.includes(name)
585
+ );
397
586
  for (const name of sortedSchemas) {
398
587
  const schema = spec.components.schemas[name];
399
588
  const sanitizedName = nameMap.get(name);
@@ -582,6 +771,9 @@ function generateWithMetadata(spec, options = {}) {
582
771
  }
583
772
  return result;
584
773
  }
774
+ function generateFromDocument(spec, options = {}) {
775
+ return generateWithMetadata(spec, options);
776
+ }
585
777
  function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
586
778
  const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
587
779
  if (requestTypesToGenerate.size > 0) {
@@ -604,7 +796,8 @@ function generateRequestTypes(output, operations, spec, nameMap, schemaOptions)
604
796
  }
605
797
  function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
606
798
  const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
607
- if (responseTypesToGenerate.size > 0) {
799
+ const errorTypesToGenerate = collectInlineErrorTypes(operations, spec);
800
+ if (responseTypesToGenerate.size > 0 || errorTypesToGenerate.size > 0) {
608
801
  output.push("// Generated Response Types");
609
802
  output.push("");
610
803
  for (const [typeName, schema] of responseTypesToGenerate) {
@@ -620,6 +813,19 @@ function generateResponseTypes(output, operations, spec, nameMap, schemaOptions)
620
813
  output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
621
814
  output.push("");
622
815
  }
816
+ for (const [typeName, schema] of errorTypesToGenerate) {
817
+ const generatedSchema = generateZodSchema(
818
+ typeName,
819
+ schema,
820
+ /* @__PURE__ */ new Set(),
821
+ schemaOptions,
822
+ nameMap
823
+ );
824
+ output.push(generatedSchema);
825
+ output.push("");
826
+ output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
827
+ output.push("");
828
+ }
623
829
  }
624
830
  }
625
831
  function appendOperationField(buffer, key, value) {
@@ -661,7 +867,7 @@ var CONTENT_TYPE_MAP = {
661
867
  "application/octet-stream": "unknown",
662
868
  "application/pdf": "unknown"
663
869
  };
664
- function findContentType(content) {
870
+ function findContentType2(content) {
665
871
  const contentTypes = Object.keys(content);
666
872
  if (contentTypes.includes("application/json")) {
667
873
  return "application/json";
@@ -685,12 +891,12 @@ function inferResponseType(contentType, statusCode) {
685
891
  function parseOperations(spec, nameMap) {
686
892
  const operations = [];
687
893
  if (spec.paths) {
688
- for (const [path2, pathItem] of Object.entries(spec.paths)) {
894
+ for (const [path3, pathItem] of Object.entries(spec.paths)) {
689
895
  for (const [method, operation] of Object.entries(pathItem)) {
690
896
  const normalizedMethod = method.toLowerCase();
691
897
  if (!isRequestMethod(normalizedMethod)) continue;
692
898
  if (!operation.operationId) continue;
693
- const pathParams = extractPathParams(path2);
899
+ const pathParams = extractPathParams(path3);
694
900
  const requestType = getRequestType(operation);
695
901
  const { successResponse, errors } = getResponseTypes(
696
902
  operation,
@@ -702,7 +908,7 @@ function parseOperations(spec, nameMap) {
702
908
  const queryParams = getQueryParams(resolvedParameters);
703
909
  operations.push({
704
910
  operationId: operation.operationId,
705
- path: path2,
911
+ path: path3,
706
912
  method: normalizedMethod,
707
913
  pathParams,
708
914
  queryParams,
@@ -720,8 +926,8 @@ function parseOperations(spec, nameMap) {
720
926
  const normalizedMethod = method.toLowerCase();
721
927
  if (!isRequestMethod(normalizedMethod)) continue;
722
928
  if (!operation.operationId) continue;
723
- const path2 = webhookName;
724
- const pathParams = extractPathParams(path2);
929
+ const path3 = webhookName;
930
+ const pathParams = extractPathParams(path3);
725
931
  const requestType = getRequestType(operation);
726
932
  const { successResponse, errors } = getResponseTypes(
727
933
  operation,
@@ -736,7 +942,7 @@ function parseOperations(spec, nameMap) {
736
942
  const queryParams = getQueryParams(resolvedParameters);
737
943
  operations.push({
738
944
  operationId: operation.operationId,
739
- path: path2,
945
+ path: path3,
740
946
  method: normalizedMethod,
741
947
  pathParams,
742
948
  queryParams,
@@ -912,7 +1118,7 @@ function collectParameters(pathItem, operation, spec) {
912
1118
  const addParameters = (params) => {
913
1119
  if (!Array.isArray(params)) return;
914
1120
  for (const param of params) {
915
- const resolved = resolveParameter(param, spec);
1121
+ const resolved = resolveParameter2(param, spec);
916
1122
  if (!resolved) continue;
917
1123
  const key = `${resolved.in}:${resolved.name}`;
918
1124
  parametersMap.set(key, resolved);
@@ -922,7 +1128,7 @@ function collectParameters(pathItem, operation, spec) {
922
1128
  addParameters(operation.parameters);
923
1129
  return Array.from(parametersMap.values());
924
1130
  }
925
- function resolveParameter(parameter, spec) {
1131
+ function resolveParameter2(parameter, spec) {
926
1132
  if (!parameter) return void 0;
927
1133
  if (parameter.$ref) {
928
1134
  const refName = extractRefName(parameter.$ref);
@@ -936,9 +1142,9 @@ function resolveParameter(parameter, spec) {
936
1142
  }
937
1143
  return parameter;
938
1144
  }
939
- function extractPathParams(path2) {
1145
+ function extractPathParams(path3) {
940
1146
  const params = [];
941
- const matches = path2.match(/{([^}]+)}/g);
1147
+ const matches = path3.match(/{([^}]+)}/g);
942
1148
  if (matches) {
943
1149
  for (const match of matches) {
944
1150
  const paramName = match.slice(1, -1);
@@ -977,7 +1183,7 @@ function getResponseTypes(operation, operationId, nameMap) {
977
1183
  }
978
1184
  continue;
979
1185
  }
980
- const contentType = findContentType(content);
1186
+ const contentType = findContentType2(content);
981
1187
  const resolvedSchema = content[contentType]?.schema;
982
1188
  if (!resolvedSchema) {
983
1189
  const inferredType = inferResponseType(contentType, statusCode);
@@ -1349,6 +1555,74 @@ function applyNumericBounds(schema, builder) {
1349
1555
  return builder;
1350
1556
  }
1351
1557
 
1558
+ // src/loader.ts
1559
+ import * as path from "path";
1560
+ import { pathToFileURL } from "url";
1561
+ var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yaml", ".yml"]);
1562
+ var JSON_EXTENSIONS = /* @__PURE__ */ new Set([".json"]);
1563
+ async function readFileText(filePath) {
1564
+ const file = Bun.file(filePath);
1565
+ if (!await file.exists()) {
1566
+ throw new Error(`File not found: ${filePath}`);
1567
+ }
1568
+ return await file.text();
1569
+ }
1570
+ async function loadConfig(filePath) {
1571
+ const extension = path.extname(filePath).toLowerCase();
1572
+ if (JSON_EXTENSIONS.has(extension)) {
1573
+ const content = await readFileText(filePath);
1574
+ return JSON.parse(content);
1575
+ }
1576
+ if (YAML_EXTENSIONS.has(extension)) {
1577
+ const content = await readFileText(filePath);
1578
+ return Bun.YAML.parse(content);
1579
+ }
1580
+ const fileUrl = pathToFileURL(filePath).href;
1581
+ const module = await import(fileUrl);
1582
+ return module.default ?? module.config ?? module;
1583
+ }
1584
+ async function loadSpec(filePath) {
1585
+ const extension = path.extname(filePath).toLowerCase();
1586
+ const content = await readFileText(filePath);
1587
+ if (YAML_EXTENSIONS.has(extension)) {
1588
+ const parsed = Bun.YAML.parse(content);
1589
+ if (!parsed || typeof parsed !== "object") {
1590
+ throw new Error(`YAML spec did not resolve to an object: ${filePath}`);
1591
+ }
1592
+ if (Array.isArray(parsed)) {
1593
+ throw new Error(
1594
+ `YAML spec produced multiple documents; provide a single document in ${filePath}`
1595
+ );
1596
+ }
1597
+ return parsed;
1598
+ }
1599
+ if (JSON_EXTENSIONS.has(extension)) {
1600
+ return JSON.parse(content);
1601
+ }
1602
+ throw new Error(
1603
+ `Unsupported specification format for ${filePath}. Expected .yaml, .yml, or .json`
1604
+ );
1605
+ }
1606
+ function normalizeGenerationOptions(entry, baseDir, defaults) {
1607
+ const resolvedInput = path.isAbsolute(entry.input) ? entry.input : path.join(baseDir, entry.input);
1608
+ const resolvedOutput = path.isAbsolute(entry.output) ? entry.output : path.join(baseDir, entry.output);
1609
+ return {
1610
+ resolvedInput,
1611
+ resolvedOutput,
1612
+ strictDates: entry.strictDates ?? defaults.strictDates,
1613
+ strictNumeric: entry.strictNumeric ?? defaults.strictNumeric,
1614
+ types: mergeTypesConfig(defaults.types, entry.types),
1615
+ operationIds: entry.operationIds ?? defaults.operationIds
1616
+ };
1617
+ }
1618
+ function mergeTypesConfig(baseConfig, entryConfig) {
1619
+ if (!baseConfig && !entryConfig) return void 0;
1620
+ return {
1621
+ ...baseConfig,
1622
+ ...entryConfig
1623
+ };
1624
+ }
1625
+
1352
1626
  // src/cli.ts
1353
1627
  async function main() {
1354
1628
  const args = process.argv.slice(2);
@@ -1374,8 +1648,8 @@ async function main() {
1374
1648
  return;
1375
1649
  }
1376
1650
  await generateSingle({
1377
- inputFile,
1378
- outputFile,
1651
+ resolvedInput: path2.resolve(inputFile),
1652
+ resolvedOutput: path2.resolve(outputFile),
1379
1653
  strictDates: parsed.strictDates,
1380
1654
  strictNumeric: parsed.strictNumeric
1381
1655
  });
@@ -1443,38 +1717,22 @@ function printHelp() {
1443
1717
  }
1444
1718
  async function runFromConfig(parsed) {
1445
1719
  const configPath = parsed.configPath;
1446
- const resolvedConfigPath = path.resolve(configPath);
1447
- const config = await loadConfig(resolvedConfigPath);
1448
- validateConfig(config);
1449
- const baseDir = path.dirname(resolvedConfigPath);
1450
- const baseTypesConfig = config.types;
1720
+ const resolvedConfigPath = path2.resolve(configPath);
1721
+ const configDocument = await loadConfig(resolvedConfigPath);
1722
+ validateConfig(configDocument);
1723
+ const config = configDocument;
1724
+ const baseDir = path2.dirname(resolvedConfigPath);
1725
+ const defaults = {
1726
+ strictDates: parsed.strictDates,
1727
+ strictNumeric: parsed.strictNumeric,
1728
+ types: config.types,
1729
+ operationIds: void 0
1730
+ };
1451
1731
  for (const entry of config.schemas) {
1452
- const inputFile = resolvePath(entry.input, baseDir);
1453
- const outputFile = resolvePath(entry.output, baseDir);
1454
- const typesConfig = resolveTypesConfig(baseTypesConfig, entry.types);
1455
- await generateSingle({
1456
- inputFile,
1457
- outputFile,
1458
- strictDates: entry.strictDates ?? parsed.strictDates,
1459
- strictNumeric: entry.strictNumeric ?? parsed.strictNumeric,
1460
- typesConfig
1461
- });
1732
+ const options = normalizeGenerationOptions(entry, baseDir, defaults);
1733
+ await generateSingle(options);
1462
1734
  }
1463
1735
  }
1464
- async function loadConfig(filePath) {
1465
- const extension = path.extname(filePath).toLowerCase();
1466
- if (extension === ".json") {
1467
- const content = fs.readFileSync(filePath, "utf8");
1468
- return JSON.parse(content);
1469
- }
1470
- if (extension === ".yaml" || extension === ".yml") {
1471
- const content = fs.readFileSync(filePath, "utf8");
1472
- return load(content);
1473
- }
1474
- const fileUrl = pathToFileURL(filePath).href;
1475
- const module = await import(fileUrl);
1476
- return module.default ?? module.config ?? module;
1477
- }
1478
1736
  function validateConfig(config) {
1479
1737
  if (!config || typeof config !== "object") {
1480
1738
  throw new Error("Config file must export an object");
@@ -1491,60 +1749,44 @@ function validateConfig(config) {
1491
1749
  }
1492
1750
  }
1493
1751
  }
1494
- function resolvePath(filePath, baseDir) {
1495
- return path.isAbsolute(filePath) ? filePath : path.join(baseDir, filePath);
1496
- }
1497
- function resolveTypesConfig(baseConfig, entryConfig) {
1498
- if (!baseConfig && !entryConfig) return void 0;
1499
- return {
1500
- ...baseConfig,
1501
- ...entryConfig
1502
- };
1503
- }
1504
1752
  async function generateSingle(options) {
1505
- const { inputFile, outputFile, strictDates, strictNumeric, typesConfig } = options;
1506
- const resolvedInput = path.resolve(inputFile);
1507
- const resolvedOutput = path.resolve(outputFile);
1508
- const spec = readSpec(resolvedInput);
1509
- const result = generateWithMetadata(spec, {
1753
+ const {
1754
+ resolvedInput,
1755
+ resolvedOutput,
1756
+ strictDates = false,
1757
+ strictNumeric = false,
1758
+ types,
1759
+ operationIds
1760
+ } = options;
1761
+ const spec = await loadSpec(resolvedInput);
1762
+ const result = generateFromDocument(spec, {
1510
1763
  strictDates,
1511
1764
  strictNumeric,
1512
- types: typesConfig
1765
+ types,
1766
+ operationIds
1513
1767
  });
1514
- fs.mkdirSync(path.dirname(resolvedOutput), { recursive: true });
1515
- fs.writeFileSync(resolvedOutput, result.output);
1768
+ await mkdir(path2.dirname(resolvedOutput), { recursive: true });
1769
+ await Bun.write(resolvedOutput, result.output);
1516
1770
  console.log(`\u2705 Generated TypeScript types in ${resolvedOutput}`);
1517
1771
  console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths || {}).length} paths`);
1518
1772
  if (spec.webhooks) {
1519
1773
  console.log(`\u{1FA9D} Processed ${Object.keys(spec.webhooks).length} webhooks`);
1520
1774
  }
1521
1775
  if (result.helperFile) {
1522
- const helperPath = path.isAbsolute(result.helperFile.path) ? result.helperFile.path : path.resolve(path.dirname(resolvedOutput), result.helperFile.path);
1523
- const absoluteResolvedOutput = path.resolve(resolvedOutput);
1524
- const absoluteHelperPath = path.resolve(helperPath);
1776
+ const helperPath = path2.isAbsolute(result.helperFile.path) ? result.helperFile.path : path2.resolve(path2.dirname(resolvedOutput), result.helperFile.path);
1777
+ const absoluteResolvedOutput = path2.resolve(resolvedOutput);
1778
+ const absoluteHelperPath = path2.resolve(helperPath);
1525
1779
  if (absoluteResolvedOutput === absoluteHelperPath) {
1526
1780
  console.warn(
1527
1781
  `\u26A0\uFE0F Skipping helper file generation: would overwrite main output at ${absoluteResolvedOutput}`
1528
1782
  );
1529
1783
  return;
1530
1784
  }
1531
- fs.mkdirSync(path.dirname(helperPath), { recursive: true });
1532
- fs.writeFileSync(helperPath, result.helperFile.content, {
1533
- encoding: "utf8"
1534
- });
1785
+ await mkdir(path2.dirname(helperPath), { recursive: true });
1786
+ await Bun.write(helperPath, result.helperFile.content);
1535
1787
  console.log(`\u{1F4E6} Generated helper types in ${helperPath}`);
1536
1788
  }
1537
1789
  }
1538
- function readSpec(filePath) {
1539
- if (!fs.existsSync(filePath)) {
1540
- throw new Error(`Input file not found: ${filePath}`);
1541
- }
1542
- const content = fs.readFileSync(filePath, "utf8");
1543
- if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
1544
- return load(content);
1545
- }
1546
- return JSON.parse(content);
1547
- }
1548
1790
  main().catch((error) => {
1549
1791
  console.error("\u274C Error:", error);
1550
1792
  process.exit(1);