mobx-tanstack-query-api 0.37.1 → 0.38.0
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 +8 -1
- package/bin.cjs.map +1 -1
- package/bin.js.map +1 -1
- package/cli.cjs +473 -16
- package/cli.cjs.map +1 -1
- package/cli.d.ts +26 -0
- package/cli.js +473 -16
- package/cli.js.map +1 -1
- package/index.cjs +68 -5
- package/index.cjs.map +1 -1
- package/index.d.ts +39 -2
- package/index.js +68 -5
- package/index.js.map +1 -1
- package/package.json +9 -3
package/cli.d.ts
CHANGED
|
@@ -184,6 +184,32 @@ interface GenerateQueryApiParams {
|
|
|
184
184
|
* [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/codegen/config/#nobarrelfiles)
|
|
185
185
|
*/
|
|
186
186
|
noBarrelFiles?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Generate Zod contracts (params + data schemas) for each endpoint and add `contracts` to the endpoint config.
|
|
189
|
+
* When truthy, can also enable validation via `validateContracts` in the endpoint config.
|
|
190
|
+
* Requires `zod` to be installed.
|
|
191
|
+
*
|
|
192
|
+
* - `true`: generate contracts and set `validateContracts: true` (validate params + data).
|
|
193
|
+
* - `false`: no contracts, no validation.
|
|
194
|
+
* - `{ validate: boolean }`: set `validateContracts` to that boolean.
|
|
195
|
+
* - `{ validate: string }`: set `validateContracts` to the expression (inserted as-is). E.g. `"process.env.NODE_ENV === 'development'"`.
|
|
196
|
+
* - `{ validate: { params?: boolean | string; data?: boolean | string } }`: set `validateContracts` to an object; each value is literal or expression (string inserted as-is).
|
|
197
|
+
*
|
|
198
|
+
* When using an object form, optional `throw` controls `throwContracts` (throw on validation errors vs warn):
|
|
199
|
+
* - `{ throw: boolean }`: set `throwContracts` to that boolean.
|
|
200
|
+
* - `{ throw: string }`: set `throwContracts` to the expression (inserted as-is).
|
|
201
|
+
* - `{ throw: { params?: boolean | string; data?: boolean | string } }`: set `throwContracts` to an object; each value is literal or expression (string inserted as-is).
|
|
202
|
+
*/
|
|
203
|
+
zodContracts?: boolean | {
|
|
204
|
+
validate: boolean | string | {
|
|
205
|
+
params?: boolean | string;
|
|
206
|
+
data?: boolean | string;
|
|
207
|
+
};
|
|
208
|
+
throw?: boolean | string | {
|
|
209
|
+
params?: boolean | string;
|
|
210
|
+
data?: boolean | string;
|
|
211
|
+
};
|
|
212
|
+
};
|
|
187
213
|
}
|
|
188
214
|
|
|
189
215
|
type AllImportFileParams = Record<KeyOfByValue<Required<GenerateQueryApiParams>, 'builtin' | ImportFileParams>, ImportFileParams>;
|
package/cli.js
CHANGED
|
@@ -216,6 +216,301 @@ const createShortModelType = (shortModelType) => {
|
|
|
216
216
|
description: shortModelType.description || ""
|
|
217
217
|
};
|
|
218
218
|
};
|
|
219
|
+
const REF_PREFIX = "#/components/schemas/";
|
|
220
|
+
function parseRef(ref) {
|
|
221
|
+
if (typeof ref !== "string" || !ref.startsWith(REF_PREFIX)) return null;
|
|
222
|
+
return ref.slice(REF_PREFIX.length);
|
|
223
|
+
}
|
|
224
|
+
function getResponseSchemaKeyFromOperation(rawOperation) {
|
|
225
|
+
const op = rawOperation;
|
|
226
|
+
const responses = op?.responses;
|
|
227
|
+
if (!responses || typeof responses !== "object") return null;
|
|
228
|
+
const successStatus = Object.keys(responses).find((s) => {
|
|
229
|
+
const code = Number.parseInt(s, 10);
|
|
230
|
+
return code >= 200 && code < 300;
|
|
231
|
+
});
|
|
232
|
+
if (!successStatus) return null;
|
|
233
|
+
const successResponse = responses[successStatus];
|
|
234
|
+
const content = successResponse?.content;
|
|
235
|
+
if (!content || typeof content !== "object") return null;
|
|
236
|
+
const jsonContent = content["application/json"] ?? Object.values(content)[0];
|
|
237
|
+
const ref = jsonContent?.schema?.$ref;
|
|
238
|
+
if (typeof ref !== "string") return null;
|
|
239
|
+
return parseRef(ref);
|
|
240
|
+
}
|
|
241
|
+
function typeNameToSchemaKey(typeName, typeSuffix = "DC") {
|
|
242
|
+
const t = typeName.trim();
|
|
243
|
+
if (typeSuffix && t.endsWith(typeSuffix))
|
|
244
|
+
return t.slice(0, -typeSuffix.length);
|
|
245
|
+
return t;
|
|
246
|
+
}
|
|
247
|
+
function schemaToString(schema) {
|
|
248
|
+
let s = "z.string()";
|
|
249
|
+
if (schema.minLength != null) s += `.min(${schema.minLength})`;
|
|
250
|
+
if (schema.maxLength != null) s += `.max(${schema.maxLength})`;
|
|
251
|
+
if (schema.pattern != null)
|
|
252
|
+
s += `.regex(new RegExp(${JSON.stringify(schema.pattern)}))`;
|
|
253
|
+
if (schema.enum != null)
|
|
254
|
+
s = `z.enum([${schema.enum.map((e) => JSON.stringify(e)).join(", ")}])`;
|
|
255
|
+
return s;
|
|
256
|
+
}
|
|
257
|
+
function schemaToNumber(schema) {
|
|
258
|
+
let n = "z.number()";
|
|
259
|
+
if (schema.type === "integer") n += ".int()";
|
|
260
|
+
if (schema.minimum != null) n += `.min(${schema.minimum})`;
|
|
261
|
+
if (schema.maximum != null) n += `.max(${schema.maximum})`;
|
|
262
|
+
return n;
|
|
263
|
+
}
|
|
264
|
+
function schemaToArray(schema, schemas, schemaKeyToVarName2, visited) {
|
|
265
|
+
const items = schema.items ? schemaToZodExpr(schema.items, schemas, schemaKeyToVarName2) : "z.any()";
|
|
266
|
+
let a = `z.array(${items})`;
|
|
267
|
+
if (schema.minItems != null) a += `.min(${schema.minItems})`;
|
|
268
|
+
if (schema.maxItems != null) a += `.max(${schema.maxItems})`;
|
|
269
|
+
return a;
|
|
270
|
+
}
|
|
271
|
+
function schemaToObject(schema, schemas, schemaKeyToVarName2, visited) {
|
|
272
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
273
|
+
const required = new Set(schema.required ?? []);
|
|
274
|
+
const entries = Object.entries(schema.properties).map(
|
|
275
|
+
([propName, propSchema]) => {
|
|
276
|
+
const expr = schemaToZodExpr(
|
|
277
|
+
propSchema,
|
|
278
|
+
schemas,
|
|
279
|
+
schemaKeyToVarName2
|
|
280
|
+
);
|
|
281
|
+
const optional = !required.has(propName);
|
|
282
|
+
const field = optional ? `${expr}.optional()` : expr;
|
|
283
|
+
return ` ${JSON.stringify(propName)}: ${field}`;
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
return `z.object({
|
|
287
|
+
${entries.join(",\n")}
|
|
288
|
+
})`;
|
|
289
|
+
}
|
|
290
|
+
if (schema.additionalProperties === true)
|
|
291
|
+
return "z.record(z.string(), z.any())";
|
|
292
|
+
if (typeof schema.additionalProperties === "object") {
|
|
293
|
+
const value = schemaToZodExpr(
|
|
294
|
+
schema.additionalProperties,
|
|
295
|
+
schemas,
|
|
296
|
+
schemaKeyToVarName2
|
|
297
|
+
);
|
|
298
|
+
return `z.record(z.string(), ${value})`;
|
|
299
|
+
}
|
|
300
|
+
return "z.record(z.string(), z.any())";
|
|
301
|
+
}
|
|
302
|
+
function schemaToZodExpr(schema, schemas, schemaKeyToVarName2, visited) {
|
|
303
|
+
if (!schema) return "z.any()";
|
|
304
|
+
if (schema.$ref) {
|
|
305
|
+
const key = parseRef(schema.$ref);
|
|
306
|
+
if (key && key in schemas)
|
|
307
|
+
return `z.lazy(() => ${schemaKeyToVarName2(key)})`;
|
|
308
|
+
return "z.any()";
|
|
309
|
+
}
|
|
310
|
+
if (schema.allOf && schema.allOf.length > 0) {
|
|
311
|
+
const parts = schema.allOf.map(
|
|
312
|
+
(part) => schemaToZodExpr(part, schemas, schemaKeyToVarName2)
|
|
313
|
+
);
|
|
314
|
+
const base2 = parts.length === 1 ? parts[0] : parts.reduce((acc, p) => `z.intersection(${acc}, ${p})`);
|
|
315
|
+
return schema.nullable === true ? `${base2}.nullable()` : base2;
|
|
316
|
+
}
|
|
317
|
+
const nullable = schema.nullable === true;
|
|
318
|
+
let base;
|
|
319
|
+
switch (schema.type) {
|
|
320
|
+
case "string":
|
|
321
|
+
base = schemaToString(schema);
|
|
322
|
+
break;
|
|
323
|
+
case "integer":
|
|
324
|
+
case "number":
|
|
325
|
+
base = schemaToNumber(schema);
|
|
326
|
+
break;
|
|
327
|
+
case "boolean":
|
|
328
|
+
base = "z.boolean()";
|
|
329
|
+
break;
|
|
330
|
+
case "array":
|
|
331
|
+
base = schemaToArray(schema, schemas, schemaKeyToVarName2);
|
|
332
|
+
break;
|
|
333
|
+
case "object":
|
|
334
|
+
base = schemaToObject(schema, schemas, schemaKeyToVarName2);
|
|
335
|
+
break;
|
|
336
|
+
default:
|
|
337
|
+
base = "z.any()";
|
|
338
|
+
}
|
|
339
|
+
return nullable ? `${base}.nullable()` : base;
|
|
340
|
+
}
|
|
341
|
+
function collectRefs(schema, schemas, out) {
|
|
342
|
+
if (!schema) return;
|
|
343
|
+
if (schema.$ref) {
|
|
344
|
+
const key = parseRef(schema.$ref);
|
|
345
|
+
if (key && key in schemas && !out.has(key)) {
|
|
346
|
+
out.add(key);
|
|
347
|
+
collectRefs(schemas[key], schemas, out);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (schema.allOf) {
|
|
352
|
+
for (const part of schema.allOf) collectRefs(part, schemas, out);
|
|
353
|
+
}
|
|
354
|
+
if (schema.properties) {
|
|
355
|
+
for (const v of Object.values(schema.properties)) {
|
|
356
|
+
collectRefs(v, schemas, out);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (schema.items) collectRefs(schema.items, schemas, out);
|
|
360
|
+
if (typeof schema.additionalProperties === "object") {
|
|
361
|
+
collectRefs(schema.additionalProperties, schemas, out);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function schemaKeyToVarName(key, utils) {
|
|
365
|
+
const _ = utils._;
|
|
366
|
+
return `${_.camelCase(key)}Schema`;
|
|
367
|
+
}
|
|
368
|
+
function generateAuxiliarySchemas(schemaKeys, schemas, schemaKeyToVarNameFn, visited) {
|
|
369
|
+
const lines = [];
|
|
370
|
+
for (const key of schemaKeys) {
|
|
371
|
+
if (visited.has(key)) continue;
|
|
372
|
+
visited.add(key);
|
|
373
|
+
const schema = schemas[key];
|
|
374
|
+
if (!schema) continue;
|
|
375
|
+
const varName = schemaKeyToVarNameFn(key);
|
|
376
|
+
const expr = schemaToZodExpr(
|
|
377
|
+
schema,
|
|
378
|
+
schemas,
|
|
379
|
+
schemaKeyToVarNameFn
|
|
380
|
+
);
|
|
381
|
+
lines.push(`export const ${varName} = ${expr};`);
|
|
382
|
+
}
|
|
383
|
+
return lines;
|
|
384
|
+
}
|
|
385
|
+
function buildCentralZodSchemasFile(params) {
|
|
386
|
+
const { componentsSchemas, utils } = params;
|
|
387
|
+
const schemaKeyToVarNameFn = (key) => schemaKeyToVarName(key, utils);
|
|
388
|
+
const lines = generateAuxiliarySchemas(
|
|
389
|
+
Object.keys(componentsSchemas),
|
|
390
|
+
componentsSchemas,
|
|
391
|
+
schemaKeyToVarNameFn,
|
|
392
|
+
/* @__PURE__ */ new Set()
|
|
393
|
+
);
|
|
394
|
+
return `import * as z from "zod";
|
|
395
|
+
|
|
396
|
+
${lines.join("\n\n")}
|
|
397
|
+
`;
|
|
398
|
+
}
|
|
399
|
+
function typeToZodSchemaFallback(typeStr) {
|
|
400
|
+
const t = typeStr.trim();
|
|
401
|
+
if (t === "RequestParams") return "z.any()";
|
|
402
|
+
if (t === "Record<string, any>" || t === "Record<string, unknown>")
|
|
403
|
+
return "z.record(z.string(), z.any())";
|
|
404
|
+
if (/^Record\s*<\s*string\s*,/i.test(t))
|
|
405
|
+
return "z.record(z.string(), z.any())";
|
|
406
|
+
if (t === "string") return "z.string()";
|
|
407
|
+
if (t === "number") return "z.number()";
|
|
408
|
+
if (t === "boolean") return "z.boolean()";
|
|
409
|
+
if (t === "any") return "z.any()";
|
|
410
|
+
if (t === "unknown") return "z.unknown()";
|
|
411
|
+
return "z.any()";
|
|
412
|
+
}
|
|
413
|
+
function typeToZodSchemaWithSchema(typeStr, schemas, utils, typeSuffix) {
|
|
414
|
+
const t = typeStr.trim();
|
|
415
|
+
if (!schemas || Object.keys(schemas).length === 0) {
|
|
416
|
+
return { expr: typeToZodSchemaFallback(t), refs: [] };
|
|
417
|
+
}
|
|
418
|
+
if (t === "RequestParams") return { expr: "z.any()", refs: [] };
|
|
419
|
+
const schemaKey = typeNameToSchemaKey(t, typeSuffix);
|
|
420
|
+
const schema = schemas[schemaKey];
|
|
421
|
+
if (!schema) {
|
|
422
|
+
return { expr: typeToZodSchemaFallback(t), refs: [] };
|
|
423
|
+
}
|
|
424
|
+
const refs = /* @__PURE__ */ new Set();
|
|
425
|
+
collectRefs(schema, schemas, refs);
|
|
426
|
+
const schemaKeyToVarNameFn = (key) => schemaKeyToVarName(key, utils);
|
|
427
|
+
const expr = schemaToZodExpr(
|
|
428
|
+
schema,
|
|
429
|
+
schemas,
|
|
430
|
+
schemaKeyToVarNameFn
|
|
431
|
+
);
|
|
432
|
+
return { expr, refs: [...refs] };
|
|
433
|
+
}
|
|
434
|
+
function schemaKeyToZod(schemaKey, schemas, utils) {
|
|
435
|
+
const schema = schemas[schemaKey];
|
|
436
|
+
if (!schema) return { expr: "z.any()", refs: [] };
|
|
437
|
+
const refs = /* @__PURE__ */ new Set();
|
|
438
|
+
collectRefs(schema, schemas, refs);
|
|
439
|
+
const schemaKeyToVarNameFn = (key) => schemaKeyToVarName(key, utils);
|
|
440
|
+
const expr = schemaToZodExpr(
|
|
441
|
+
schema,
|
|
442
|
+
schemas,
|
|
443
|
+
schemaKeyToVarNameFn
|
|
444
|
+
);
|
|
445
|
+
return { expr, refs: [...refs] };
|
|
446
|
+
}
|
|
447
|
+
function buildEndpointZodContractsCode(params) {
|
|
448
|
+
const {
|
|
449
|
+
routeNameUsage,
|
|
450
|
+
inputParams,
|
|
451
|
+
responseDataTypeName,
|
|
452
|
+
contractsVarName,
|
|
453
|
+
utils,
|
|
454
|
+
componentsSchemas = null,
|
|
455
|
+
typeSuffix = "DC",
|
|
456
|
+
responseSchemaKey,
|
|
457
|
+
useExternalZodSchemas = false
|
|
458
|
+
} = params;
|
|
459
|
+
const _ = utils._;
|
|
460
|
+
const paramsSchemaName = `${_.camelCase(routeNameUsage)}ParamsSchema`;
|
|
461
|
+
const dataSchemaName = `${_.camelCase(routeNameUsage)}DataSchema`;
|
|
462
|
+
const allAuxiliaryKeys = /* @__PURE__ */ new Set();
|
|
463
|
+
const paramParts = [];
|
|
464
|
+
for (const p of inputParams) {
|
|
465
|
+
const { expr, refs: refKeys } = typeToZodSchemaWithSchema(
|
|
466
|
+
p.type,
|
|
467
|
+
componentsSchemas,
|
|
468
|
+
utils,
|
|
469
|
+
typeSuffix
|
|
470
|
+
);
|
|
471
|
+
for (const k of refKeys) allAuxiliaryKeys.add(k);
|
|
472
|
+
const schemaWithOptional = p.optional ? `${expr}.optional()` : expr;
|
|
473
|
+
paramParts.push(`${p.name}: ${schemaWithOptional}`);
|
|
474
|
+
}
|
|
475
|
+
const responseResult = responseSchemaKey && componentsSchemas && responseSchemaKey in componentsSchemas ? schemaKeyToZod(responseSchemaKey, componentsSchemas, utils) : typeToZodSchemaWithSchema(
|
|
476
|
+
responseDataTypeName,
|
|
477
|
+
componentsSchemas,
|
|
478
|
+
utils,
|
|
479
|
+
typeSuffix
|
|
480
|
+
);
|
|
481
|
+
const schemaKeyToVarNameFn = (key) => schemaKeyToVarName(key, utils);
|
|
482
|
+
const useDataSchemaFromCentral = useExternalZodSchemas && responseSchemaKey && componentsSchemas && responseSchemaKey in componentsSchemas;
|
|
483
|
+
if (useDataSchemaFromCentral) {
|
|
484
|
+
allAuxiliaryKeys.add(responseSchemaKey);
|
|
485
|
+
} else {
|
|
486
|
+
for (const k of responseResult.refs) allAuxiliaryKeys.add(k);
|
|
487
|
+
}
|
|
488
|
+
const zodSchemaImportNames = useExternalZodSchemas && allAuxiliaryKeys.size > 0 ? [...allAuxiliaryKeys].map(schemaKeyToVarNameFn) : [];
|
|
489
|
+
const allAuxiliary = useExternalZodSchemas ? [] : generateAuxiliarySchemas(
|
|
490
|
+
[...allAuxiliaryKeys],
|
|
491
|
+
componentsSchemas ?? {},
|
|
492
|
+
schemaKeyToVarNameFn,
|
|
493
|
+
/* @__PURE__ */ new Set()
|
|
494
|
+
);
|
|
495
|
+
const paramsFields = paramParts.join(",\n ");
|
|
496
|
+
const paramsSchemaCode = `export const ${paramsSchemaName} = z.object({
|
|
497
|
+
${paramsFields},
|
|
498
|
+
});`;
|
|
499
|
+
const dataSchemaCode = useDataSchemaFromCentral ? `export const ${dataSchemaName} = ${schemaKeyToVarNameFn(responseSchemaKey)};` : `export const ${dataSchemaName} = ${responseResult.expr};`;
|
|
500
|
+
const contractsCode = `export const ${contractsVarName} = {
|
|
501
|
+
params: ${paramsSchemaName},
|
|
502
|
+
data: ${dataSchemaName},
|
|
503
|
+
};`;
|
|
504
|
+
const auxiliaryBlock = allAuxiliary.length > 0 ? `${allAuxiliary.join("\n\n")}
|
|
505
|
+
|
|
506
|
+
` : "";
|
|
507
|
+
const content = `${auxiliaryBlock}${paramsSchemaCode}
|
|
508
|
+
|
|
509
|
+
${dataSchemaCode}
|
|
510
|
+
|
|
511
|
+
${contractsCode}`;
|
|
512
|
+
return { content, zodSchemaImportNames };
|
|
513
|
+
}
|
|
219
514
|
const formatGroupNameEnumKey = (groupName, { _ }) => _.upperFirst(_.camelCase(groupName));
|
|
220
515
|
const formatTagNameEnumKey = (tagName, utils) => formatGroupNameEnumKey(tagName, utils);
|
|
221
516
|
const metaInfoTmpl = async ({
|
|
@@ -367,8 +662,17 @@ const newEndpointTmpl = ({
|
|
|
367
662
|
groupName,
|
|
368
663
|
metaInfo,
|
|
369
664
|
filterTypes,
|
|
370
|
-
configuration
|
|
665
|
+
configuration,
|
|
666
|
+
zodContracts,
|
|
667
|
+
relativePathZodSchemas
|
|
668
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: codegen template, many branches by design
|
|
371
669
|
}) => {
|
|
670
|
+
const zodContractsIsObject = typeof zodContracts === "object" && zodContracts !== null;
|
|
671
|
+
const hasZodContracts = zodContracts === true || zodContractsIsObject;
|
|
672
|
+
const validateOpt = zodContractsIsObject ? zodContracts.validate : zodContracts === true ? true : void 0;
|
|
673
|
+
const throwOpt = zodContractsIsObject ? zodContracts.throw : void 0;
|
|
674
|
+
const validateOptObj = validateOpt != null && typeof validateOpt === "object" && !Array.isArray(validateOpt) ? validateOpt : null;
|
|
675
|
+
const throwOptObj = throwOpt != null && typeof throwOpt === "object" && !Array.isArray(throwOpt) ? throwOpt : null;
|
|
372
676
|
const { _ } = utils;
|
|
373
677
|
const positiveResponseTypes = route.raw.responsesTypes?.filter(
|
|
374
678
|
(it) => +it.status >= 200 && +it.status < 300 && (!it.typeData || filterTypes(it.typeData))
|
|
@@ -481,9 +785,95 @@ const newEndpointTmpl = ({
|
|
|
481
785
|
}`
|
|
482
786
|
});
|
|
483
787
|
const isAllowedInputType = filterTypes(requestInputTypeDc);
|
|
788
|
+
const defaultOkResponseType = positiveResponseTypes?.[0]?.type ?? "unknown";
|
|
789
|
+
const contractsVarName = hasZodContracts ? `${_.camelCase(route.routeName.usage)}Contracts` : null;
|
|
790
|
+
const swaggerSchema = configuration.config?.swaggerSchema ?? configuration?.swaggerSchema;
|
|
791
|
+
const componentsSchemas = swaggerSchema?.components?.schemas;
|
|
792
|
+
let operationFromSpec = null;
|
|
793
|
+
const pathKeyForSpec = path2?.startsWith("/") ? path2 : `/${path2 || ""}`;
|
|
794
|
+
const methodKey = method?.toLowerCase?.() ?? method;
|
|
795
|
+
if (pathKeyForSpec && methodKey && swaggerSchema?.paths?.[pathKeyForSpec]) {
|
|
796
|
+
operationFromSpec = swaggerSchema.paths[pathKeyForSpec][methodKey] ?? null;
|
|
797
|
+
}
|
|
798
|
+
if (!operationFromSpec && swaggerSchema?.paths && raw?.operationId) {
|
|
799
|
+
for (const pathItem of Object.values(swaggerSchema.paths)) {
|
|
800
|
+
const op = pathItem?.[methodKey];
|
|
801
|
+
if (op?.operationId === raw.operationId) {
|
|
802
|
+
operationFromSpec = op;
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
let responseSchemaKey = getResponseSchemaKeyFromOperation(
|
|
808
|
+
operationFromSpec ?? raw
|
|
809
|
+
);
|
|
810
|
+
if (!responseSchemaKey && componentsSchemas && configuration.modelTypes) {
|
|
811
|
+
const aliasType = configuration.modelTypes.find(
|
|
812
|
+
(m) => m.name === defaultOkResponseType
|
|
813
|
+
);
|
|
814
|
+
if (aliasType?.typeIdentifier === "type" && typeof aliasType.content === "string" && /^[A-Za-z0-9_]+$/.test(aliasType.content.trim())) {
|
|
815
|
+
const resolved = typeNameToSchemaKey(aliasType.content.trim(), "DC");
|
|
816
|
+
if (resolved in componentsSchemas) responseSchemaKey = resolved;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
if (!responseSchemaKey && componentsSchemas) {
|
|
820
|
+
const match = defaultOkResponseType.match(/^Get(.+)DataDC$/);
|
|
821
|
+
if (match) {
|
|
822
|
+
const candidate = match[1];
|
|
823
|
+
if (candidate in componentsSchemas) responseSchemaKey = candidate;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
const contractsCode = hasZodContracts && contractsVarName ? buildEndpointZodContractsCode({
|
|
827
|
+
routeNameUsage: route.routeName.usage,
|
|
828
|
+
inputParams,
|
|
829
|
+
responseDataTypeName: defaultOkResponseType,
|
|
830
|
+
contractsVarName,
|
|
831
|
+
utils,
|
|
832
|
+
componentsSchemas: componentsSchemas ?? void 0,
|
|
833
|
+
typeSuffix: "DC",
|
|
834
|
+
responseSchemaKey: responseSchemaKey ?? void 0,
|
|
835
|
+
useExternalZodSchemas: Boolean(relativePathZodSchemas)
|
|
836
|
+
}) : null;
|
|
837
|
+
const contractsLine = contractsVarName != null ? `contracts: ${contractsVarName},` : "";
|
|
838
|
+
const validateContractsLine = (() => {
|
|
839
|
+
if (validateOpt === void 0) return "";
|
|
840
|
+
if (typeof validateOpt === "string")
|
|
841
|
+
return `validateContracts: ${validateOpt},`;
|
|
842
|
+
if (typeof validateOpt === "boolean")
|
|
843
|
+
return `validateContracts: ${validateOpt},`;
|
|
844
|
+
if (validateOptObj !== null) {
|
|
845
|
+
const parts = [];
|
|
846
|
+
if (validateOptObj.params !== void 0)
|
|
847
|
+
parts.push(
|
|
848
|
+
`params: ${typeof validateOptObj.params === "string" ? validateOptObj.params : validateOptObj.params}`
|
|
849
|
+
);
|
|
850
|
+
if (validateOptObj.data !== void 0)
|
|
851
|
+
parts.push(
|
|
852
|
+
`data: ${typeof validateOptObj.data === "string" ? validateOptObj.data : validateOptObj.data}`
|
|
853
|
+
);
|
|
854
|
+
return parts.length > 0 ? `validateContracts: { ${parts.join(", ")} },` : "";
|
|
855
|
+
}
|
|
856
|
+
return "";
|
|
857
|
+
})();
|
|
858
|
+
const throwContractsLine = (() => {
|
|
859
|
+
if (throwOpt === void 0) return "";
|
|
860
|
+
if (typeof throwOpt === "string") return `throwContracts: ${throwOpt},`;
|
|
861
|
+
if (typeof throwOpt === "boolean") return `throwContracts: ${throwOpt},`;
|
|
862
|
+
if (throwOptObj !== null) {
|
|
863
|
+
const parts = [];
|
|
864
|
+
if (throwOptObj.params !== void 0)
|
|
865
|
+
parts.push(`params: ${throwOptObj.params}`);
|
|
866
|
+
if (throwOptObj.data !== void 0)
|
|
867
|
+
parts.push(`data: ${throwOptObj.data}`);
|
|
868
|
+
return parts.length > 0 ? `throwContracts: { ${parts.join(", ")} },` : "";
|
|
869
|
+
}
|
|
870
|
+
return "";
|
|
871
|
+
})();
|
|
484
872
|
return {
|
|
485
873
|
reservedDataContractNames,
|
|
486
874
|
localModelTypes: isAllowedInputType ? [requestInputTypeDc] : [],
|
|
875
|
+
contractsCode: contractsCode ?? void 0,
|
|
876
|
+
contractsVarName: contractsVarName ?? void 0,
|
|
487
877
|
content: `
|
|
488
878
|
new ${importFileParams.endpoint.exportName}<
|
|
489
879
|
${getHttpRequestGenerics()},
|
|
@@ -516,6 +906,9 @@ new ${importFileParams.endpoint.exportName}<
|
|
|
516
906
|
${groupName ? `group: ${metaInfo ? `Group.${formatGroupNameEnumKey(groupName, utils)}` : `"${groupName}"`},` : ""}
|
|
517
907
|
${metaInfo?.namespace ? `namespace,` : ""}
|
|
518
908
|
meta: ${requestInfoMeta?.tmplData ?? "{} as any"},
|
|
909
|
+
${contractsLine}
|
|
910
|
+
${validateContractsLine}
|
|
911
|
+
${throwContractsLine}
|
|
519
912
|
},
|
|
520
913
|
${importFileParams.queryClient.exportName},
|
|
521
914
|
${importFileParams.httpClient.exportName},
|
|
@@ -533,7 +926,8 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
533
926
|
utils,
|
|
534
927
|
relativePathDataContracts,
|
|
535
928
|
groupName,
|
|
536
|
-
metaInfo
|
|
929
|
+
metaInfo,
|
|
930
|
+
relativePathZodSchemas
|
|
537
931
|
} = params;
|
|
538
932
|
const { _ } = utils;
|
|
539
933
|
const dataContractNamesInThisFile = [];
|
|
@@ -545,7 +939,11 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
545
939
|
const newEndpointTemplates = routes.map((route) => {
|
|
546
940
|
const newEndpointTemplateData = newEndpointTmpl({
|
|
547
941
|
...params,
|
|
548
|
-
route
|
|
942
|
+
route,
|
|
943
|
+
groupName,
|
|
944
|
+
metaInfo,
|
|
945
|
+
zodContracts: codegenParams.zodContracts,
|
|
946
|
+
relativePathZodSchemas: relativePathZodSchemas ?? void 0
|
|
549
947
|
});
|
|
550
948
|
const { reservedDataContractNames } = newEndpointTemplateData;
|
|
551
949
|
reservedDataContractNames.forEach((reservedDataContractName) => {
|
|
@@ -556,12 +954,27 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
556
954
|
return { ...newEndpointTemplateData, route };
|
|
557
955
|
});
|
|
558
956
|
const extraImportLines = [];
|
|
957
|
+
const hasAnyZodContracts = newEndpointTemplates.some(
|
|
958
|
+
(t) => t.contractsCode != null
|
|
959
|
+
);
|
|
960
|
+
const allZodSchemaImportNames = /* @__PURE__ */ new Set();
|
|
961
|
+
newEndpointTemplates.forEach((t) => {
|
|
962
|
+
const c = t.contractsCode;
|
|
963
|
+
if (c != null && typeof c === "object" && c.zodSchemaImportNames?.length) {
|
|
964
|
+
for (const n of c.zodSchemaImportNames) {
|
|
965
|
+
allZodSchemaImportNames.add(n);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
const zodImportLine = hasAnyZodContracts ? 'import * as z from "zod";' : "";
|
|
970
|
+
const zodSchemasImportLine = allZodSchemaImportNames.size && relativePathZodSchemas ? `import { ${[...allZodSchemaImportNames].sort().join(", ")} } from "${relativePathZodSchemas}";` : "";
|
|
559
971
|
const endpointTemplates = await Promise.all(
|
|
560
972
|
newEndpointTemplates.map(
|
|
561
973
|
async ({
|
|
562
974
|
content: requestInfoInstanceContent,
|
|
563
975
|
localModelTypes,
|
|
564
|
-
route
|
|
976
|
+
route,
|
|
977
|
+
contractsCode
|
|
565
978
|
}) => {
|
|
566
979
|
const requestInfoMeta = codegenParams.getEndpointMeta?.(route, utils);
|
|
567
980
|
if (requestInfoMeta?.typeNameImportPath && requestInfoMeta.typeName) {
|
|
@@ -569,6 +982,12 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
569
982
|
`import { ${requestInfoMeta.typeName} } from "${requestInfoMeta.typeNameImportPath}";`
|
|
570
983
|
);
|
|
571
984
|
}
|
|
985
|
+
const contractsResult = contractsCode != null && typeof contractsCode === "object" ? contractsCode : null;
|
|
986
|
+
const contractsBlock = contractsResult != null ? `
|
|
987
|
+
|
|
988
|
+
${contractsResult.content}
|
|
989
|
+
|
|
990
|
+
` : "";
|
|
572
991
|
return `
|
|
573
992
|
${(await Promise.all(
|
|
574
993
|
localModelTypes.map(async (modelType) => {
|
|
@@ -580,7 +999,7 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
580
999
|
return contractType;
|
|
581
1000
|
})
|
|
582
1001
|
)).filter(Boolean).join("\n\n")}
|
|
583
|
-
|
|
1002
|
+
${contractsBlock}
|
|
584
1003
|
${endpointJSDocTmpl({
|
|
585
1004
|
...params,
|
|
586
1005
|
route
|
|
@@ -607,6 +1026,7 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
607
1026
|
import { ${importFileParams.httpClient.exportName} } from "${importFileParams.httpClient.path}";
|
|
608
1027
|
import { ${importFileParams.queryClient.exportName} } from "${importFileParams.queryClient.path}";
|
|
609
1028
|
${extraImportLines.join("\n")}
|
|
1029
|
+
${[zodImportLine, zodSchemasImportLine].filter(Boolean).join("\n")}
|
|
610
1030
|
${dataContractImportToken}
|
|
611
1031
|
|
|
612
1032
|
${(await Promise.all(
|
|
@@ -646,11 +1066,12 @@ const allEndpointPerFileTmpl = async (params) => {
|
|
|
646
1066
|
const allExportsTmpl = async ({
|
|
647
1067
|
collectedExportFiles,
|
|
648
1068
|
metaInfo,
|
|
649
|
-
formatTSContent
|
|
1069
|
+
formatTSContent,
|
|
1070
|
+
exportSchemas
|
|
650
1071
|
}) => {
|
|
651
1072
|
return await formatTSContent(`${LINTERS_IGNORE}
|
|
652
1073
|
export * from './data-contracts';
|
|
653
|
-
${collectedExportFiles.map((fileName) => `export * from './${fileName}';`).join("\n")}
|
|
1074
|
+
${exportSchemas ? " export * from './schemas';\n " : ""}${collectedExportFiles.map((fileName) => `export * from './${fileName}';`).join("\n")}
|
|
654
1075
|
${metaInfo ? 'export * from "./meta-info";' : ""}
|
|
655
1076
|
`);
|
|
656
1077
|
};
|
|
@@ -689,18 +1110,22 @@ const endpointPerFileTmpl = async (params) => {
|
|
|
689
1110
|
utils,
|
|
690
1111
|
relativePathDataContracts,
|
|
691
1112
|
groupName,
|
|
692
|
-
metaInfo
|
|
1113
|
+
metaInfo,
|
|
1114
|
+
relativePathZodSchemas
|
|
693
1115
|
} = params;
|
|
694
1116
|
const { _ } = utils;
|
|
695
1117
|
const {
|
|
696
1118
|
content: requestInfoInstanceContent,
|
|
697
1119
|
reservedDataContractNames,
|
|
698
|
-
localModelTypes
|
|
1120
|
+
localModelTypes,
|
|
1121
|
+
contractsCode
|
|
699
1122
|
} = newEndpointTmpl({
|
|
700
1123
|
...params,
|
|
701
1124
|
route,
|
|
702
1125
|
groupName,
|
|
703
|
-
metaInfo
|
|
1126
|
+
metaInfo,
|
|
1127
|
+
zodContracts: codegenParams.zodContracts,
|
|
1128
|
+
relativePathZodSchemas: relativePathZodSchemas ?? void 0
|
|
704
1129
|
});
|
|
705
1130
|
const dataContactNames = new Set(
|
|
706
1131
|
Object.keys(
|
|
@@ -726,6 +1151,15 @@ const endpointPerFileTmpl = async (params) => {
|
|
|
726
1151
|
);
|
|
727
1152
|
}
|
|
728
1153
|
const dataContractImportToken = "/*__DATA_CONTRACT_IMPORTS__*/";
|
|
1154
|
+
const contractsResult = contractsCode != null && typeof contractsCode === "object" ? contractsCode : null;
|
|
1155
|
+
const zodImportLine = contractsResult != null ? 'import * as z from "zod";' : "";
|
|
1156
|
+
const zodSchemasImportLine = contractsResult?.zodSchemaImportNames?.length && relativePathZodSchemas ? `import { ${contractsResult.zodSchemaImportNames.join(", ")} } from "${relativePathZodSchemas}";` : "";
|
|
1157
|
+
const contractsBlock = contractsResult != null ? `
|
|
1158
|
+
|
|
1159
|
+
${contractsResult.content}
|
|
1160
|
+
|
|
1161
|
+
` : "";
|
|
1162
|
+
const zodImportsBlock = [zodImportLine, zodSchemasImportLine].filter(Boolean).join("\n");
|
|
729
1163
|
const contentWithImportToken = await formatTSContent(`${LINTERS_IGNORE}
|
|
730
1164
|
import {
|
|
731
1165
|
RequestParams,
|
|
@@ -736,6 +1170,7 @@ const endpointPerFileTmpl = async (params) => {
|
|
|
736
1170
|
import { ${importFileParams.httpClient.exportName} } from "${importFileParams.httpClient.path}";
|
|
737
1171
|
import { ${importFileParams.queryClient.exportName} } from "${importFileParams.queryClient.path}";
|
|
738
1172
|
${extraImportLines.join("\n")}
|
|
1173
|
+
${zodImportsBlock}
|
|
739
1174
|
${dataContractImportToken}
|
|
740
1175
|
|
|
741
1176
|
${(await Promise.all(
|
|
@@ -765,7 +1200,7 @@ const endpointPerFileTmpl = async (params) => {
|
|
|
765
1200
|
return contractType;
|
|
766
1201
|
})
|
|
767
1202
|
)).filter(Boolean).join("\n\n")}
|
|
768
|
-
|
|
1203
|
+
${contractsBlock}
|
|
769
1204
|
${endpointJSDocTmpl({
|
|
770
1205
|
...params,
|
|
771
1206
|
route
|
|
@@ -813,7 +1248,7 @@ const unpackFilterOption = (option, argsToString, defaultReturnValue = true) =>
|
|
|
813
1248
|
const removeUnusedTypesItteration = async ({
|
|
814
1249
|
directory,
|
|
815
1250
|
keepTypes
|
|
816
|
-
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity:
|
|
1251
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: iterative AST traversal
|
|
817
1252
|
}) => {
|
|
818
1253
|
const project = new Project();
|
|
819
1254
|
project.addSourceFilesAtPaths([
|
|
@@ -1131,6 +1566,8 @@ const generateApi = async (params) => {
|
|
|
1131
1566
|
filterTypes
|
|
1132
1567
|
};
|
|
1133
1568
|
const reservedDataContractNamesMap = /* @__PURE__ */ new Map();
|
|
1569
|
+
const componentsSchemasForZod = generated.configuration.config?.swaggerSchema?.components?.schemas ?? generated.configuration.swaggerSchema?.components?.schemas;
|
|
1570
|
+
const hasZodSchemasFile = (params.zodContracts === true || typeof params.zodContracts === "object" && params.zodContracts != null) && componentsSchemasForZod && typeof componentsSchemasForZod === "object" && Object.keys(componentsSchemasForZod).length > 0;
|
|
1134
1571
|
const collectedExportFilesFromIndexFile = [];
|
|
1135
1572
|
const groupsMap = /* @__PURE__ */ new Map();
|
|
1136
1573
|
const nonEmptyGroups = /* @__PURE__ */ new Set();
|
|
@@ -1152,7 +1589,8 @@ const generateApi = async (params) => {
|
|
|
1152
1589
|
metaInfo: params.noMetaInfo ? null : {
|
|
1153
1590
|
groupNames: [],
|
|
1154
1591
|
namespace
|
|
1155
|
-
}
|
|
1592
|
+
},
|
|
1593
|
+
relativePathZodSchemas: hasZodSchemasFile ? "../schemas" : null
|
|
1156
1594
|
});
|
|
1157
1595
|
if (Array.isArray(route.raw.tags)) {
|
|
1158
1596
|
route.raw.tags.forEach((tag) => {
|
|
@@ -1196,7 +1634,8 @@ const generateApi = async (params) => {
|
|
|
1196
1634
|
metaInfo: params.noMetaInfo ? null : {
|
|
1197
1635
|
namespace,
|
|
1198
1636
|
groupNames: []
|
|
1199
|
-
}
|
|
1637
|
+
},
|
|
1638
|
+
relativePathZodSchemas: hasZodSchemasFile ? "./schemas" : null
|
|
1200
1639
|
});
|
|
1201
1640
|
reservedDataContractNames.forEach((name) => {
|
|
1202
1641
|
reservedDataContractNamesMap.set(
|
|
@@ -1392,6 +1831,22 @@ export * as ${exportGroupName} from './endpoints';
|
|
|
1392
1831
|
withPrefix: false,
|
|
1393
1832
|
content: dataContractsContent
|
|
1394
1833
|
});
|
|
1834
|
+
if (hasZodSchemasFile && componentsSchemasForZod) {
|
|
1835
|
+
const schemasTsContent = buildCentralZodSchemasFile({
|
|
1836
|
+
componentsSchemas: componentsSchemasForZod,
|
|
1837
|
+
utils
|
|
1838
|
+
});
|
|
1839
|
+
const formattedSchemasContent = await generated.formatTSContent(
|
|
1840
|
+
`${LINTERS_IGNORE}
|
|
1841
|
+
${schemasTsContent}`
|
|
1842
|
+
);
|
|
1843
|
+
codegenFs.createFile({
|
|
1844
|
+
path: paths.outputDir,
|
|
1845
|
+
fileName: "schemas.ts",
|
|
1846
|
+
withPrefix: false,
|
|
1847
|
+
content: formattedSchemasContent
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1395
1850
|
if (metaInfo) {
|
|
1396
1851
|
codegenFs.createFile({
|
|
1397
1852
|
path: paths.outputDir,
|
|
@@ -1411,7 +1866,8 @@ export * as ${exportGroupName} from './endpoints';
|
|
|
1411
1866
|
content: await allExportsTmpl({
|
|
1412
1867
|
...baseTmplParams,
|
|
1413
1868
|
collectedExportFiles: collectedExportFilesFromIndexFile,
|
|
1414
|
-
metaInfo
|
|
1869
|
+
metaInfo,
|
|
1870
|
+
exportSchemas: hasZodSchemasFile
|
|
1415
1871
|
})
|
|
1416
1872
|
});
|
|
1417
1873
|
if (shouldGenerateBarrelFiles) {
|
|
@@ -1433,7 +1889,8 @@ export * as ${namespace} from './__exports';
|
|
|
1433
1889
|
content: await allExportsTmpl({
|
|
1434
1890
|
...baseTmplParams,
|
|
1435
1891
|
collectedExportFiles: collectedExportFilesFromIndexFile,
|
|
1436
|
-
metaInfo
|
|
1892
|
+
metaInfo,
|
|
1893
|
+
exportSchemas: hasZodSchemasFile
|
|
1437
1894
|
})
|
|
1438
1895
|
});
|
|
1439
1896
|
}
|