adorn-api 1.0.20 → 1.0.21

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.cjs CHANGED
@@ -323,7 +323,7 @@ function unwrapPromiseTypeNode(typeNode) {
323
323
  }
324
324
 
325
325
  // src/compiler/schema/openapi.ts
326
- var import_typescript9 = __toESM(require("typescript"), 1);
326
+ var import_typescript11 = __toESM(require("typescript"), 1);
327
327
 
328
328
  // src/compiler/schema/typeToJsonSchema.ts
329
329
  var import_typescript7 = __toESM(require("typescript"), 1);
@@ -718,6 +718,48 @@ function getExplicitTypeNameFromNode3(typeNode) {
718
718
 
719
719
  // src/compiler/schema/objectHandler.ts
720
720
  var import_typescript6 = __toESM(require("typescript"), 1);
721
+ function getTypeParameterName(type) {
722
+ if (type.flags & import_typescript6.default.TypeFlags.TypeParameter) {
723
+ const typeParam = type;
724
+ return typeParam.symbol?.getName() ?? null;
725
+ }
726
+ return null;
727
+ }
728
+ function getTypeArguments(type) {
729
+ const typeRef = type;
730
+ const args = typeRef.typeArguments;
731
+ if (!args) return void 0;
732
+ return Array.from(args);
733
+ }
734
+ function createTypeParameterSubstitutions(type, typeNode, checker) {
735
+ const typeArgs = getTypeArguments(type);
736
+ if (!typeArgs || typeArgs.length === 0) {
737
+ return void 0;
738
+ }
739
+ if (!typeNode || !import_typescript6.default.isTypeReferenceNode(typeNode)) {
740
+ return void 0;
741
+ }
742
+ const typeParams = typeNode.typeArguments;
743
+ if (!typeParams || typeParams.length !== typeArgs.length) {
744
+ return void 0;
745
+ }
746
+ const substitutions = /* @__PURE__ */ new Map();
747
+ for (let i = 0; i < typeParams.length; i++) {
748
+ const typeParamNode = typeParams[i];
749
+ const typeArg = typeArgs[i];
750
+ if (import_typescript6.default.isIdentifier(typeParamNode)) {
751
+ substitutions.set(typeParamNode.text, typeArg);
752
+ }
753
+ }
754
+ return substitutions.size > 0 ? substitutions : void 0;
755
+ }
756
+ function resolveTypeParameter(type, substitutions, _checker) {
757
+ if (!substitutions) return null;
758
+ const paramName = getTypeParameterName(type);
759
+ if (!paramName) return null;
760
+ const resolved = substitutions.get(paramName);
761
+ return resolved ?? null;
762
+ }
721
763
  function handleObjectType(type, ctx, typeNode) {
722
764
  const { checker, components, typeStack } = ctx;
723
765
  const symbol = type.getSymbol();
@@ -737,7 +779,9 @@ function handleObjectType(type, ctx, typeNode) {
737
779
  }
738
780
  typeStack.add(type);
739
781
  }
740
- const schema = buildObjectSchema(type, ctx, typeNode);
782
+ const typeParamSubstitutions = createTypeParameterSubstitutions(type, typeNode, checker);
783
+ const buildCtx = typeParamSubstitutions ? { ...ctx, typeParameterSubstitutions: typeParamSubstitutions } : ctx;
784
+ const schema = buildObjectSchema(type, buildCtx, typeNode);
741
785
  if (typeName && typeName !== "__type") {
742
786
  typeStack.delete(type);
743
787
  const existing = components.get(typeName);
@@ -755,7 +799,7 @@ function handleObjectType(type, ctx, typeNode) {
755
799
  return schema;
756
800
  }
757
801
  function buildObjectSchema(type, ctx, _typeNode) {
758
- const { checker, mode } = ctx;
802
+ const { checker, mode, typeParameterSubstitutions } = ctx;
759
803
  const properties = {};
760
804
  const required = [];
761
805
  const props = checker.getPropertiesOfType(type);
@@ -764,10 +808,14 @@ function buildObjectSchema(type, ctx, _typeNode) {
764
808
  if (isIteratorOrSymbolProperty(propName)) {
765
809
  continue;
766
810
  }
767
- const propType = checker.getTypeOfSymbol(prop);
811
+ let propType = checker.getTypeOfSymbol(prop);
768
812
  if (isMethodLike(propType)) {
769
813
  continue;
770
814
  }
815
+ const resolvedType = resolveTypeParameter(propType, typeParameterSubstitutions, checker);
816
+ if (resolvedType) {
817
+ propType = resolvedType;
818
+ }
771
819
  const isOptional = !!(prop.flags & import_typescript6.default.SymbolFlags.Optional);
772
820
  const isRelation = isMetalOrmWrapperType(propType, checker);
773
821
  const propCtx = { ...ctx, propertyName: propName };
@@ -787,7 +835,8 @@ function buildObjectSchema(type, ctx, _typeNode) {
787
835
  if (isRecordType(type, checker)) {
788
836
  const valueType = getRecordValueType(type, checker);
789
837
  if (valueType) {
790
- schema.additionalProperties = typeToJsonSchema(valueType, ctx);
838
+ const resolvedValueType = resolveTypeParameter(valueType, typeParameterSubstitutions, checker);
839
+ schema.additionalProperties = typeToJsonSchema(resolvedValueType ?? valueType, ctx);
791
840
  }
792
841
  }
793
842
  return schema;
@@ -1579,6 +1628,376 @@ function resolveAndCollectObjectProps(schema, components) {
1579
1628
  return { properties, required };
1580
1629
  }
1581
1630
 
1631
+ // src/compiler/schema/queryBuilderAnalyzer.ts
1632
+ var import_typescript9 = __toESM(require("typescript"), 1);
1633
+ function analyzeQueryBuilderForSchema(methodDeclaration, checker, options = {}) {
1634
+ const body = methodDeclaration.body;
1635
+ if (!body) {
1636
+ return null;
1637
+ }
1638
+ const trackedSchema = analyzeWithVariableTracking(body, checker, options);
1639
+ if (trackedSchema) {
1640
+ return trackedSchema;
1641
+ }
1642
+ const returnStatement = findReturnStatement(body);
1643
+ if (!returnStatement) {
1644
+ return null;
1645
+ }
1646
+ const callChain = analyzeReturnExpression(returnStatement.expression);
1647
+ if (!callChain) {
1648
+ return null;
1649
+ }
1650
+ return parseQueryBuilderChain(callChain, checker, options);
1651
+ }
1652
+ function analyzeWithVariableTracking(body, checker, options) {
1653
+ let queryBuilderVar = null;
1654
+ let entityName = null;
1655
+ const selectedFields = /* @__PURE__ */ new Set();
1656
+ const includes = {};
1657
+ let isPaged = false;
1658
+ let hasReturn = false;
1659
+ for (const statement of body.statements) {
1660
+ if (import_typescript9.default.isReturnStatement(statement)) {
1661
+ hasReturn = true;
1662
+ const returnExpr = statement.expression;
1663
+ if (returnExpr && import_typescript9.default.isCallExpression(returnExpr)) {
1664
+ const callExpr = returnExpr;
1665
+ if (import_typescript9.default.isIdentifier(callExpr.expression) && queryBuilderVar) {
1666
+ const varName = callExpr.expression.text;
1667
+ if (varName === queryBuilderVar) {
1668
+ const methodName = callExpr.expression.text;
1669
+ if (methodName === "executePaged") {
1670
+ isPaged = true;
1671
+ }
1672
+ }
1673
+ }
1674
+ if (import_typescript9.default.isPropertyAccessExpression(callExpr.expression) && queryBuilderVar) {
1675
+ const propAccess = callExpr.expression;
1676
+ if (import_typescript9.default.isIdentifier(propAccess.expression) && propAccess.expression.text === queryBuilderVar) {
1677
+ const methodName = propAccess.name.text;
1678
+ if (methodName === "executePaged") {
1679
+ isPaged = true;
1680
+ }
1681
+ }
1682
+ }
1683
+ }
1684
+ continue;
1685
+ }
1686
+ if (!import_typescript9.default.isExpressionStatement(statement)) {
1687
+ if (import_typescript9.default.isVariableStatement(statement)) {
1688
+ for (const declaration of statement.declarationList.declarations) {
1689
+ if (!import_typescript9.default.isIdentifier(declaration.name)) continue;
1690
+ const varName = declaration.name.text;
1691
+ const initializer = declaration.initializer;
1692
+ if (!initializer || !import_typescript9.default.isCallExpression(initializer)) continue;
1693
+ const opInfo = extractChainedOperation(initializer);
1694
+ if (opInfo && (opInfo.operation === "selectFromEntity" || opInfo.operation === "selectFrom")) {
1695
+ queryBuilderVar = varName;
1696
+ if (opInfo.entityName) {
1697
+ entityName = opInfo.entityName;
1698
+ }
1699
+ }
1700
+ }
1701
+ }
1702
+ continue;
1703
+ }
1704
+ const expr = statement.expression;
1705
+ if (import_typescript9.default.isBinaryExpression(expr) && expr.operatorToken.kind === import_typescript9.default.SyntaxKind.EqualsToken) {
1706
+ if (!import_typescript9.default.isIdentifier(expr.left)) {
1707
+ continue;
1708
+ }
1709
+ const varName = expr.left.text;
1710
+ const rightSide = expr.right;
1711
+ if (import_typescript9.default.isCallExpression(rightSide)) {
1712
+ const opInfo = extractChainedOperation(rightSide);
1713
+ if (opInfo) {
1714
+ if (opInfo.operation === "selectFromEntity" || opInfo.operation === "selectFrom") {
1715
+ queryBuilderVar = varName;
1716
+ if (opInfo.entityName) {
1717
+ entityName = opInfo.entityName;
1718
+ }
1719
+ }
1720
+ if ((opInfo.operation === "select" || opInfo.operation === "include") && queryBuilderVar === varName) {
1721
+ if (opInfo.operation === "select") {
1722
+ for (const field of opInfo.fields || []) {
1723
+ selectedFields.add(field);
1724
+ }
1725
+ } else if (opInfo.operation === "include" && opInfo.includeArg) {
1726
+ const parsedIncludes = parseIncludeObjectLiteral(opInfo.includeArg);
1727
+ if (parsedIncludes) {
1728
+ for (const [relName, relSchema] of Object.entries(parsedIncludes)) {
1729
+ includes[relName] = relSchema;
1730
+ }
1731
+ }
1732
+ }
1733
+ }
1734
+ }
1735
+ }
1736
+ }
1737
+ }
1738
+ if (!hasReturn || !queryBuilderVar || !entityName) {
1739
+ return null;
1740
+ }
1741
+ return {
1742
+ entityName,
1743
+ selectedFields: Array.from(selectedFields),
1744
+ includes,
1745
+ isPaged
1746
+ };
1747
+ }
1748
+ function extractChainedOperation(callExpr) {
1749
+ if (import_typescript9.default.isIdentifier(callExpr.expression)) {
1750
+ const methodName2 = callExpr.expression.text;
1751
+ if (methodName2 === "selectFromEntity" || methodName2 === "selectFrom") {
1752
+ const entityArg = callExpr.arguments[0];
1753
+ let entityName = null;
1754
+ if (import_typescript9.default.isIdentifier(entityArg)) {
1755
+ entityName = entityArg.text;
1756
+ } else if (import_typescript9.default.isPropertyAccessExpression(entityArg)) {
1757
+ entityName = entityArg.name.text;
1758
+ }
1759
+ return {
1760
+ operation: methodName2 === "selectFromEntity" ? "selectFromEntity" : "selectFrom",
1761
+ fields: null,
1762
+ includeArg: null,
1763
+ entityName
1764
+ };
1765
+ }
1766
+ }
1767
+ if (!import_typescript9.default.isPropertyAccessExpression(callExpr.expression)) {
1768
+ return null;
1769
+ }
1770
+ const propAccess = callExpr.expression;
1771
+ const methodName = propAccess.name.text;
1772
+ if (methodName === "select") {
1773
+ const fields = [];
1774
+ for (const arg of callExpr.arguments) {
1775
+ if (import_typescript9.default.isStringLiteral(arg)) {
1776
+ fields.push(arg.text);
1777
+ }
1778
+ }
1779
+ return {
1780
+ operation: "select",
1781
+ fields,
1782
+ includeArg: null,
1783
+ entityName: null
1784
+ };
1785
+ }
1786
+ if (methodName === "include") {
1787
+ return {
1788
+ operation: "include",
1789
+ fields: null,
1790
+ includeArg: callExpr.arguments[0] || null,
1791
+ entityName: null
1792
+ };
1793
+ }
1794
+ return null;
1795
+ }
1796
+ function parseIncludeObjectLiteral(arg) {
1797
+ if (!import_typescript9.default.isObjectLiteralExpression(arg)) {
1798
+ return null;
1799
+ }
1800
+ const includes = {};
1801
+ for (const prop of arg.properties) {
1802
+ if (!import_typescript9.default.isPropertyAssignment(prop) || !import_typescript9.default.isIdentifier(prop.name)) {
1803
+ continue;
1804
+ }
1805
+ const relationName = prop.name.text;
1806
+ const value = prop.initializer;
1807
+ if (value.kind === import_typescript9.default.SyntaxKind.TrueKeyword) {
1808
+ includes[relationName] = true;
1809
+ } else if (import_typescript9.default.isObjectLiteralExpression(value)) {
1810
+ const nestedSchema = parseNestedInclude(value, 0);
1811
+ if (nestedSchema) {
1812
+ includes[relationName] = nestedSchema;
1813
+ }
1814
+ }
1815
+ }
1816
+ return includes;
1817
+ }
1818
+ function parseNestedInclude(obj, depth) {
1819
+ const selectedFields = [];
1820
+ const includes = {};
1821
+ for (const prop of obj.properties) {
1822
+ if (!import_typescript9.default.isPropertyAssignment(prop) || !import_typescript9.default.isIdentifier(prop.name)) {
1823
+ continue;
1824
+ }
1825
+ const propName = prop.name.text;
1826
+ const value = prop.initializer;
1827
+ if (propName === "select" && import_typescript9.default.isArrayLiteralExpression(value)) {
1828
+ for (const element of value.elements) {
1829
+ if (import_typescript9.default.isStringLiteral(element)) {
1830
+ selectedFields.push(element.text);
1831
+ }
1832
+ }
1833
+ } else if (propName === "include" && import_typescript9.default.isObjectLiteralExpression(value)) {
1834
+ const nestedIncludes = parseIncludeObjectLiteral(value);
1835
+ if (nestedIncludes) {
1836
+ for (const [relName, relSchema] of Object.entries(nestedIncludes)) {
1837
+ includes[relName] = relSchema;
1838
+ }
1839
+ }
1840
+ }
1841
+ }
1842
+ return {
1843
+ entityName: "",
1844
+ selectedFields,
1845
+ includes,
1846
+ isPaged: false
1847
+ };
1848
+ }
1849
+ function getMethodName(expression) {
1850
+ if (import_typescript9.default.isIdentifier(expression)) {
1851
+ return expression.text;
1852
+ }
1853
+ if (import_typescript9.default.isPropertyAccessExpression(expression)) {
1854
+ return expression.name.text;
1855
+ }
1856
+ return null;
1857
+ }
1858
+ function findReturnStatement(body) {
1859
+ let returnStatement = null;
1860
+ for (const statement of body.statements) {
1861
+ if (import_typescript9.default.isReturnStatement(statement)) {
1862
+ if (returnStatement !== null) {
1863
+ return null;
1864
+ }
1865
+ returnStatement = statement;
1866
+ }
1867
+ }
1868
+ return returnStatement;
1869
+ }
1870
+ function analyzeReturnExpression(expression) {
1871
+ if (!expression) {
1872
+ return null;
1873
+ }
1874
+ if (import_typescript9.default.isCallExpression(expression)) {
1875
+ return buildCallChain(expression, null);
1876
+ }
1877
+ return null;
1878
+ }
1879
+ function buildCallChain(node, parent) {
1880
+ if (import_typescript9.default.isCallExpression(node)) {
1881
+ const callNode = {
1882
+ expression: node.expression,
1883
+ methodName: getMethodName(node.expression),
1884
+ arguments: node.arguments,
1885
+ parent
1886
+ };
1887
+ if (import_typescript9.default.isPropertyAccessExpression(node.expression)) {
1888
+ return buildCallChain(node.expression.expression, callNode);
1889
+ }
1890
+ return callNode;
1891
+ }
1892
+ return parent;
1893
+ }
1894
+ function parseQueryBuilderChain(chain, checker, options) {
1895
+ if (!chain) {
1896
+ return null;
1897
+ }
1898
+ const rootNode = findSelectFromEntityCall(chain);
1899
+ if (!rootNode) {
1900
+ return null;
1901
+ }
1902
+ const entityName = extractEntityName(rootNode, checker);
1903
+ if (!entityName) {
1904
+ return null;
1905
+ }
1906
+ const selectedFields = /* @__PURE__ */ new Set();
1907
+ const includes = {};
1908
+ let isPaged = false;
1909
+ let currentNode = chain;
1910
+ while (currentNode) {
1911
+ const methodName = currentNode.methodName;
1912
+ if (methodName === "select") {
1913
+ for (const arg of currentNode.arguments) {
1914
+ if (import_typescript9.default.isStringLiteral(arg)) {
1915
+ selectedFields.add(arg.text);
1916
+ }
1917
+ }
1918
+ } else if (methodName === "include") {
1919
+ parseIncludeArgument(currentNode.arguments[0], includes, checker, options, 0);
1920
+ } else if (methodName === "executePaged") {
1921
+ isPaged = true;
1922
+ }
1923
+ currentNode = currentNode.parent;
1924
+ }
1925
+ return {
1926
+ entityName,
1927
+ selectedFields: Array.from(selectedFields),
1928
+ includes,
1929
+ isPaged
1930
+ };
1931
+ }
1932
+ function findSelectFromEntityCall(chain) {
1933
+ let currentNode = chain;
1934
+ let lastNode = null;
1935
+ while (currentNode) {
1936
+ if (currentNode.methodName === "selectFromEntity" || currentNode.methodName === "selectFrom") {
1937
+ return currentNode;
1938
+ }
1939
+ lastNode = currentNode;
1940
+ currentNode = currentNode.parent;
1941
+ }
1942
+ return lastNode;
1943
+ }
1944
+ function extractEntityName(callNode, checker) {
1945
+ if (callNode.arguments.length === 0) {
1946
+ return null;
1947
+ }
1948
+ const entityArg = callNode.arguments[0];
1949
+ if (import_typescript9.default.isIdentifier(entityArg)) {
1950
+ return entityArg.text;
1951
+ }
1952
+ if (import_typescript9.default.isPropertyAccessExpression(entityArg)) {
1953
+ return entityArg.name.text;
1954
+ }
1955
+ return null;
1956
+ }
1957
+ function parseIncludeArgument(arg, includes, checker, options, depth) {
1958
+ if (!arg) {
1959
+ return;
1960
+ }
1961
+ if (import_typescript9.default.isObjectLiteralExpression(arg)) {
1962
+ for (const prop of arg.properties) {
1963
+ if (!import_typescript9.default.isPropertyAssignment(prop) || !import_typescript9.default.isIdentifier(prop.name)) {
1964
+ continue;
1965
+ }
1966
+ const relationName = prop.name.text;
1967
+ const value = prop.initializer;
1968
+ if (value.kind === import_typescript9.default.SyntaxKind.TrueKeyword) {
1969
+ includes[relationName] = true;
1970
+ } else if (import_typescript9.default.isObjectLiteralExpression(value)) {
1971
+ const maxDepth = options.maxDepth ?? 5;
1972
+ if (depth < maxDepth) {
1973
+ const nestedSchema = parseNestedInclude(value, depth + 1);
1974
+ if (nestedSchema) {
1975
+ includes[relationName] = nestedSchema;
1976
+ }
1977
+ }
1978
+ }
1979
+ }
1980
+ }
1981
+ }
1982
+
1983
+ // src/compiler/schema/queryBuilderSchemaBuilder.ts
1984
+ var import_typescript10 = require("typescript");
1985
+ function wrapInPaginatedResult(schema) {
1986
+ return {
1987
+ type: "object",
1988
+ properties: {
1989
+ items: {
1990
+ type: "array",
1991
+ items: schema
1992
+ },
1993
+ page: { type: "integer" },
1994
+ pageSize: { type: "integer" },
1995
+ totalItems: { type: "integer" }
1996
+ },
1997
+ required: ["items", "page", "pageSize", "totalItems"]
1998
+ };
1999
+ }
2000
+
1582
2001
  // src/compiler/schema/openapi.ts
1583
2002
  var METAL_ORM_WRAPPER_NAMES2 = ["BelongsToReference", "HasOneReference", "HasManyCollection", "ManyToManyCollection"];
1584
2003
  function generateOpenAPI(controllers, checker, options = {}) {
@@ -1733,6 +2152,88 @@ function convertToOpenApiPath(basePath, path4) {
1733
2152
  }
1734
2153
  return fullPath;
1735
2154
  }
2155
+ function tryInferQueryBuilderSchema(operation, checker) {
2156
+ return analyzeQueryBuilderForSchema(operation.methodDeclaration, checker) ?? null;
2157
+ }
2158
+ function getEntityTypeFromReturnType(operation, checker) {
2159
+ const returnType = operation.returnType;
2160
+ const unwrapPromise2 = (type) => {
2161
+ const symbol2 = type.getSymbol();
2162
+ if (symbol2?.getName() === "Promise") {
2163
+ const typeArgs = type.typeArguments;
2164
+ if (typeArgs && typeArgs.length > 0) {
2165
+ return typeArgs[0];
2166
+ }
2167
+ }
2168
+ return type;
2169
+ };
2170
+ const innerType = unwrapPromise2(returnType);
2171
+ const symbol = innerType.getSymbol();
2172
+ if (symbol?.getName() === "PaginatedResult") {
2173
+ const typeArgs = innerType.typeArguments;
2174
+ if (typeArgs && typeArgs.length > 0) {
2175
+ return typeArgs[0];
2176
+ }
2177
+ }
2178
+ return null;
2179
+ }
2180
+ function filterSchemaByQueryBuilder(querySchema, operation, ctx) {
2181
+ const entityType = getEntityTypeFromReturnType(operation, ctx.checker);
2182
+ if (!entityType) {
2183
+ return {};
2184
+ }
2185
+ const entitySchema = typeToJsonSchema(entityType, ctx);
2186
+ let baseSchema = entitySchema;
2187
+ if (entitySchema.$ref && entitySchema.$ref.startsWith("#/components/schemas/")) {
2188
+ const schemaName = entitySchema.$ref.replace("#/components/schemas/", "");
2189
+ const componentSchema = ctx.components.get(schemaName);
2190
+ if (componentSchema) {
2191
+ baseSchema = componentSchema;
2192
+ }
2193
+ }
2194
+ if (!baseSchema.properties || Object.keys(baseSchema.properties).length === 0) {
2195
+ return {};
2196
+ }
2197
+ const filteredSchema = buildFilteredSchema(querySchema, baseSchema);
2198
+ if (querySchema.isPaged) {
2199
+ return wrapInPaginatedResult(filteredSchema);
2200
+ }
2201
+ return filteredSchema;
2202
+ }
2203
+ function buildFilteredSchema(querySchema, entitySchema) {
2204
+ const properties = {};
2205
+ const required = [];
2206
+ for (const field of querySchema.selectedFields) {
2207
+ if (entitySchema.properties?.[field]) {
2208
+ properties[field] = entitySchema.properties[field];
2209
+ if (entitySchema.required && entitySchema.required.includes(field)) {
2210
+ required.push(field);
2211
+ }
2212
+ }
2213
+ }
2214
+ for (const [relationName, includeSpec] of Object.entries(querySchema.includes)) {
2215
+ if (entitySchema.properties?.[relationName]) {
2216
+ properties[relationName] = {
2217
+ type: "object",
2218
+ properties: {
2219
+ id: { type: "integer" }
2220
+ },
2221
+ required: ["id"]
2222
+ };
2223
+ if (entitySchema.required && entitySchema.required.includes(relationName)) {
2224
+ required.push(relationName);
2225
+ }
2226
+ }
2227
+ }
2228
+ const schema = {
2229
+ type: "object",
2230
+ properties
2231
+ };
2232
+ if (required.length > 0) {
2233
+ schema.required = required;
2234
+ }
2235
+ return schema;
2236
+ }
1736
2237
  function buildOperation(operation, ctx, controllerConsumes) {
1737
2238
  const op = {
1738
2239
  operationId: operation.operationId,
@@ -1747,7 +2248,18 @@ function buildOperation(operation, ctx, controllerConsumes) {
1747
2248
  op.parameters = parameters;
1748
2249
  }
1749
2250
  const responseCtx = { ...ctx, mode: "response" };
1750
- const responseSchema = typeToJsonSchema(operation.returnType, responseCtx, operation.returnTypeNode);
2251
+ let responseSchema;
2252
+ const querySchema = tryInferQueryBuilderSchema(operation, ctx.checker);
2253
+ if (querySchema) {
2254
+ const entityType = getEntityTypeFromReturnType(operation, ctx.checker);
2255
+ if (entityType) {
2256
+ responseSchema = filterSchemaByQueryBuilder(querySchema, operation, responseCtx);
2257
+ } else {
2258
+ responseSchema = typeToJsonSchema(operation.returnType, responseCtx, operation.returnTypeNode);
2259
+ }
2260
+ } else {
2261
+ responseSchema = typeToJsonSchema(operation.returnType, responseCtx, operation.returnTypeNode);
2262
+ }
1751
2263
  const status = operation.httpMethod === "POST" ? 201 : 200;
1752
2264
  op.responses[status] = {
1753
2265
  description: status === 201 ? "Created" : "OK",
@@ -1789,12 +2301,12 @@ function mergeBodySchemaAnnotations(bodyParam, ctx, schema) {
1789
2301
  const declarations = typeSymbol.getDeclarations();
1790
2302
  if (!declarations || declarations.length === 0) return schema;
1791
2303
  const classDecl = declarations[0];
1792
- if (!import_typescript9.default.isClassDeclaration(classDecl)) return schema;
2304
+ if (!import_typescript11.default.isClassDeclaration(classDecl)) return schema;
1793
2305
  const result = { ...schema };
1794
2306
  const props = { ...result.properties };
1795
2307
  for (const member of classDecl.members) {
1796
- if (!import_typescript9.default.isPropertyDeclaration(member) || !member.name) continue;
1797
- const propName = import_typescript9.default.isIdentifier(member.name) ? member.name.text : null;
2308
+ if (!import_typescript11.default.isPropertyDeclaration(member) || !member.name) continue;
2309
+ const propName = import_typescript11.default.isIdentifier(member.name) ? member.name.text : null;
1798
2310
  if (!propName) continue;
1799
2311
  if (!props[propName]) continue;
1800
2312
  const frags = extractPropertySchemaFragments(ctx.checker, member);
@@ -1807,7 +2319,7 @@ function mergeBodySchemaAnnotations(bodyParam, ctx, schema) {
1807
2319
  }
1808
2320
 
1809
2321
  // src/compiler/manifest/emit.ts
1810
- var import_typescript10 = __toESM(require("typescript"), 1);
2322
+ var import_typescript12 = __toESM(require("typescript"), 1);
1811
2323
  function generateManifest(controllers, checker, version, validationMode = "ajv-runtime") {
1812
2324
  const components = /* @__PURE__ */ new Map();
1813
2325
  const ctx = {
@@ -1829,7 +2341,7 @@ function generateManifest(controllers, checker, version, validationMode = "ajv-r
1829
2341
  generator: {
1830
2342
  name: "adorn-api",
1831
2343
  version,
1832
- typescript: import_typescript10.default.version
2344
+ typescript: import_typescript12.default.version
1833
2345
  },
1834
2346
  schemas: {
1835
2347
  kind: "openapi-3.1",
@@ -2315,7 +2827,7 @@ async function isStale(params) {
2315
2827
  // src/compiler/cache/writeCache.ts
2316
2828
  var import_node_fs4 = __toESM(require("fs"), 1);
2317
2829
  var import_node_path4 = __toESM(require("path"), 1);
2318
- var import_typescript11 = __toESM(require("typescript"), 1);
2830
+ var import_typescript13 = __toESM(require("typescript"), 1);
2319
2831
  function statMtimeMs2(p) {
2320
2832
  return import_node_fs4.default.statSync(p).mtimeMs;
2321
2833
  }
@@ -2348,7 +2860,7 @@ function writeCache(params) {
2348
2860
  generator: {
2349
2861
  name: "adorn-api",
2350
2862
  version: params.adornVersion,
2351
- typescript: import_typescript11.default.version
2863
+ typescript: import_typescript13.default.version
2352
2864
  },
2353
2865
  project: {
2354
2866
  tsconfigPath: params.tsconfigAbs,
@@ -3101,7 +3613,7 @@ function getEdgesByRelation(graph, relation) {
3101
3613
  }
3102
3614
 
3103
3615
  // src/compiler/graph/builder.ts
3104
- var import_typescript12 = __toESM(require("typescript"), 1);
3616
+ var import_typescript14 = __toESM(require("typescript"), 1);
3105
3617
 
3106
3618
  // src/compiler/graph/schemaGraph.ts
3107
3619
  var SchemaGraph = class {
@@ -3353,7 +3865,7 @@ var SchemaGraph = class {
3353
3865
  };
3354
3866
 
3355
3867
  // src/cli.ts
3356
- var import_typescript13 = __toESM(require("typescript"), 1);
3868
+ var import_typescript15 = __toESM(require("typescript"), 1);
3357
3869
  var import_node_process2 = __toESM(require("process"), 1);
3358
3870
  var import_meta2 = {};
3359
3871
  var ADORN_VERSION = (() => {
@@ -3432,7 +3944,7 @@ function sanitizeForJson(obj) {
3432
3944
  return result;
3433
3945
  }
3434
3946
  function buildControllerGraph(controllers) {
3435
- const graph = createGraph(import_typescript13.default.version);
3947
+ const graph = createGraph(import_typescript15.default.version);
3436
3948
  const nodeMap = /* @__PURE__ */ new Map();
3437
3949
  for (const ctrl of controllers) {
3438
3950
  const nodeId = `Controller:${ctrl.className}`;
@@ -3543,7 +4055,7 @@ async function buildCommand(args) {
3543
4055
  outDir: outputDir,
3544
4056
  project: projectPath,
3545
4057
  adornVersion: ADORN_VERSION,
3546
- typescriptVersion: import_typescript13.default.version
4058
+ typescriptVersion: import_typescript15.default.version
3547
4059
  });
3548
4060
  if (!stale.stale) {
3549
4061
  progress.completePhase("staleness-check");