zenko 0.1.10-beta.3 → 0.1.10
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/README.md +21 -11
- package/dist/cli.cjs +94 -176
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.mjs +94 -176
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +13 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -24
- package/dist/index.d.ts +1 -24
- package/dist/index.mjs +12 -71
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -17,25 +17,30 @@ Unlike most OpenAPI generators, Zenko does not create a client. Instead you are
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
### One-time Usage
|
|
20
|
+
### One-time Usage
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
# Use directly with
|
|
23
|
+
# Use directly with npx (no installation required)
|
|
24
|
+
npx zenko input.yaml output.ts
|
|
25
|
+
|
|
26
|
+
# Or with bunx
|
|
24
27
|
bunx zenko input.yaml output.ts
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
### Install for Repeated Use
|
|
30
|
+
### Install for Repeated Use
|
|
28
31
|
|
|
29
32
|
```bash
|
|
30
33
|
# Install globally
|
|
34
|
+
npm install -g zenko
|
|
31
35
|
bun install -g zenko
|
|
32
36
|
|
|
33
37
|
# Or install locally
|
|
38
|
+
npm install zenko
|
|
34
39
|
bun add zenko
|
|
40
|
+
yarn add zenko
|
|
41
|
+
pnpm add zenko
|
|
35
42
|
```
|
|
36
43
|
|
|
37
|
-
> 💡 Need pure Node.js support? Install [`zenko-node`](../zenko-node/README.md) for an equivalent CLI and library powered by `js-yaml`.
|
|
38
|
-
|
|
39
44
|
## Usage
|
|
40
45
|
|
|
41
46
|
### Command Line
|
|
@@ -98,13 +103,18 @@ The config file controls generation for multiple specs and can also configure ty
|
|
|
98
103
|
### Programmatic Usage
|
|
99
104
|
|
|
100
105
|
```typescript
|
|
101
|
-
import {
|
|
106
|
+
import { generate, type OpenAPISpec } from "zenko"
|
|
107
|
+
import * as fs from "fs"
|
|
108
|
+
import { load } from "js-yaml"
|
|
109
|
+
|
|
110
|
+
// Load your OpenAPI spec
|
|
111
|
+
const spec = load(fs.readFileSync("api.yaml", "utf8")) as OpenAPISpec
|
|
102
112
|
|
|
103
|
-
|
|
104
|
-
const
|
|
113
|
+
// Generate TypeScript code
|
|
114
|
+
const output = generate(spec)
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
// Write to file
|
|
117
|
+
fs.writeFileSync("types.ts", output)
|
|
108
118
|
```
|
|
109
119
|
|
|
110
120
|
#### ES Modules
|
|
@@ -274,7 +284,7 @@ bun test
|
|
|
274
284
|
bun run build
|
|
275
285
|
|
|
276
286
|
# Test with example spec
|
|
277
|
-
zenko
|
|
287
|
+
zenko src/resources/petstore.yaml output.ts
|
|
278
288
|
|
|
279
289
|
# Format code
|
|
280
290
|
bun run format
|
package/dist/cli.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -24,10 +24,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
27
|
+
var fs = __toESM(require("fs"), 1);
|
|
28
|
+
var path = __toESM(require("path"), 1);
|
|
29
|
+
var import_url = require("url");
|
|
30
|
+
var import_js_yaml = require("js-yaml");
|
|
29
31
|
|
|
30
|
-
//
|
|
32
|
+
// src/utils/topological-sort.ts
|
|
31
33
|
function topologicalSort(schemas) {
|
|
32
34
|
const visited = /* @__PURE__ */ new Set();
|
|
33
35
|
const visiting = /* @__PURE__ */ new Set();
|
|
@@ -76,7 +78,7 @@ function extractRefName(ref) {
|
|
|
76
78
|
return ref.split("/").pop() || "Unknown";
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
//
|
|
81
|
+
// src/utils/property-name.ts
|
|
80
82
|
function isValidJSIdentifier(name) {
|
|
81
83
|
if (!name) return false;
|
|
82
84
|
const firstChar = name.at(0);
|
|
@@ -156,7 +158,7 @@ function formatPropertyName(name) {
|
|
|
156
158
|
return isValidJSIdentifier(name) ? name : `"${name}"`;
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
//
|
|
161
|
+
// src/utils/string-utils.ts
|
|
160
162
|
function toCamelCase(str) {
|
|
161
163
|
return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
|
|
162
164
|
}
|
|
@@ -164,7 +166,7 @@ function capitalize(str) {
|
|
|
164
166
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
//
|
|
169
|
+
// src/utils/http-status.ts
|
|
168
170
|
var statusNameMap = {
|
|
169
171
|
"400": "badRequest",
|
|
170
172
|
"401": "unauthorized",
|
|
@@ -230,7 +232,7 @@ function isErrorStatus(status) {
|
|
|
230
232
|
return code >= 400;
|
|
231
233
|
}
|
|
232
234
|
|
|
233
|
-
//
|
|
235
|
+
// src/utils/tree-shaking.ts
|
|
234
236
|
function analyzeZenkoUsage(operations) {
|
|
235
237
|
const usage = {
|
|
236
238
|
usesHeaderFn: false,
|
|
@@ -270,7 +272,7 @@ function hasAnyErrors(errors) {
|
|
|
270
272
|
return Boolean(errors && Object.keys(errors).length > 0);
|
|
271
273
|
}
|
|
272
274
|
|
|
273
|
-
//
|
|
275
|
+
// src/utils/collect-inline-types.ts
|
|
274
276
|
function collectInlineRequestTypes(operations, spec) {
|
|
275
277
|
const requestTypesToGenerate = /* @__PURE__ */ new Map();
|
|
276
278
|
const operationLookup = /* @__PURE__ */ new Map();
|
|
@@ -347,48 +349,8 @@ function collectInlineResponseTypes(operations, spec) {
|
|
|
347
349
|
}
|
|
348
350
|
return responseTypesToGenerate;
|
|
349
351
|
}
|
|
350
|
-
function collectInlineErrorTypes(operations, spec) {
|
|
351
|
-
const errorTypesToGenerate = /* @__PURE__ */ new Map();
|
|
352
|
-
const operationLookup = /* @__PURE__ */ new Map();
|
|
353
|
-
for (const [, pathItem] of Object.entries(spec.paths || {})) {
|
|
354
|
-
for (const [, operation] of Object.entries(pathItem)) {
|
|
355
|
-
const op = operation;
|
|
356
|
-
if (op.operationId) {
|
|
357
|
-
operationLookup.set(op.operationId, op);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
|
|
362
|
-
for (const [, operation] of Object.entries(pathItem)) {
|
|
363
|
-
const op = operation;
|
|
364
|
-
if (op.operationId) {
|
|
365
|
-
operationLookup.set(op.operationId, op);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
for (const op of operations) {
|
|
370
|
-
const operation = operationLookup.get(op.operationId);
|
|
371
|
-
if (!operation) continue;
|
|
372
|
-
const responses = operation.responses || {};
|
|
373
|
-
for (const [statusCode, response] of Object.entries(responses)) {
|
|
374
|
-
if (isErrorStatus(statusCode) && response.content) {
|
|
375
|
-
const content = response.content;
|
|
376
|
-
const jsonContent = content["application/json"];
|
|
377
|
-
if (jsonContent && jsonContent.schema) {
|
|
378
|
-
const schema = jsonContent.schema;
|
|
379
|
-
const identifier = mapStatusToIdentifier(statusCode);
|
|
380
|
-
const typeName = `${capitalize(toCamelCase(op.operationId))}${capitalize(identifier)}`;
|
|
381
|
-
if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
382
|
-
errorTypesToGenerate.set(typeName, schema);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return errorTypesToGenerate;
|
|
389
|
-
}
|
|
390
352
|
|
|
391
|
-
//
|
|
353
|
+
// src/utils/collect-referenced-schemas.ts
|
|
392
354
|
function findContentType(content) {
|
|
393
355
|
const contentTypes = Object.keys(content);
|
|
394
356
|
if (contentTypes.includes("application/json")) {
|
|
@@ -526,7 +488,7 @@ function collectReferencedSchemas(operations, spec) {
|
|
|
526
488
|
return referenced;
|
|
527
489
|
}
|
|
528
490
|
|
|
529
|
-
//
|
|
491
|
+
// src/utils/generate-helper-file.ts
|
|
530
492
|
function generateHelperFile() {
|
|
531
493
|
const output = [];
|
|
532
494
|
output.push("// Generated helper types for Zenko");
|
|
@@ -568,7 +530,7 @@ function generateHelperFile() {
|
|
|
568
530
|
return output.join("\n");
|
|
569
531
|
}
|
|
570
532
|
|
|
571
|
-
//
|
|
533
|
+
// src/zenko.ts
|
|
572
534
|
function generateWithMetadata(spec, options = {}) {
|
|
573
535
|
const output = [];
|
|
574
536
|
const generatedTypes = /* @__PURE__ */ new Set();
|
|
@@ -794,9 +756,6 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
794
756
|
}
|
|
795
757
|
return result;
|
|
796
758
|
}
|
|
797
|
-
function generateFromDocument(spec, options = {}) {
|
|
798
|
-
return generateWithMetadata(spec, options);
|
|
799
|
-
}
|
|
800
759
|
function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
801
760
|
const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
|
|
802
761
|
if (requestTypesToGenerate.size > 0) {
|
|
@@ -819,8 +778,7 @@ function generateRequestTypes(output, operations, spec, nameMap, schemaOptions)
|
|
|
819
778
|
}
|
|
820
779
|
function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
821
780
|
const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
|
|
822
|
-
|
|
823
|
-
if (responseTypesToGenerate.size > 0 || errorTypesToGenerate.size > 0) {
|
|
781
|
+
if (responseTypesToGenerate.size > 0) {
|
|
824
782
|
output.push("// Generated Response Types");
|
|
825
783
|
output.push("");
|
|
826
784
|
for (const [typeName, schema] of responseTypesToGenerate) {
|
|
@@ -836,19 +794,6 @@ function generateResponseTypes(output, operations, spec, nameMap, schemaOptions)
|
|
|
836
794
|
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
837
795
|
output.push("");
|
|
838
796
|
}
|
|
839
|
-
for (const [typeName, schema] of errorTypesToGenerate) {
|
|
840
|
-
const generatedSchema = generateZodSchema(
|
|
841
|
-
typeName,
|
|
842
|
-
schema,
|
|
843
|
-
/* @__PURE__ */ new Set(),
|
|
844
|
-
schemaOptions,
|
|
845
|
-
nameMap
|
|
846
|
-
);
|
|
847
|
-
output.push(generatedSchema);
|
|
848
|
-
output.push("");
|
|
849
|
-
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
850
|
-
output.push("");
|
|
851
|
-
}
|
|
852
797
|
}
|
|
853
798
|
}
|
|
854
799
|
function appendOperationField(buffer, key, value) {
|
|
@@ -914,12 +859,12 @@ function inferResponseType(contentType, statusCode) {
|
|
|
914
859
|
function parseOperations(spec, nameMap) {
|
|
915
860
|
const operations = [];
|
|
916
861
|
if (spec.paths) {
|
|
917
|
-
for (const [
|
|
862
|
+
for (const [path2, pathItem] of Object.entries(spec.paths)) {
|
|
918
863
|
for (const [method, operation] of Object.entries(pathItem)) {
|
|
919
864
|
const normalizedMethod = method.toLowerCase();
|
|
920
865
|
if (!isRequestMethod(normalizedMethod)) continue;
|
|
921
866
|
if (!operation.operationId) continue;
|
|
922
|
-
const pathParams = extractPathParams(
|
|
867
|
+
const pathParams = extractPathParams(path2);
|
|
923
868
|
const requestType = getRequestType(operation);
|
|
924
869
|
const { successResponse, errors } = getResponseTypes(
|
|
925
870
|
operation,
|
|
@@ -931,7 +876,7 @@ function parseOperations(spec, nameMap) {
|
|
|
931
876
|
const queryParams = getQueryParams(resolvedParameters);
|
|
932
877
|
operations.push({
|
|
933
878
|
operationId: operation.operationId,
|
|
934
|
-
path:
|
|
879
|
+
path: path2,
|
|
935
880
|
method: normalizedMethod,
|
|
936
881
|
pathParams,
|
|
937
882
|
queryParams,
|
|
@@ -949,8 +894,8 @@ function parseOperations(spec, nameMap) {
|
|
|
949
894
|
const normalizedMethod = method.toLowerCase();
|
|
950
895
|
if (!isRequestMethod(normalizedMethod)) continue;
|
|
951
896
|
if (!operation.operationId) continue;
|
|
952
|
-
const
|
|
953
|
-
const pathParams = extractPathParams(
|
|
897
|
+
const path2 = webhookName;
|
|
898
|
+
const pathParams = extractPathParams(path2);
|
|
954
899
|
const requestType = getRequestType(operation);
|
|
955
900
|
const { successResponse, errors } = getResponseTypes(
|
|
956
901
|
operation,
|
|
@@ -965,7 +910,7 @@ function parseOperations(spec, nameMap) {
|
|
|
965
910
|
const queryParams = getQueryParams(resolvedParameters);
|
|
966
911
|
operations.push({
|
|
967
912
|
operationId: operation.operationId,
|
|
968
|
-
path:
|
|
913
|
+
path: path2,
|
|
969
914
|
method: normalizedMethod,
|
|
970
915
|
pathParams,
|
|
971
916
|
queryParams,
|
|
@@ -1165,9 +1110,9 @@ function resolveParameter2(parameter, spec) {
|
|
|
1165
1110
|
}
|
|
1166
1111
|
return parameter;
|
|
1167
1112
|
}
|
|
1168
|
-
function extractPathParams(
|
|
1113
|
+
function extractPathParams(path2) {
|
|
1169
1114
|
const params = [];
|
|
1170
|
-
const matches =
|
|
1115
|
+
const matches = path2.match(/{([^}]+)}/g);
|
|
1171
1116
|
if (matches) {
|
|
1172
1117
|
for (const match of matches) {
|
|
1173
1118
|
const paramName = match.slice(1, -1);
|
|
@@ -1578,74 +1523,6 @@ function applyNumericBounds(schema, builder) {
|
|
|
1578
1523
|
return builder;
|
|
1579
1524
|
}
|
|
1580
1525
|
|
|
1581
|
-
// src/loader.ts
|
|
1582
|
-
var path = __toESM(require("path"), 1);
|
|
1583
|
-
var import_url = require("url");
|
|
1584
|
-
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yaml", ".yml"]);
|
|
1585
|
-
var JSON_EXTENSIONS = /* @__PURE__ */ new Set([".json"]);
|
|
1586
|
-
async function readFileText(filePath) {
|
|
1587
|
-
const file = Bun.file(filePath);
|
|
1588
|
-
if (!await file.exists()) {
|
|
1589
|
-
throw new Error(`File not found: ${filePath}`);
|
|
1590
|
-
}
|
|
1591
|
-
return await file.text();
|
|
1592
|
-
}
|
|
1593
|
-
async function loadConfig(filePath) {
|
|
1594
|
-
const extension = path.extname(filePath).toLowerCase();
|
|
1595
|
-
if (JSON_EXTENSIONS.has(extension)) {
|
|
1596
|
-
const content = await readFileText(filePath);
|
|
1597
|
-
return JSON.parse(content);
|
|
1598
|
-
}
|
|
1599
|
-
if (YAML_EXTENSIONS.has(extension)) {
|
|
1600
|
-
const content = await readFileText(filePath);
|
|
1601
|
-
return Bun.YAML.parse(content);
|
|
1602
|
-
}
|
|
1603
|
-
const fileUrl = (0, import_url.pathToFileURL)(filePath).href;
|
|
1604
|
-
const module2 = await import(fileUrl);
|
|
1605
|
-
return module2.default ?? module2.config ?? module2;
|
|
1606
|
-
}
|
|
1607
|
-
async function loadSpec(filePath) {
|
|
1608
|
-
const extension = path.extname(filePath).toLowerCase();
|
|
1609
|
-
const content = await readFileText(filePath);
|
|
1610
|
-
if (YAML_EXTENSIONS.has(extension)) {
|
|
1611
|
-
const parsed = Bun.YAML.parse(content);
|
|
1612
|
-
if (!parsed || typeof parsed !== "object") {
|
|
1613
|
-
throw new Error(`YAML spec did not resolve to an object: ${filePath}`);
|
|
1614
|
-
}
|
|
1615
|
-
if (Array.isArray(parsed)) {
|
|
1616
|
-
throw new Error(
|
|
1617
|
-
`YAML spec produced multiple documents; provide a single document in ${filePath}`
|
|
1618
|
-
);
|
|
1619
|
-
}
|
|
1620
|
-
return parsed;
|
|
1621
|
-
}
|
|
1622
|
-
if (JSON_EXTENSIONS.has(extension)) {
|
|
1623
|
-
return JSON.parse(content);
|
|
1624
|
-
}
|
|
1625
|
-
throw new Error(
|
|
1626
|
-
`Unsupported specification format for ${filePath}. Expected .yaml, .yml, or .json`
|
|
1627
|
-
);
|
|
1628
|
-
}
|
|
1629
|
-
function normalizeGenerationOptions(entry, baseDir, defaults) {
|
|
1630
|
-
const resolvedInput = path.isAbsolute(entry.input) ? entry.input : path.join(baseDir, entry.input);
|
|
1631
|
-
const resolvedOutput = path.isAbsolute(entry.output) ? entry.output : path.join(baseDir, entry.output);
|
|
1632
|
-
return {
|
|
1633
|
-
resolvedInput,
|
|
1634
|
-
resolvedOutput,
|
|
1635
|
-
strictDates: entry.strictDates ?? defaults.strictDates,
|
|
1636
|
-
strictNumeric: entry.strictNumeric ?? defaults.strictNumeric,
|
|
1637
|
-
types: mergeTypesConfig(defaults.types, entry.types),
|
|
1638
|
-
operationIds: entry.operationIds ?? defaults.operationIds
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
|
-
function mergeTypesConfig(baseConfig, entryConfig) {
|
|
1642
|
-
if (!baseConfig && !entryConfig) return void 0;
|
|
1643
|
-
return {
|
|
1644
|
-
...baseConfig,
|
|
1645
|
-
...entryConfig
|
|
1646
|
-
};
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
1526
|
// src/cli.ts
|
|
1650
1527
|
async function main() {
|
|
1651
1528
|
const args = process.argv.slice(2);
|
|
@@ -1671,8 +1548,8 @@ async function main() {
|
|
|
1671
1548
|
return;
|
|
1672
1549
|
}
|
|
1673
1550
|
await generateSingle({
|
|
1674
|
-
|
|
1675
|
-
|
|
1551
|
+
inputFile,
|
|
1552
|
+
outputFile,
|
|
1676
1553
|
strictDates: parsed.strictDates,
|
|
1677
1554
|
strictNumeric: parsed.strictNumeric
|
|
1678
1555
|
});
|
|
@@ -1740,22 +1617,39 @@ function printHelp() {
|
|
|
1740
1617
|
}
|
|
1741
1618
|
async function runFromConfig(parsed) {
|
|
1742
1619
|
const configPath = parsed.configPath;
|
|
1743
|
-
const resolvedConfigPath =
|
|
1744
|
-
const
|
|
1745
|
-
validateConfig(
|
|
1746
|
-
const
|
|
1747
|
-
const
|
|
1748
|
-
const defaults = {
|
|
1749
|
-
strictDates: parsed.strictDates,
|
|
1750
|
-
strictNumeric: parsed.strictNumeric,
|
|
1751
|
-
types: config.types,
|
|
1752
|
-
operationIds: void 0
|
|
1753
|
-
};
|
|
1620
|
+
const resolvedConfigPath = path.resolve(configPath);
|
|
1621
|
+
const config = await loadConfig(resolvedConfigPath);
|
|
1622
|
+
validateConfig(config);
|
|
1623
|
+
const baseDir = path.dirname(resolvedConfigPath);
|
|
1624
|
+
const baseTypesConfig = config.types;
|
|
1754
1625
|
for (const entry of config.schemas) {
|
|
1755
|
-
const
|
|
1756
|
-
|
|
1626
|
+
const inputFile = resolvePath(entry.input, baseDir);
|
|
1627
|
+
const outputFile = resolvePath(entry.output, baseDir);
|
|
1628
|
+
const typesConfig = resolveTypesConfig(baseTypesConfig, entry.types);
|
|
1629
|
+
await generateSingle({
|
|
1630
|
+
inputFile,
|
|
1631
|
+
outputFile,
|
|
1632
|
+
strictDates: entry.strictDates ?? parsed.strictDates,
|
|
1633
|
+
strictNumeric: entry.strictNumeric ?? parsed.strictNumeric,
|
|
1634
|
+
typesConfig,
|
|
1635
|
+
operationIds: entry.operationIds
|
|
1636
|
+
});
|
|
1757
1637
|
}
|
|
1758
1638
|
}
|
|
1639
|
+
async function loadConfig(filePath) {
|
|
1640
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
1641
|
+
if (extension === ".json") {
|
|
1642
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
1643
|
+
return JSON.parse(content);
|
|
1644
|
+
}
|
|
1645
|
+
if (extension === ".yaml" || extension === ".yml") {
|
|
1646
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
1647
|
+
return (0, import_js_yaml.load)(content);
|
|
1648
|
+
}
|
|
1649
|
+
const fileUrl = (0, import_url.pathToFileURL)(filePath).href;
|
|
1650
|
+
const module2 = await import(fileUrl);
|
|
1651
|
+
return module2.default ?? module2.config ?? module2;
|
|
1652
|
+
}
|
|
1759
1653
|
function validateConfig(config) {
|
|
1760
1654
|
if (!config || typeof config !== "object") {
|
|
1761
1655
|
throw new Error("Config file must export an object");
|
|
@@ -1772,44 +1666,68 @@ function validateConfig(config) {
|
|
|
1772
1666
|
}
|
|
1773
1667
|
}
|
|
1774
1668
|
}
|
|
1669
|
+
function resolvePath(filePath, baseDir) {
|
|
1670
|
+
return path.isAbsolute(filePath) ? filePath : path.join(baseDir, filePath);
|
|
1671
|
+
}
|
|
1672
|
+
function resolveTypesConfig(baseConfig, entryConfig) {
|
|
1673
|
+
if (!baseConfig && !entryConfig) return void 0;
|
|
1674
|
+
return {
|
|
1675
|
+
...baseConfig,
|
|
1676
|
+
...entryConfig
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1775
1679
|
async function generateSingle(options) {
|
|
1776
1680
|
const {
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
strictDates
|
|
1780
|
-
strictNumeric
|
|
1781
|
-
|
|
1681
|
+
inputFile,
|
|
1682
|
+
outputFile,
|
|
1683
|
+
strictDates,
|
|
1684
|
+
strictNumeric,
|
|
1685
|
+
typesConfig,
|
|
1782
1686
|
operationIds
|
|
1783
1687
|
} = options;
|
|
1784
|
-
const
|
|
1785
|
-
const
|
|
1688
|
+
const resolvedInput = path.resolve(inputFile);
|
|
1689
|
+
const resolvedOutput = path.resolve(outputFile);
|
|
1690
|
+
const spec = readSpec(resolvedInput);
|
|
1691
|
+
const result = generateWithMetadata(spec, {
|
|
1786
1692
|
strictDates,
|
|
1787
1693
|
strictNumeric,
|
|
1788
|
-
types,
|
|
1694
|
+
types: typesConfig,
|
|
1789
1695
|
operationIds
|
|
1790
1696
|
});
|
|
1791
|
-
|
|
1792
|
-
|
|
1697
|
+
fs.mkdirSync(path.dirname(resolvedOutput), { recursive: true });
|
|
1698
|
+
fs.writeFileSync(resolvedOutput, result.output);
|
|
1793
1699
|
console.log(`\u2705 Generated TypeScript types in ${resolvedOutput}`);
|
|
1794
1700
|
console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths || {}).length} paths`);
|
|
1795
1701
|
if (spec.webhooks) {
|
|
1796
1702
|
console.log(`\u{1FA9D} Processed ${Object.keys(spec.webhooks).length} webhooks`);
|
|
1797
1703
|
}
|
|
1798
1704
|
if (result.helperFile) {
|
|
1799
|
-
const helperPath =
|
|
1800
|
-
const absoluteResolvedOutput =
|
|
1801
|
-
const absoluteHelperPath =
|
|
1705
|
+
const helperPath = path.isAbsolute(result.helperFile.path) ? result.helperFile.path : path.resolve(path.dirname(resolvedOutput), result.helperFile.path);
|
|
1706
|
+
const absoluteResolvedOutput = path.resolve(resolvedOutput);
|
|
1707
|
+
const absoluteHelperPath = path.resolve(helperPath);
|
|
1802
1708
|
if (absoluteResolvedOutput === absoluteHelperPath) {
|
|
1803
1709
|
console.warn(
|
|
1804
1710
|
`\u26A0\uFE0F Skipping helper file generation: would overwrite main output at ${absoluteResolvedOutput}`
|
|
1805
1711
|
);
|
|
1806
1712
|
return;
|
|
1807
1713
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1714
|
+
fs.mkdirSync(path.dirname(helperPath), { recursive: true });
|
|
1715
|
+
fs.writeFileSync(helperPath, result.helperFile.content, {
|
|
1716
|
+
encoding: "utf8"
|
|
1717
|
+
});
|
|
1810
1718
|
console.log(`\u{1F4E6} Generated helper types in ${helperPath}`);
|
|
1811
1719
|
}
|
|
1812
1720
|
}
|
|
1721
|
+
function readSpec(filePath) {
|
|
1722
|
+
if (!fs.existsSync(filePath)) {
|
|
1723
|
+
throw new Error(`Input file not found: ${filePath}`);
|
|
1724
|
+
}
|
|
1725
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
1726
|
+
if (filePath.endsWith(".yaml") || filePath.endsWith(".yml")) {
|
|
1727
|
+
return (0, import_js_yaml.load)(content);
|
|
1728
|
+
}
|
|
1729
|
+
return JSON.parse(content);
|
|
1730
|
+
}
|
|
1813
1731
|
main().catch((error) => {
|
|
1814
1732
|
console.error("\u274C Error:", error);
|
|
1815
1733
|
process.exit(1);
|