@dudousxd/nestjs-codegen 0.12.0 → 0.13.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.
@@ -1,5 +1,5 @@
1
1
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/common';
2
- import { U as UserConfig } from '../index-CxkGbILp.cjs';
2
+ import { U as UserConfig } from '../index-D8RIMVpU.cjs';
3
3
  import 'ts-morph';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/common';
2
- import { U as UserConfig } from '../index-CxkGbILp.js';
2
+ import { U as UserConfig } from '../index-D8RIMVpU.js';
3
3
  import 'ts-morph';
4
4
 
5
5
  /**
@@ -1568,6 +1568,55 @@ function extractParamsType(method, sourceFile, project) {
1568
1568
  }
1569
1569
  return entries.length > 0 ? `{ ${entries.join("; ")} }` : null;
1570
1570
  }
1571
+ function extractUploadedFiles(method) {
1572
+ const FILE = "File | Blob";
1573
+ const entries = [];
1574
+ let multipart = false;
1575
+ const hasUploadedFileParam = method.getParameters().some(
1576
+ (p) => p.getDecorators().some((d) => {
1577
+ const name = d.getName();
1578
+ return name === "UploadedFile" || name === "UploadedFiles";
1579
+ })
1580
+ );
1581
+ for (const decorator of method.getDecorators()) {
1582
+ if (decorator.getName() !== "UseInterceptors") continue;
1583
+ for (const arg of decorator.getArguments()) {
1584
+ if (!Node5.isCallExpression(arg)) continue;
1585
+ const interceptor = arg.getExpression().getText();
1586
+ const callArgs = arg.getArguments();
1587
+ const firstArg2 = callArgs[0];
1588
+ if (interceptor === "FileInterceptor") {
1589
+ if (firstArg2 && Node5.isStringLiteral(firstArg2)) {
1590
+ entries.push(`${firstArg2.getLiteralValue()}: ${FILE}`);
1591
+ multipart = true;
1592
+ }
1593
+ } else if (interceptor === "FilesInterceptor") {
1594
+ if (firstArg2 && Node5.isStringLiteral(firstArg2)) {
1595
+ entries.push(`${firstArg2.getLiteralValue()}: Array<${FILE}>`);
1596
+ multipart = true;
1597
+ }
1598
+ } else if (interceptor === "FileFieldsInterceptor") {
1599
+ if (firstArg2 && Node5.isArrayLiteralExpression(firstArg2)) {
1600
+ for (const el of firstArg2.getElements()) {
1601
+ if (!Node5.isObjectLiteralExpression(el)) continue;
1602
+ const nameProp = el.getProperty("name");
1603
+ if (nameProp && Node5.isPropertyAssignment(nameProp)) {
1604
+ const init = nameProp.getInitializer();
1605
+ if (init && Node5.isStringLiteral(init)) {
1606
+ entries.push(`${init.getLiteralValue()}: Array<${FILE}>`);
1607
+ }
1608
+ }
1609
+ }
1610
+ multipart = true;
1611
+ }
1612
+ } else if (interceptor === "AnyFilesInterceptor") {
1613
+ multipart = true;
1614
+ }
1615
+ }
1616
+ }
1617
+ if (hasUploadedFileParam) multipart = true;
1618
+ return { fields: entries.length > 0 ? entries.join("; ") : null, multipart };
1619
+ }
1571
1620
  function extractResponseType(method, sourceFile, project) {
1572
1621
  const apiResponseDecorator = method.getDecorators().find((d) => d.getName() === "ApiResponse" && (apiResponseStatus(d) ?? 0) < 400);
1573
1622
  if (apiResponseDecorator) {
@@ -1702,6 +1751,8 @@ function extractDtoContract(method, sourceFile, project) {
1702
1751
  let body = extractBodyType(method, sourceFile, project);
1703
1752
  const filterInfo = extractApplyFilterInfo(method, sourceFile, project);
1704
1753
  const query = extractQueryType(method, sourceFile, project);
1754
+ const uploads = extractUploadedFiles(method);
1755
+ const multipartBody = uploads.fields ? `{ ${uploads.fields} }` : null;
1705
1756
  const streamElement = detectStreamElement(method);
1706
1757
  const isStream = streamElement !== null;
1707
1758
  if (filterInfo && filterInfo.source === "body") {
@@ -1711,7 +1762,7 @@ function extractDtoContract(method, sourceFile, project) {
1711
1762
  const paramsType = extractParamsType(method, sourceFile, project);
1712
1763
  const response = isStream ? resolveTypeNodeToString(streamElement, sourceFile, project, 3) : extractResponseType(method, sourceFile, project);
1713
1764
  const errorInfo = extractErrorType(method, sourceFile, project);
1714
- if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream) {
1765
+ if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart) {
1715
1766
  return null;
1716
1767
  }
1717
1768
  let bodyRef = null;
@@ -1784,7 +1835,9 @@ function extractDtoContract(method, sourceFile, project) {
1784
1835
  formWarnings,
1785
1836
  bodySchema,
1786
1837
  querySchema,
1787
- stream: isStream
1838
+ stream: isStream,
1839
+ multipart: uploads.multipart,
1840
+ multipartBody
1788
1841
  };
1789
1842
  }
1790
1843
  function resolveParamClass(method, decoratorName, sourceFile, project) {
@@ -2251,7 +2304,9 @@ function extractDtoRoute(args) {
2251
2304
  formWarnings: dtoContract?.formWarnings ?? [],
2252
2305
  bodySchema: dtoContract?.bodySchema ?? null,
2253
2306
  querySchema: dtoContract?.querySchema ?? null,
2254
- stream: dtoContract?.stream ?? false
2307
+ stream: dtoContract?.stream ?? false,
2308
+ multipart: dtoContract?.multipart ?? false,
2309
+ multipartBody: dtoContract?.multipartBody ?? null
2255
2310
  }
2256
2311
  });
2257
2312
  }
@@ -2862,7 +2917,15 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
2862
2917
  const isFilterQuery = c.contractSource.filterSource === "query" && !!c.contractSource.filterFields?.length;
2863
2918
  const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : isFilterQuery ? emitFilterQueryType(c) : c.contractSource.query ?? "never";
2864
2919
  const bodyRef = c.contractSource.bodyRef;
2865
- const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
2920
+ let body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
2921
+ const multipartBody = c.contractSource.multipartBody;
2922
+ if (c.contractSource.multipart && multipartBody) {
2923
+ if (body === "never") {
2924
+ body = multipartBody;
2925
+ } else if (!bodyAcceptsAnything(body)) {
2926
+ body = `(${body}) & ${multipartBody}`;
2927
+ }
2928
+ }
2866
2929
  const response = buildResponseType(c, outDir, serialization);
2867
2930
  const error = buildErrorType(c);
2868
2931
  const params = buildParamsType(c.params);
@@ -2881,6 +2944,25 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
2881
2944
  }
2882
2945
  return lines;
2883
2946
  }
2947
+ function topLevelUnionArms(type) {
2948
+ const arms = [];
2949
+ let depth = 0;
2950
+ let start = 0;
2951
+ for (let i = 0; i < type.length; i++) {
2952
+ const ch = type[i];
2953
+ if (ch === "{" || ch === "[" || ch === "<" || ch === "(") depth++;
2954
+ else if (ch === "}" || ch === "]" || ch === ">" || ch === ")") depth--;
2955
+ else if (ch === "|" && depth === 0) {
2956
+ arms.push(type.slice(start, i).trim());
2957
+ start = i + 1;
2958
+ }
2959
+ }
2960
+ arms.push(type.slice(start).trim());
2961
+ return arms;
2962
+ }
2963
+ function bodyAcceptsAnything(body) {
2964
+ return topLevelUnionArms(body).some((arm) => arm === "unknown" || arm === "any");
2965
+ }
2884
2966
  function buildRequestModel(c) {
2885
2967
  const m = c.method.toLowerCase();
2886
2968
  const flat = JSON.stringify(c.name);
@@ -2897,6 +2979,7 @@ function buildRequestModel(c) {
2897
2979
  const optsParts = [];
2898
2980
  if (hasQuery) optsParts.push("query: input?.query as Record<string, unknown> | undefined");
2899
2981
  if (hasBody) optsParts.push("body: input?.body");
2982
+ if (hasBody && c.contractSource.multipart) optsParts.push("multipart: true");
2900
2983
  const optsExpr = optsParts.length ? `{ ${optsParts.join(", ")} }` : "{}";
2901
2984
  return {
2902
2985
  routeName: c.name,
@@ -4243,7 +4326,7 @@ async function acquireLock(outDir) {
4243
4326
  }
4244
4327
 
4245
4328
  // src/index.ts
4246
- var VERSION = "0.12.0";
4329
+ var VERSION = "0.13.1";
4247
4330
 
4248
4331
  // src/generate-manifest.ts
4249
4332
  var MANIFEST_FILE = ".codegen-manifest.json";