swgto-ts 0.1.0 → 0.1.1

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.
@@ -53,6 +53,66 @@ function groupByPrefix(operations) {
53
53
  }, {});
54
54
  }
55
55
 
56
+ // src/generators/schemaToTs.ts
57
+ function formatPropertyName(name) {
58
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
59
+ }
60
+ function refToTypeName(ref) {
61
+ const parts = ref.split("/");
62
+ return parts[parts.length - 1] || "unknown";
63
+ }
64
+ function schemaToTs(schema) {
65
+ if (!schema) {
66
+ return "unknown";
67
+ }
68
+ if (schema.$ref) {
69
+ return refToTypeName(schema.$ref);
70
+ }
71
+ if (schema.enum?.length) {
72
+ return schema.enum.map((item) => JSON.stringify(item)).join(" | ");
73
+ }
74
+ if (schema.anyOf?.length) {
75
+ return schema.anyOf.map((item) => schemaToTs(item)).join(" | ");
76
+ }
77
+ if (schema.oneOf?.length) {
78
+ return schema.oneOf.map((item) => schemaToTs(item)).join(" | ");
79
+ }
80
+ if (schema.allOf?.length) {
81
+ return schema.allOf.map((item) => schemaToTs(item)).join(" & ");
82
+ }
83
+ if (schema.type === "array") {
84
+ return `${schemaToTs(schema.items)}[]`;
85
+ }
86
+ if (schema.type === "object" || schema.properties) {
87
+ const requiredSet = new Set(schema.required ?? []);
88
+ const properties = Object.entries(schema.properties ?? {}).map(([key, value]) => {
89
+ const optional = requiredSet.has(key) ? "" : "?";
90
+ return `${formatPropertyName(key)}${optional}: ${schemaToTs(value)};`;
91
+ });
92
+ if (!properties.length && schema.additionalProperties) {
93
+ const valueType = schema.additionalProperties === true ? "unknown" : schemaToTs(schema.additionalProperties);
94
+ return `{ [key: string]: ${valueType} }`;
95
+ }
96
+ return `{ ${properties.join(" ")} }`;
97
+ }
98
+ switch (schema.type) {
99
+ case "integer":
100
+ case "number":
101
+ return "number";
102
+ case "boolean":
103
+ return "boolean";
104
+ case "string":
105
+ return "string";
106
+ case "null":
107
+ return "null";
108
+ default:
109
+ return "unknown";
110
+ }
111
+ }
112
+ function toTypePropertyName(name) {
113
+ return formatPropertyName(name);
114
+ }
115
+
56
116
  // src/utils/naming.ts
57
117
  function toPascalCase(value) {
58
118
  return value.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((segment) => segment[0].toUpperCase() + segment.slice(1)).join("");
@@ -77,6 +137,36 @@ function buildTypeName(functionName, suffix) {
77
137
 
78
138
  // src/core/parsePaths.ts
79
139
  var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"];
140
+ function collectReferencedTypeNames(schema, collected = /* @__PURE__ */ new Set()) {
141
+ if (!schema) {
142
+ return [...collected];
143
+ }
144
+ if (schema.$ref) {
145
+ const typeName = schema.$ref.split("/").pop();
146
+ if (typeName) {
147
+ collected.add(typeName);
148
+ }
149
+ }
150
+ for (const child of schema.anyOf ?? []) {
151
+ collectReferencedTypeNames(child, collected);
152
+ }
153
+ for (const child of schema.oneOf ?? []) {
154
+ collectReferencedTypeNames(child, collected);
155
+ }
156
+ for (const child of schema.allOf ?? []) {
157
+ collectReferencedTypeNames(child, collected);
158
+ }
159
+ if (schema.items) {
160
+ collectReferencedTypeNames(schema.items, collected);
161
+ }
162
+ for (const property of Object.values(schema.properties ?? {})) {
163
+ collectReferencedTypeNames(property, collected);
164
+ }
165
+ if (schema.additionalProperties && schema.additionalProperties !== true) {
166
+ collectReferencedTypeNames(schema.additionalProperties, collected);
167
+ }
168
+ return [...collected];
169
+ }
80
170
  function getPrimarySchema(content) {
81
171
  if (!content) {
82
172
  return void 0;
@@ -108,7 +198,21 @@ function parsePaths(document, docUrl, config) {
108
198
  const requestBodySchema = getPrimarySchema(operation.requestBody?.content);
109
199
  const responseSchema = getSuccessResponse(operation.responses);
110
200
  const hasRequestParams = queryParams.length > 0 || pathParams.length > 0 || Boolean(requestBodySchema);
111
- const requestTypeName = hasRequestParams ? buildTypeName(functionName, "Request") : void 0;
201
+ const bodyType = requestBodySchema ? schemaToTs(requestBodySchema) : void 0;
202
+ const requestImportTypes = collectReferencedTypeNames(requestBodySchema);
203
+ const pathFields = pathParams.map((param) => `${param.name}: ${schemaToTs(param.schema)};`);
204
+ const queryFields = queryParams.map((param) => `${param.name}${param.required ? "" : "?"}: ${schemaToTs(param.schema)};`);
205
+ const requestTypeParts = [];
206
+ if (bodyType) {
207
+ requestTypeParts.push(bodyType);
208
+ }
209
+ if (pathFields.length) {
210
+ requestTypeParts.push(`{ path: { ${pathFields.join(" ")} } }`);
211
+ }
212
+ if (queryFields.length) {
213
+ requestTypeParts.push(`{ query: { ${queryFields.join(" ")} } }`);
214
+ }
215
+ const requestTypeExpression = hasRequestParams ? requestTypeParts.join(" & ") || "unknown" : void 0;
112
216
  operations.push({
113
217
  docUrl,
114
218
  moduleName,
@@ -123,7 +227,8 @@ function parsePaths(document, docUrl, config) {
123
227
  pathParams,
124
228
  requestBodySchema,
125
229
  responseSchema,
126
- requestTypeName,
230
+ requestTypeExpression,
231
+ requestImportTypes,
127
232
  responseTypeName: responseSchema ? buildTypeName(functionName, "Response") : void 0,
128
233
  fileBaseName: functionName
129
234
  });
@@ -178,9 +283,11 @@ function buildFunctionDoc(operation, typeImportPath, requestParamType) {
178
283
  return ["/**", ...lines.map((line) => ` * ${line}`), " */"].join("\n");
179
284
  }
180
285
  function generateJsRequestFile(operation, httpClientPath, typeImportPath) {
181
- const requestParamType = operation.requestTypeName ?? "void";
286
+ const requestParamType = operation.requestTypeExpression ?? "void";
182
287
  const queryLine = operation.queryParams.length ? " params: params?.query,\n" : "";
183
- const bodyLine = operation.requestBodySchema ? " data: params?.body,\n" : "";
288
+ const bodyOnly = Boolean(operation.requestBodySchema) && !operation.queryParams.length && !operation.pathParams.length;
289
+ const bodyLine = operation.requestBodySchema ? ` data: ${bodyOnly ? "params" : "params?.body"},
290
+ ` : "";
184
291
  const pathLine = operation.pathParams.length ? " url: buildUrl(params?.path),\n" : ` url: ${JSON.stringify(operation.requestPath)},
185
292
  `;
186
293
  const buildUrlHelper = operation.pathParams.length ? `
@@ -219,15 +326,17 @@ function buildFunctionDoc2(operation) {
219
326
  }
220
327
  function generateTsRequestFile(operation, httpClientPath, typeImportPath) {
221
328
  const importTypes = [
222
- operation.requestTypeName,
329
+ ...operation.requestImportTypes,
223
330
  operation.responseTypeName,
224
331
  "RequestConfig"
225
332
  ].filter((value, index, array) => Boolean(value) && array.indexOf(value) === index);
226
333
  const importLine = importTypes.length ? `import type { ${importTypes.join(", ")} } from ${JSON.stringify(typeImportPath)};
227
334
  ` : "";
228
- const requestArg = operation.requestTypeName ? `params: ${operation.requestTypeName}, config?: RequestConfig` : "params?: void, config?: RequestConfig";
335
+ const requestArg = operation.requestTypeExpression ? `params: ${operation.requestTypeExpression}, config?: RequestConfig` : "params?: void, config?: RequestConfig";
229
336
  const defaultResponseType = operation.responseTypeName ?? "unknown";
230
- const bodyLine = operation.requestBodySchema ? " data: params?.body,\n" : "";
337
+ const bodyOnly = Boolean(operation.requestBodySchema) && !operation.queryParams.length && !operation.pathParams.length;
338
+ const bodyLine = operation.requestBodySchema ? ` data: ${bodyOnly ? "params" : "params?.body"},
339
+ ` : "";
231
340
  const queryLine = operation.queryParams.length ? " params: params?.query,\n" : "";
232
341
  const pathLine = operation.pathParams.length ? " url: buildUrl(params?.path),\n" : ` url: ${JSON.stringify(operation.requestPath)},
233
342
  `;
@@ -251,66 +360,6 @@ ${queryLine}${bodyLine} ...config,
251
360
  `;
252
361
  }
253
362
 
254
- // src/generators/schemaToTs.ts
255
- function formatPropertyName(name) {
256
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
257
- }
258
- function refToTypeName(ref) {
259
- const parts = ref.split("/");
260
- return parts[parts.length - 1] || "unknown";
261
- }
262
- function schemaToTs(schema) {
263
- if (!schema) {
264
- return "unknown";
265
- }
266
- if (schema.$ref) {
267
- return refToTypeName(schema.$ref);
268
- }
269
- if (schema.enum?.length) {
270
- return schema.enum.map((item) => JSON.stringify(item)).join(" | ");
271
- }
272
- if (schema.anyOf?.length) {
273
- return schema.anyOf.map((item) => schemaToTs(item)).join(" | ");
274
- }
275
- if (schema.oneOf?.length) {
276
- return schema.oneOf.map((item) => schemaToTs(item)).join(" | ");
277
- }
278
- if (schema.allOf?.length) {
279
- return schema.allOf.map((item) => schemaToTs(item)).join(" & ");
280
- }
281
- if (schema.type === "array") {
282
- return `${schemaToTs(schema.items)}[]`;
283
- }
284
- if (schema.type === "object" || schema.properties) {
285
- const requiredSet = new Set(schema.required ?? []);
286
- const properties = Object.entries(schema.properties ?? {}).map(([key, value]) => {
287
- const optional = requiredSet.has(key) ? "" : "?";
288
- return `${formatPropertyName(key)}${optional}: ${schemaToTs(value)};`;
289
- });
290
- if (!properties.length && schema.additionalProperties) {
291
- const valueType = schema.additionalProperties === true ? "unknown" : schemaToTs(schema.additionalProperties);
292
- return `{ [key: string]: ${valueType} }`;
293
- }
294
- return `{ ${properties.join(" ")} }`;
295
- }
296
- switch (schema.type) {
297
- case "integer":
298
- case "number":
299
- return "number";
300
- case "boolean":
301
- return "boolean";
302
- case "string":
303
- return "string";
304
- case "null":
305
- return "null";
306
- default:
307
- return "unknown";
308
- }
309
- }
310
- function toTypePropertyName(name) {
311
- return formatPropertyName(name);
312
- }
313
-
314
363
  // src/generators/genTypes.ts
315
364
  function formatDocLines(lines) {
316
365
  if (!lines.length) {
@@ -328,16 +377,6 @@ function buildSchemaDoc(schema) {
328
377
  }
329
378
  return formatDocLines(lines);
330
379
  }
331
- function buildParameterDoc(parameter, fallback) {
332
- const lines = [parameter.description ?? fallback];
333
- if (parameter.required) {
334
- lines.push("@required");
335
- }
336
- if (parameter.example !== void 0) {
337
- lines.push(`@example ${JSON.stringify(parameter.example)}`);
338
- }
339
- return formatDocLines(lines);
340
- }
341
380
  function renderObjectFields(fields, indent = "") {
342
381
  const lines = [];
343
382
  for (const field of fields) {
@@ -370,56 +409,6 @@ ${body}
370
409
  }
371
410
  function renderOperationTypes(operation) {
372
411
  const blocks = [];
373
- if (operation.requestTypeName) {
374
- const fields = [];
375
- const pathFields = [];
376
- const queryFields = [];
377
- for (const param of operation.pathParams) {
378
- pathFields.push({
379
- name: toTypePropertyName(param.name),
380
- type: schemaToTs(param.schema),
381
- optional: false,
382
- doc: buildParameterDoc(param, `Path parameter: ${param.name}`)
383
- });
384
- }
385
- for (const param of operation.queryParams) {
386
- queryFields.push({
387
- name: toTypePropertyName(param.name),
388
- type: schemaToTs(param.schema),
389
- optional: !param.required,
390
- doc: buildParameterDoc(param, `Query parameter: ${param.name}`)
391
- });
392
- }
393
- if (operation.requestBodySchema) {
394
- const doc = buildSchemaDoc(operation.requestBodySchema);
395
- if (doc) {
396
- fields.push(...doc.split("\n"));
397
- }
398
- fields.push(`body${operation.requestBodySchema.nullable ? "?" : ""}: ${schemaToTs(operation.requestBodySchema)};`);
399
- }
400
- if (pathFields.length) {
401
- fields.push("/** Path parameters */");
402
- fields.push("path: {");
403
- fields.push(...renderObjectFields(pathFields, " "));
404
- fields.push("};");
405
- }
406
- if (queryFields.length) {
407
- fields.push("/** Query parameters */");
408
- fields.push("query: {");
409
- fields.push(...renderObjectFields(queryFields, " "));
410
- fields.push("};");
411
- }
412
- const requestDoc = formatDocLines(
413
- [
414
- operation.summary,
415
- operation.description
416
- ].filter((value) => Boolean(value))
417
- );
418
- blocks.push(`${requestDoc ? `${requestDoc}
419
- ` : ""}export interface ${operation.requestTypeName} {
420
- ${fields.map((line) => ` ${line}`).join("\n")}
421
- }`);
422
- }
423
412
  if (operation.responseTypeName) {
424
413
  const responseDoc = buildSchemaDoc(operation.responseSchema);
425
414
  blocks.push(`${responseDoc ? `${responseDoc}
@@ -450,13 +439,6 @@ function generateTypesFile(documentMap, operations, config) {
450
439
  }
451
440
  }
452
441
  for (const operation of operations) {
453
- if (operation.requestTypeName) {
454
- const rendered = renderOperationTypes(operation).find((line) => line.startsWith(`export interface ${operation.requestTypeName}`));
455
- if (rendered) {
456
- const body = rendered.replace(`export interface ${operation.requestTypeName} `, "").trim();
457
- parts2.push(`/** @typedef ${body} ${operation.requestTypeName} */`);
458
- }
459
- }
460
442
  if (operation.responseTypeName) {
461
443
  parts2.push(`/** @typedef {${toJSDocType(schemaToTs(operation.responseSchema))}} ${operation.responseTypeName} */`);
462
444
  }
@@ -484,7 +466,7 @@ function generateTypesFile(documentMap, operations, config) {
484
466
  function generateApiDtsContent(operations, config) {
485
467
  const lines = ["// Auto-generated by swgto.", 'export * from "./index";', `export * from "./${config.typeName}";`];
486
468
  for (const operation of operations) {
487
- const paramsType = operation.requestTypeName ?? "void";
469
+ const paramsType = operation.requestTypeExpression ?? "void";
488
470
  const responseType = operation.responseTypeName ?? "unknown";
489
471
  lines.push(`export declare function ${operation.functionName}<T = ${responseType}>(params${paramsType === "void" ? "?" : ""}: ${paramsType}, config?: import("./index").RequestConfig): Promise<T>;`);
490
472
  }
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  generateFromConfig
4
- } from "./chunk-RRFCLHNU.js";
4
+ } from "./chunk-5JY6MCOD.js";
5
5
 
6
6
  // src/cli.ts
7
7
  async function main() {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  generateFromConfig
3
- } from "./chunk-RRFCLHNU.js";
3
+ } from "./chunk-5JY6MCOD.js";
4
4
  export {
5
5
  generateFromConfig
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swgto-ts",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Generate API request files from OpenAPI 3.x documents.",
5
5
  "license": "MIT",
6
6
  "type": "module",