adorn-api 1.0.19 → 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 +537 -25
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +537 -25
- package/dist/cli.js.map +1 -1
- package/dist/compiler/schema/objectHandler.d.ts +40 -0
- package/dist/compiler/schema/objectHandler.d.ts.map +1 -1
- package/dist/compiler/schema/openapi.d.ts.map +1 -1
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts +43 -0
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts.map +1 -0
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts +13 -0
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts.map +1 -0
- package/dist/compiler/schema/types.d.ts +1 -0
- package/dist/compiler/schema/types.d.ts.map +1 -1
- package/dist/metal/applyListQuery.d.ts +1 -1
- package/dist/metal/applyListQuery.d.ts.map +1 -1
- package/dist/metal/index.cjs.map +1 -1
- package/dist/metal/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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 (!
|
|
1797
|
-
const propName =
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
2863
|
+
typescript: import_typescript13.default.version
|
|
2352
2864
|
},
|
|
2353
2865
|
project: {
|
|
2354
2866
|
tsconfigPath: params.tsconfigAbs,
|
|
@@ -2868,7 +3380,7 @@ function partitionSchemas(schemas, graph, schemaGraph, config = {}) {
|
|
|
2868
3380
|
complexity: totalComplexity,
|
|
2869
3381
|
dependencies: []
|
|
2870
3382
|
}];
|
|
2871
|
-
recommendation = recommendation || "Single file mode (--
|
|
3383
|
+
recommendation = recommendation || "Single file mode (--split not specified)";
|
|
2872
3384
|
} else if (strategy === "controller") {
|
|
2873
3385
|
groups = partitionByController(schemas, graph, finalConfig);
|
|
2874
3386
|
} else if (strategy === "dependency") {
|
|
@@ -3101,7 +3613,7 @@ function getEdgesByRelation(graph, relation) {
|
|
|
3101
3613
|
}
|
|
3102
3614
|
|
|
3103
3615
|
// src/compiler/graph/builder.ts
|
|
3104
|
-
var
|
|
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
|
|
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(
|
|
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}`;
|
|
@@ -3523,7 +4035,7 @@ async function buildCommand(args) {
|
|
|
3523
4035
|
const validationMode = validationModeIndex !== -1 ? args[validationModeIndex + 1] : "ajv-runtime";
|
|
3524
4036
|
const verbose = args.includes("--verbose");
|
|
3525
4037
|
const quiet = args.includes("--quiet");
|
|
3526
|
-
const
|
|
4038
|
+
const split = args.includes("--split");
|
|
3527
4039
|
const splitStrategyIndex = args.indexOf("--split-strategy");
|
|
3528
4040
|
const splitStrategy = splitStrategyIndex !== -1 ? args[splitStrategyIndex + 1] : void 0;
|
|
3529
4041
|
const splitThresholdIndex = args.indexOf("--split-threshold");
|
|
@@ -3543,7 +4055,7 @@ async function buildCommand(args) {
|
|
|
3543
4055
|
outDir: outputDir,
|
|
3544
4056
|
project: projectPath,
|
|
3545
4057
|
adornVersion: ADORN_VERSION,
|
|
3546
|
-
typescriptVersion:
|
|
4058
|
+
typescriptVersion: import_typescript15.default.version
|
|
3547
4059
|
});
|
|
3548
4060
|
if (!stale.stale) {
|
|
3549
4061
|
progress.completePhase("staleness-check");
|
|
@@ -3601,7 +4113,7 @@ async function buildCommand(args) {
|
|
|
3601
4113
|
if (!quiet) openapiSpinner.stop();
|
|
3602
4114
|
const schemaCount = Object.keys(openapi.components?.schemas || {}).length;
|
|
3603
4115
|
let splitEnabled = false;
|
|
3604
|
-
if (
|
|
4116
|
+
if (split && schemaCount >= splitThreshold) {
|
|
3605
4117
|
progress.verboseLog(`Schema count (${schemaCount}) >= threshold (${splitThreshold}), analyzing for auto-split...`);
|
|
3606
4118
|
const graph = buildControllerGraph(controllers);
|
|
3607
4119
|
const schemaGraph = new SchemaGraph(graph);
|
|
@@ -3641,9 +4153,9 @@ async function buildCommand(args) {
|
|
|
3641
4153
|
log(` Auto-split not needed: ${partitioning.recommendation}`);
|
|
3642
4154
|
}
|
|
3643
4155
|
}
|
|
3644
|
-
} else if (
|
|
4156
|
+
} else if (!split) {
|
|
3645
4157
|
if (!quiet) {
|
|
3646
|
-
log(` Splitting disabled (--
|
|
4158
|
+
log(` Splitting disabled (--split not specified)`);
|
|
3647
4159
|
}
|
|
3648
4160
|
} else {
|
|
3649
4161
|
if (!quiet) {
|
|
@@ -3764,12 +4276,12 @@ Commands:
|
|
|
3764
4276
|
build Generate OpenAPI and manifest from TypeScript source
|
|
3765
4277
|
clean Remove generated artifacts
|
|
3766
4278
|
|
|
3767
|
-
Options:
|
|
4279
|
+
Options:
|
|
3768
4280
|
-p <path> Path to tsconfig.json (default: ./tsconfig.json)
|
|
3769
4281
|
--output <dir> Output directory (default: .adorn)
|
|
3770
4282
|
--if-stale Only rebuild if artifacts are stale
|
|
3771
4283
|
--validation-mode <mode> Validation mode: none, ajv-runtime, precompiled (default: ajv-runtime)
|
|
3772
|
-
--
|
|
4284
|
+
--split Enable automatic schema splitting (default: disabled)
|
|
3773
4285
|
--split-strategy <mode> Override splitting strategy: controller, dependency, size, auto (default: auto)
|
|
3774
4286
|
--split-threshold <num> Schema count threshold for auto-split (default: 50)
|
|
3775
4287
|
--verbose Show detailed progress information
|
|
@@ -3780,7 +4292,7 @@ Examples:
|
|
|
3780
4292
|
adorn-api build --if-stale
|
|
3781
4293
|
adorn-api build --validation-mode precompiled
|
|
3782
4294
|
adorn-api build --verbose
|
|
3783
|
-
adorn-api build --
|
|
4295
|
+
adorn-api build --split # Enable split mode
|
|
3784
4296
|
adorn-api build --split-strategy controller # Force controller-based splitting
|
|
3785
4297
|
adorn-api build --split-threshold 100 # Increase threshold to 100
|
|
3786
4298
|
adorn-api clean
|