@lark-apaas/fullstack-cli 1.1.6-alpha.10 → 1.1.6-alpha.11
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/index.js +385 -299
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import
|
|
2
|
+
import fs14 from "fs";
|
|
3
3
|
import path14 from "path";
|
|
4
4
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5
5
|
import { config as dotenvConfig } from "dotenv";
|
|
@@ -1385,39 +1385,55 @@ import path9 from "path";
|
|
|
1385
1385
|
var DEFAULT_PLUGIN_VERSION = "1.0.0";
|
|
1386
1386
|
var PLUGIN_MAPPING = {
|
|
1387
1387
|
// 飞书相关
|
|
1388
|
-
"
|
|
1389
|
-
|
|
1390
|
-
pluginVersion: "1.0.0"
|
|
1388
|
+
"@official-plugins/send-feishu-message": {
|
|
1389
|
+
sourceActionID: "official_feishu/send_message",
|
|
1390
|
+
pluginVersion: "1.0.0",
|
|
1391
|
+
actionName: "send_feishu_message"
|
|
1391
1392
|
},
|
|
1392
|
-
"
|
|
1393
|
-
|
|
1394
|
-
pluginVersion: "1.0.0"
|
|
1393
|
+
"@official-plugins/feishu-group-create": {
|
|
1394
|
+
sourceActionID: "official_feishu/create_group",
|
|
1395
|
+
pluginVersion: "1.0.0",
|
|
1396
|
+
actionName: "createGroup"
|
|
1395
1397
|
},
|
|
1396
1398
|
// AI 相关
|
|
1397
|
-
"
|
|
1398
|
-
|
|
1399
|
-
pluginVersion: "1.0.0"
|
|
1399
|
+
"@official-plugins/ai-text-generate": {
|
|
1400
|
+
sourceActionID: "official_ai/text_generate",
|
|
1401
|
+
pluginVersion: "1.0.0",
|
|
1402
|
+
actionName: "text_generate"
|
|
1400
1403
|
},
|
|
1401
|
-
"
|
|
1402
|
-
|
|
1403
|
-
pluginVersion: "1.0.0"
|
|
1404
|
+
"@official-plugins/ai-image-understanding": {
|
|
1405
|
+
sourceActionID: "official_ai/image_understanding",
|
|
1406
|
+
pluginVersion: "1.0.0",
|
|
1407
|
+
actionName: "imageUnderstanding"
|
|
1404
1408
|
},
|
|
1405
|
-
"
|
|
1406
|
-
|
|
1407
|
-
pluginVersion: "1.0.0"
|
|
1409
|
+
"@official-plugins/ai-text-to-image": {
|
|
1410
|
+
sourceActionID: "official_ai/image_generate",
|
|
1411
|
+
pluginVersion: "1.0.0",
|
|
1412
|
+
actionName: "textToImage"
|
|
1408
1413
|
}
|
|
1409
1414
|
};
|
|
1410
|
-
function
|
|
1411
|
-
const item
|
|
1415
|
+
function getPluginInfoBySourceActionID(sourceActionID) {
|
|
1416
|
+
for (const [pluginKey, item] of Object.entries(PLUGIN_MAPPING)) {
|
|
1417
|
+
if (item.sourceActionID === sourceActionID) {
|
|
1418
|
+
return {
|
|
1419
|
+
pluginKey,
|
|
1420
|
+
pluginVersion: item.pluginVersion ?? DEFAULT_PLUGIN_VERSION,
|
|
1421
|
+
actionName: item.actionName
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
throw new Error(
|
|
1426
|
+
`Unknown sourceActionID: "${sourceActionID}". This sourceActionID is not in the built-in mapping. Please contact the developer to add it.`
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
function getActionNameByPluginKey(pluginKey) {
|
|
1430
|
+
const item = PLUGIN_MAPPING[pluginKey];
|
|
1412
1431
|
if (!item) {
|
|
1413
1432
|
throw new Error(
|
|
1414
|
-
`Unknown
|
|
1433
|
+
`Unknown pluginKey: "${pluginKey}". This pluginKey is not in the built-in mapping. Please contact the developer to add it.`
|
|
1415
1434
|
);
|
|
1416
1435
|
}
|
|
1417
|
-
return
|
|
1418
|
-
pluginKey: item.pluginKey,
|
|
1419
|
-
pluginVersion: item.pluginVersion ?? DEFAULT_PLUGIN_VERSION
|
|
1420
|
-
};
|
|
1436
|
+
return item.actionName;
|
|
1421
1437
|
}
|
|
1422
1438
|
|
|
1423
1439
|
// src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/capabilities/send-feishu-message.ts
|
|
@@ -1536,7 +1552,7 @@ function transformFormValue(sourceActionID, actionInput) {
|
|
|
1536
1552
|
|
|
1537
1553
|
// src/commands/migration/versions/v001_capability/json-migrator/transformer.ts
|
|
1538
1554
|
function transformCapability(old) {
|
|
1539
|
-
const { pluginKey, pluginVersion } =
|
|
1555
|
+
const { pluginKey, pluginVersion } = getPluginInfoBySourceActionID(old.sourceActionID);
|
|
1540
1556
|
const formValue = transformFormValue(old.sourceActionID, old.actionInput);
|
|
1541
1557
|
return {
|
|
1542
1558
|
id: old.id,
|
|
@@ -1555,15 +1571,39 @@ function transformCapabilities(oldCapabilities) {
|
|
|
1555
1571
|
}
|
|
1556
1572
|
|
|
1557
1573
|
// src/commands/migration/versions/v001_capability/json-migrator/index.ts
|
|
1574
|
+
function loadExistingCapabilities() {
|
|
1575
|
+
const capabilitiesDir = getCapabilitiesDir2();
|
|
1576
|
+
if (!fs9.existsSync(capabilitiesDir)) {
|
|
1577
|
+
return [];
|
|
1578
|
+
}
|
|
1579
|
+
const files = fs9.readdirSync(capabilitiesDir);
|
|
1580
|
+
const capabilities = [];
|
|
1581
|
+
for (const file of files) {
|
|
1582
|
+
if (file === "capabilities.json" || !file.endsWith(".json")) {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
try {
|
|
1586
|
+
const filePath = path9.join(capabilitiesDir, file);
|
|
1587
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
1588
|
+
const capability = JSON.parse(content);
|
|
1589
|
+
if (capability.id && capability.pluginKey) {
|
|
1590
|
+
capabilities.push(capability);
|
|
1591
|
+
}
|
|
1592
|
+
} catch {
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
return capabilities;
|
|
1596
|
+
}
|
|
1558
1597
|
async function migrateJsonFiles(options) {
|
|
1559
1598
|
const detection = detectJsonMigration();
|
|
1560
1599
|
if (!detection.needsMigration) {
|
|
1600
|
+
const existingCapabilities = loadExistingCapabilities();
|
|
1561
1601
|
return {
|
|
1562
1602
|
success: true,
|
|
1563
1603
|
skipped: true,
|
|
1564
1604
|
reason: detection.reason,
|
|
1565
|
-
count:
|
|
1566
|
-
capabilities:
|
|
1605
|
+
count: existingCapabilities.length,
|
|
1606
|
+
capabilities: existingCapabilities
|
|
1567
1607
|
};
|
|
1568
1608
|
}
|
|
1569
1609
|
const { oldCapabilities, oldFilePath } = detection;
|
|
@@ -1695,9 +1735,8 @@ async function installPlugins(capabilities, options) {
|
|
|
1695
1735
|
}
|
|
1696
1736
|
|
|
1697
1737
|
// src/commands/migration/versions/v001_capability/code-migrator/index.ts
|
|
1698
|
-
import fs12 from "fs";
|
|
1699
1738
|
import path11 from "path";
|
|
1700
|
-
import
|
|
1739
|
+
import { Project } from "ts-morph";
|
|
1701
1740
|
|
|
1702
1741
|
// src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
|
|
1703
1742
|
import fs11 from "fs";
|
|
@@ -1750,177 +1789,153 @@ function scanFilesToMigrate() {
|
|
|
1750
1789
|
}
|
|
1751
1790
|
|
|
1752
1791
|
// src/commands/migration/versions/v001_capability/code-migrator/analyzers/import-analyzer.ts
|
|
1753
|
-
import * as ts from "typescript";
|
|
1754
1792
|
function extractCapabilityId(importPath) {
|
|
1755
1793
|
const match = importPath.match(/capabilities\/([^/]+)$/);
|
|
1756
|
-
|
|
1757
|
-
return match[1];
|
|
1758
|
-
}
|
|
1759
|
-
return null;
|
|
1794
|
+
return match ? match[1] : null;
|
|
1760
1795
|
}
|
|
1761
1796
|
function isCapabilityImport(importPath) {
|
|
1762
1797
|
return importPath.includes("capabilities/") || importPath.includes("capabilities\\");
|
|
1763
1798
|
}
|
|
1764
1799
|
function analyzeImports(sourceFile) {
|
|
1765
1800
|
const imports = [];
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1801
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
1802
|
+
for (const importDecl of importDeclarations) {
|
|
1803
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
1804
|
+
if (!isCapabilityImport(moduleSpecifier)) {
|
|
1805
|
+
continue;
|
|
1806
|
+
}
|
|
1807
|
+
const capabilityId = extractCapabilityId(moduleSpecifier);
|
|
1808
|
+
if (!capabilityId) {
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
const namedImports = importDecl.getNamedImports();
|
|
1812
|
+
for (const namedImport of namedImports) {
|
|
1813
|
+
const importName = namedImport.getAliasNode()?.getText() || namedImport.getName();
|
|
1814
|
+
imports.push({
|
|
1815
|
+
importName,
|
|
1816
|
+
capabilityId,
|
|
1817
|
+
start: importDecl.getStart(),
|
|
1818
|
+
end: importDecl.getEnd(),
|
|
1819
|
+
text: importDecl.getText()
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
const namespaceImport = importDecl.getNamespaceImport();
|
|
1823
|
+
if (namespaceImport) {
|
|
1824
|
+
imports.push({
|
|
1825
|
+
importName: namespaceImport.getText(),
|
|
1826
|
+
capabilityId,
|
|
1827
|
+
start: importDecl.getStart(),
|
|
1828
|
+
end: importDecl.getEnd(),
|
|
1829
|
+
text: importDecl.getText()
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
const defaultImport = importDecl.getDefaultImport();
|
|
1833
|
+
if (defaultImport) {
|
|
1834
|
+
imports.push({
|
|
1835
|
+
importName: defaultImport.getText(),
|
|
1836
|
+
capabilityId,
|
|
1837
|
+
start: importDecl.getStart(),
|
|
1838
|
+
end: importDecl.getEnd(),
|
|
1839
|
+
text: importDecl.getText()
|
|
1840
|
+
});
|
|
1809
1841
|
}
|
|
1810
|
-
ts.forEachChild(node, visit);
|
|
1811
1842
|
}
|
|
1812
|
-
visit(sourceFile);
|
|
1813
1843
|
return imports;
|
|
1814
1844
|
}
|
|
1815
1845
|
|
|
1816
1846
|
// src/commands/migration/versions/v001_capability/code-migrator/analyzers/call-site-analyzer.ts
|
|
1817
|
-
import
|
|
1847
|
+
import { SyntaxKind } from "ts-morph";
|
|
1818
1848
|
function analyzeCallSites(sourceFile, imports) {
|
|
1819
1849
|
const callSites = [];
|
|
1820
1850
|
const importMap = /* @__PURE__ */ new Map();
|
|
1821
1851
|
for (const imp of imports) {
|
|
1822
1852
|
importMap.set(imp.importName, imp.capabilityId);
|
|
1823
1853
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
const
|
|
1844
|
-
if (
|
|
1845
|
-
const
|
|
1854
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
1855
|
+
for (const callExpr of callExpressions) {
|
|
1856
|
+
const expression = callExpr.getExpression();
|
|
1857
|
+
if (expression.getKind() === SyntaxKind.Identifier) {
|
|
1858
|
+
const functionName = expression.getText();
|
|
1859
|
+
const capabilityId = importMap.get(functionName);
|
|
1860
|
+
if (capabilityId) {
|
|
1861
|
+
callSites.push({
|
|
1862
|
+
functionName,
|
|
1863
|
+
capabilityId,
|
|
1864
|
+
start: callExpr.getStart(),
|
|
1865
|
+
end: callExpr.getEnd(),
|
|
1866
|
+
line: callExpr.getStartLineNumber(),
|
|
1867
|
+
text: callExpr.getText()
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
} else if (expression.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
1871
|
+
const propAccess = expression.asKind(SyntaxKind.PropertyAccessExpression);
|
|
1872
|
+
if (propAccess) {
|
|
1873
|
+
const objectExpr = propAccess.getExpression();
|
|
1874
|
+
if (objectExpr.getKind() === SyntaxKind.Identifier) {
|
|
1875
|
+
const objectName = objectExpr.getText();
|
|
1876
|
+
const capabilityId = importMap.get(objectName);
|
|
1846
1877
|
if (capabilityId) {
|
|
1847
|
-
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
1848
1878
|
callSites.push({
|
|
1849
|
-
functionName: `${objectName
|
|
1879
|
+
functionName: `${objectName}.${propAccess.getName()}`,
|
|
1850
1880
|
capabilityId,
|
|
1851
|
-
start:
|
|
1852
|
-
end:
|
|
1853
|
-
line:
|
|
1854
|
-
text:
|
|
1881
|
+
start: callExpr.getStart(),
|
|
1882
|
+
end: callExpr.getEnd(),
|
|
1883
|
+
line: callExpr.getStartLineNumber(),
|
|
1884
|
+
text: callExpr.getText()
|
|
1855
1885
|
});
|
|
1856
1886
|
}
|
|
1857
1887
|
}
|
|
1858
1888
|
}
|
|
1859
1889
|
}
|
|
1860
|
-
ts2.forEachChild(node, visit);
|
|
1861
1890
|
}
|
|
1862
|
-
visit(sourceFile);
|
|
1863
1891
|
return callSites;
|
|
1864
1892
|
}
|
|
1865
1893
|
|
|
1866
1894
|
// src/commands/migration/versions/v001_capability/code-migrator/analyzers/class-analyzer.ts
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
const decorators = ts3.getDecorators(node);
|
|
1870
|
-
if (!decorators) {
|
|
1871
|
-
return false;
|
|
1872
|
-
}
|
|
1895
|
+
function hasDecorator(classDecl, decoratorName) {
|
|
1896
|
+
const decorators = classDecl.getDecorators();
|
|
1873
1897
|
return decorators.some((decorator) => {
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
return expression.text === decoratorName;
|
|
1877
|
-
}
|
|
1878
|
-
if (ts3.isCallExpression(expression) && ts3.isIdentifier(expression.expression)) {
|
|
1879
|
-
return expression.expression.text === decoratorName;
|
|
1880
|
-
}
|
|
1881
|
-
return false;
|
|
1898
|
+
const name = decorator.getName();
|
|
1899
|
+
return name === decoratorName;
|
|
1882
1900
|
});
|
|
1883
1901
|
}
|
|
1884
1902
|
function analyzeClass(sourceFile) {
|
|
1903
|
+
const classes = sourceFile.getClasses();
|
|
1885
1904
|
let classInfo;
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
break;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
if (isInjectable || isController || !classInfo) {
|
|
1918
|
-
classInfo = info;
|
|
1905
|
+
for (const classDecl of classes) {
|
|
1906
|
+
const name = classDecl.getName();
|
|
1907
|
+
if (!name) continue;
|
|
1908
|
+
const isInjectable = hasDecorator(classDecl, "Injectable");
|
|
1909
|
+
const isController = hasDecorator(classDecl, "Controller");
|
|
1910
|
+
if (classInfo && classInfo.isInjectable && !isInjectable && !isController) {
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
const info = {
|
|
1914
|
+
name,
|
|
1915
|
+
isInjectable,
|
|
1916
|
+
isController,
|
|
1917
|
+
constructorParamCount: 0
|
|
1918
|
+
};
|
|
1919
|
+
const classBody = classDecl.getChildSyntaxListOrThrow();
|
|
1920
|
+
info.classBodyStart = classBody.getStart();
|
|
1921
|
+
const constructors = classDecl.getConstructors();
|
|
1922
|
+
if (constructors.length > 0) {
|
|
1923
|
+
const ctor = constructors[0];
|
|
1924
|
+
info.constructorParamCount = ctor.getParameters().length;
|
|
1925
|
+
info.constructorStart = ctor.getStart();
|
|
1926
|
+
info.constructorEnd = ctor.getEnd();
|
|
1927
|
+
const params = ctor.getParameters();
|
|
1928
|
+
if (params.length > 0) {
|
|
1929
|
+
const lastParam = params[params.length - 1];
|
|
1930
|
+
info.constructorParamsEnd = lastParam.getEnd();
|
|
1931
|
+
} else {
|
|
1932
|
+
info.constructorParamsEnd = ctor.getStart();
|
|
1919
1933
|
}
|
|
1920
1934
|
}
|
|
1921
|
-
|
|
1935
|
+
if (isInjectable || isController || !classInfo) {
|
|
1936
|
+
classInfo = info;
|
|
1937
|
+
}
|
|
1922
1938
|
}
|
|
1923
|
-
visit(sourceFile);
|
|
1924
1939
|
return classInfo;
|
|
1925
1940
|
}
|
|
1926
1941
|
function canAutoMigrate(classInfo) {
|
|
@@ -1940,128 +1955,203 @@ function canAutoMigrate(classInfo) {
|
|
|
1940
1955
|
}
|
|
1941
1956
|
|
|
1942
1957
|
// src/commands/migration/versions/v001_capability/code-migrator/transformers/import-transformer.ts
|
|
1943
|
-
var
|
|
1944
|
-
var
|
|
1945
|
-
function hasCapabilityServiceImport(
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
for (const imp of sortedImports) {
|
|
1967
|
-
const before = result.substring(0, imp.start);
|
|
1968
|
-
const after = result.substring(imp.end);
|
|
1969
|
-
const trimmedAfter = after.replace(/^\r?\n/, "");
|
|
1970
|
-
result = before + trimmedAfter;
|
|
1958
|
+
var CORE_MODULE = "@lark-apaas/fullstack-nestjs-core";
|
|
1959
|
+
var NESTJS_COMMON_MODULE = "@nestjs/common";
|
|
1960
|
+
function hasCapabilityServiceImport(sourceFile) {
|
|
1961
|
+
const imports = sourceFile.getImportDeclarations();
|
|
1962
|
+
for (const importDecl of imports) {
|
|
1963
|
+
if (importDecl.getModuleSpecifierValue() === CORE_MODULE) {
|
|
1964
|
+
const namedImports = importDecl.getNamedImports();
|
|
1965
|
+
if (namedImports.some((ni) => ni.getName() === "CapabilityService")) {
|
|
1966
|
+
return true;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
return false;
|
|
1971
|
+
}
|
|
1972
|
+
function hasInjectImport(sourceFile) {
|
|
1973
|
+
const imports = sourceFile.getImportDeclarations();
|
|
1974
|
+
for (const importDecl of imports) {
|
|
1975
|
+
if (importDecl.getModuleSpecifierValue() === NESTJS_COMMON_MODULE) {
|
|
1976
|
+
const namedImports = importDecl.getNamedImports();
|
|
1977
|
+
if (namedImports.some((ni) => ni.getName() === "Inject")) {
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1971
1981
|
}
|
|
1982
|
+
return false;
|
|
1983
|
+
}
|
|
1984
|
+
function transformImports(sourceFile, capabilityImports) {
|
|
1972
1985
|
let importAdded = false;
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1986
|
+
let importsRemoved = 0;
|
|
1987
|
+
const importPaths = new Set(capabilityImports.map((imp) => {
|
|
1988
|
+
const match = imp.text.match(/from\s+['"]([^'"]+)['"]/);
|
|
1989
|
+
return match ? match[1] : "";
|
|
1990
|
+
}));
|
|
1991
|
+
const importDeclarations = sourceFile.getImportDeclarations();
|
|
1992
|
+
for (const importDecl of importDeclarations) {
|
|
1993
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
1994
|
+
if (importPaths.has(moduleSpecifier)) {
|
|
1995
|
+
importDecl.remove();
|
|
1996
|
+
importsRemoved++;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
if (!hasCapabilityServiceImport(sourceFile)) {
|
|
2000
|
+
const existingCoreImport = sourceFile.getImportDeclaration(CORE_MODULE);
|
|
2001
|
+
if (existingCoreImport) {
|
|
2002
|
+
const namedImports = existingCoreImport.getNamedImports();
|
|
2003
|
+
const existingNames = namedImports.map((ni) => ni.getName());
|
|
2004
|
+
if (!existingNames.includes("CapabilityService")) {
|
|
2005
|
+
existingCoreImport.addNamedImport("CapabilityService");
|
|
2006
|
+
}
|
|
2007
|
+
if (!existingNames.includes("migrationAdaptor")) {
|
|
2008
|
+
existingCoreImport.addNamedImport("migrationAdaptor");
|
|
2009
|
+
}
|
|
1977
2010
|
} else {
|
|
1978
|
-
|
|
2011
|
+
sourceFile.addImportDeclaration({
|
|
2012
|
+
moduleSpecifier: CORE_MODULE,
|
|
2013
|
+
namedImports: ["CapabilityService", "migrationAdaptor"]
|
|
2014
|
+
});
|
|
1979
2015
|
}
|
|
1980
2016
|
importAdded = true;
|
|
1981
2017
|
}
|
|
1982
|
-
if (!hasInjectImport(
|
|
1983
|
-
const
|
|
1984
|
-
if (
|
|
1985
|
-
|
|
2018
|
+
if (!hasInjectImport(sourceFile)) {
|
|
2019
|
+
const existingNestImport = sourceFile.getImportDeclaration(NESTJS_COMMON_MODULE);
|
|
2020
|
+
if (existingNestImport) {
|
|
2021
|
+
const namedImports = existingNestImport.getNamedImports();
|
|
2022
|
+
const existingNames = namedImports.map((ni) => ni.getName());
|
|
2023
|
+
if (!existingNames.includes("Inject")) {
|
|
2024
|
+
existingNestImport.addNamedImport("Inject");
|
|
2025
|
+
}
|
|
1986
2026
|
} else {
|
|
1987
|
-
|
|
2027
|
+
sourceFile.addImportDeclaration({
|
|
2028
|
+
moduleSpecifier: NESTJS_COMMON_MODULE,
|
|
2029
|
+
namedImports: ["Inject"]
|
|
2030
|
+
});
|
|
1988
2031
|
}
|
|
1989
2032
|
importAdded = true;
|
|
1990
2033
|
}
|
|
1991
|
-
return {
|
|
2034
|
+
return { importAdded, importsRemoved };
|
|
1992
2035
|
}
|
|
1993
2036
|
|
|
1994
2037
|
// src/commands/migration/versions/v001_capability/code-migrator/transformers/injection-transformer.ts
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
const afterParams = content.substring(insertPos);
|
|
2010
|
-
const beforeParams = content.substring(0, insertPos);
|
|
2011
|
-
result = beforeParams + ",\n " + INJECTION_PARAM + afterParams;
|
|
2012
|
-
} else {
|
|
2013
|
-
const constructorMatch = content.match(/constructor\s*\(\s*/);
|
|
2014
|
-
if (constructorMatch && constructorMatch.index !== void 0) {
|
|
2015
|
-
const paramStart = constructorMatch.index + constructorMatch[0].length;
|
|
2016
|
-
const before = content.substring(0, paramStart);
|
|
2017
|
-
const after = content.substring(paramStart);
|
|
2018
|
-
result = before + INJECTION_PARAM + after;
|
|
2038
|
+
import { Scope } from "ts-morph";
|
|
2039
|
+
var PARAM_NAME = "capabilityService";
|
|
2040
|
+
var PARAM_TYPE = "CapabilityService";
|
|
2041
|
+
function hasCapabilityServiceInjection(sourceFile) {
|
|
2042
|
+
const classes = sourceFile.getClasses();
|
|
2043
|
+
for (const classDecl of classes) {
|
|
2044
|
+
const constructors = classDecl.getConstructors();
|
|
2045
|
+
for (const ctor of constructors) {
|
|
2046
|
+
const params = ctor.getParameters();
|
|
2047
|
+
for (const param of params) {
|
|
2048
|
+
if (param.getName() === PARAM_NAME) {
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2019
2052
|
}
|
|
2020
2053
|
}
|
|
2021
|
-
return
|
|
2054
|
+
return false;
|
|
2022
2055
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
const argsEnd = originalCall.lastIndexOf(")");
|
|
2032
|
-
let args = "{}";
|
|
2033
|
-
if (argsEnd !== -1 && argsEnd > argsStart) {
|
|
2034
|
-
const extractedArgs = originalCall.substring(argsStart, argsEnd).trim();
|
|
2035
|
-
if (extractedArgs) {
|
|
2036
|
-
args = extractedArgs;
|
|
2056
|
+
function findInjectableClass(sourceFile) {
|
|
2057
|
+
const classes = sourceFile.getClasses();
|
|
2058
|
+
for (const classDecl of classes) {
|
|
2059
|
+
const decorators = classDecl.getDecorators();
|
|
2060
|
+
const isInjectable = decorators.some((d) => d.getName() === "Injectable");
|
|
2061
|
+
const isController = decorators.some((d) => d.getName() === "Controller");
|
|
2062
|
+
if (isInjectable || isController) {
|
|
2063
|
+
return classDecl;
|
|
2037
2064
|
}
|
|
2038
2065
|
}
|
|
2039
|
-
return
|
|
2066
|
+
return void 0;
|
|
2040
2067
|
}
|
|
2041
|
-
function
|
|
2042
|
-
|
|
2043
|
-
|
|
2068
|
+
function addInjection(sourceFile) {
|
|
2069
|
+
if (hasCapabilityServiceInjection(sourceFile)) {
|
|
2070
|
+
return { injectionAdded: false };
|
|
2071
|
+
}
|
|
2072
|
+
const classDecl = findInjectableClass(sourceFile);
|
|
2073
|
+
if (!classDecl) {
|
|
2074
|
+
return { injectionAdded: false };
|
|
2075
|
+
}
|
|
2076
|
+
const constructors = classDecl.getConstructors();
|
|
2077
|
+
if (constructors.length > 0) {
|
|
2078
|
+
const ctor = constructors[0];
|
|
2079
|
+
ctor.addParameter({
|
|
2080
|
+
name: PARAM_NAME,
|
|
2081
|
+
type: PARAM_TYPE,
|
|
2082
|
+
scope: Scope.Private,
|
|
2083
|
+
isReadonly: true,
|
|
2084
|
+
decorators: [{ name: "Inject", arguments: [] }]
|
|
2085
|
+
});
|
|
2086
|
+
} else {
|
|
2087
|
+
classDecl.addConstructor({
|
|
2088
|
+
parameters: [{
|
|
2089
|
+
name: PARAM_NAME,
|
|
2090
|
+
type: PARAM_TYPE,
|
|
2091
|
+
scope: Scope.Private,
|
|
2092
|
+
isReadonly: true,
|
|
2093
|
+
decorators: [{ name: "Inject", arguments: [] }]
|
|
2094
|
+
}]
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
return { injectionAdded: true };
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
// src/commands/migration/versions/v001_capability/code-migrator/transformers/call-site-transformer.ts
|
|
2101
|
+
import { SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
2102
|
+
var DEFAULT_ACTION_NAME = "run";
|
|
2103
|
+
function generateNewCallText(capabilityId, actionName, args) {
|
|
2104
|
+
const argsText = args.trim() || "{}";
|
|
2105
|
+
return `migrationAdaptor(this.capabilityService.load('${capabilityId}').call('${actionName}', ${argsText}))`;
|
|
2106
|
+
}
|
|
2107
|
+
function transformCallSites(sourceFile, imports) {
|
|
2108
|
+
const importMap = /* @__PURE__ */ new Map();
|
|
2109
|
+
for (const imp of imports) {
|
|
2110
|
+
importMap.set(imp.importName, {
|
|
2111
|
+
capabilityId: imp.capabilityId,
|
|
2112
|
+
actionName: imp.actionName ?? DEFAULT_ACTION_NAME
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2044
2115
|
let replacedCount = 0;
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2050
|
-
|
|
2116
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind2.CallExpression);
|
|
2117
|
+
const sortedCalls = [...callExpressions].sort((a, b) => b.getStart() - a.getStart());
|
|
2118
|
+
for (const callExpr of sortedCalls) {
|
|
2119
|
+
const expression = callExpr.getExpression();
|
|
2120
|
+
let importInfo;
|
|
2121
|
+
if (expression.getKind() === SyntaxKind2.Identifier) {
|
|
2122
|
+
const functionName = expression.getText();
|
|
2123
|
+
importInfo = importMap.get(functionName);
|
|
2124
|
+
} else if (expression.getKind() === SyntaxKind2.PropertyAccessExpression) {
|
|
2125
|
+
const propAccess = expression.asKind(SyntaxKind2.PropertyAccessExpression);
|
|
2126
|
+
if (propAccess) {
|
|
2127
|
+
const objectExpr = propAccess.getExpression();
|
|
2128
|
+
if (objectExpr.getKind() === SyntaxKind2.Identifier) {
|
|
2129
|
+
const objectName = objectExpr.getText();
|
|
2130
|
+
importInfo = importMap.get(objectName);
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
if (importInfo) {
|
|
2135
|
+
const args = callExpr.getArguments();
|
|
2136
|
+
const argsText = args.map((arg) => arg.getText()).join(", ");
|
|
2137
|
+
const newCallText = generateNewCallText(importInfo.capabilityId, importInfo.actionName, argsText);
|
|
2138
|
+
callExpr.replaceWithText(newCallText);
|
|
2139
|
+
replacedCount++;
|
|
2140
|
+
}
|
|
2051
2141
|
}
|
|
2052
|
-
return {
|
|
2142
|
+
return { replacedCount };
|
|
2053
2143
|
}
|
|
2054
2144
|
|
|
2055
2145
|
// src/commands/migration/versions/v001_capability/code-migrator/index.ts
|
|
2056
|
-
function analyzeFile(filePath) {
|
|
2057
|
-
const
|
|
2058
|
-
const sourceFile = ts4.createSourceFile(
|
|
2059
|
-
filePath,
|
|
2060
|
-
content,
|
|
2061
|
-
ts4.ScriptTarget.Latest,
|
|
2062
|
-
true
|
|
2063
|
-
);
|
|
2146
|
+
function analyzeFile(project, filePath, actionNameMap) {
|
|
2147
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
2064
2148
|
const imports = analyzeImports(sourceFile);
|
|
2149
|
+
for (const imp of imports) {
|
|
2150
|
+
const actionName = actionNameMap.get(imp.capabilityId);
|
|
2151
|
+
if (actionName) {
|
|
2152
|
+
imp.actionName = actionName;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2065
2155
|
const callSites = analyzeCallSites(sourceFile, imports);
|
|
2066
2156
|
const classInfo = analyzeClass(sourceFile);
|
|
2067
2157
|
const { canMigrate, reason } = canAutoMigrate(classInfo);
|
|
@@ -2075,7 +2165,7 @@ function analyzeFile(filePath) {
|
|
|
2075
2165
|
manualMigrationReason: reason
|
|
2076
2166
|
};
|
|
2077
2167
|
}
|
|
2078
|
-
function migrateFile(analysis, dryRun) {
|
|
2168
|
+
function migrateFile(project, analysis, dryRun) {
|
|
2079
2169
|
const absolutePath = path11.join(getProjectRoot3(), analysis.filePath);
|
|
2080
2170
|
if (!analysis.canAutoMigrate) {
|
|
2081
2171
|
return {
|
|
@@ -2088,42 +2178,19 @@ function migrateFile(analysis, dryRun) {
|
|
|
2088
2178
|
};
|
|
2089
2179
|
}
|
|
2090
2180
|
try {
|
|
2091
|
-
|
|
2092
|
-
const callResult = transformCallSites(
|
|
2093
|
-
|
|
2094
|
-
const
|
|
2095
|
-
analysis.filePath,
|
|
2096
|
-
content,
|
|
2097
|
-
ts4.ScriptTarget.Latest,
|
|
2098
|
-
true
|
|
2099
|
-
);
|
|
2100
|
-
const newImports = analyzeImports(sourceFile);
|
|
2101
|
-
const importResult = transformImports(content, newImports);
|
|
2102
|
-
content = importResult.content;
|
|
2103
|
-
let injectionAdded = false;
|
|
2104
|
-
if (analysis.classInfo) {
|
|
2105
|
-
const newSourceFile = ts4.createSourceFile(
|
|
2106
|
-
analysis.filePath,
|
|
2107
|
-
content,
|
|
2108
|
-
ts4.ScriptTarget.Latest,
|
|
2109
|
-
true
|
|
2110
|
-
);
|
|
2111
|
-
const newClassInfo = analyzeClass(newSourceFile);
|
|
2112
|
-
if (newClassInfo) {
|
|
2113
|
-
const injectionResult = addInjection(content, newClassInfo);
|
|
2114
|
-
content = injectionResult.content;
|
|
2115
|
-
injectionAdded = injectionResult.injectionAdded;
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2181
|
+
const sourceFile = project.getSourceFileOrThrow(absolutePath);
|
|
2182
|
+
const callResult = transformCallSites(sourceFile, analysis.imports);
|
|
2183
|
+
const importResult = transformImports(sourceFile, analysis.imports);
|
|
2184
|
+
const injectionResult = addInjection(sourceFile);
|
|
2118
2185
|
if (!dryRun) {
|
|
2119
|
-
|
|
2186
|
+
sourceFile.saveSync();
|
|
2120
2187
|
}
|
|
2121
2188
|
return {
|
|
2122
2189
|
filePath: analysis.filePath,
|
|
2123
2190
|
success: true,
|
|
2124
|
-
importsRemoved:
|
|
2191
|
+
importsRemoved: importResult.importsRemoved,
|
|
2125
2192
|
callSitesReplaced: callResult.replacedCount,
|
|
2126
|
-
injectionAdded
|
|
2193
|
+
injectionAdded: injectionResult.injectionAdded
|
|
2127
2194
|
};
|
|
2128
2195
|
} catch (error) {
|
|
2129
2196
|
return {
|
|
@@ -2136,20 +2203,39 @@ function migrateFile(analysis, dryRun) {
|
|
|
2136
2203
|
};
|
|
2137
2204
|
}
|
|
2138
2205
|
}
|
|
2139
|
-
|
|
2206
|
+
function buildActionNameMap(capabilities) {
|
|
2207
|
+
const map = /* @__PURE__ */ new Map();
|
|
2208
|
+
for (const cap of capabilities) {
|
|
2209
|
+
try {
|
|
2210
|
+
const actionName = getActionNameByPluginKey(cap.pluginKey);
|
|
2211
|
+
map.set(cap.id, actionName);
|
|
2212
|
+
} catch {
|
|
2213
|
+
map.set(cap.id, "run");
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
return map;
|
|
2217
|
+
}
|
|
2218
|
+
async function migrateCode(options, capabilities) {
|
|
2140
2219
|
const result = {
|
|
2141
2220
|
autoMigrated: [],
|
|
2142
2221
|
manualRequired: []
|
|
2143
2222
|
};
|
|
2223
|
+
const actionNameMap = buildActionNameMap(capabilities);
|
|
2144
2224
|
const filesToMigrate = scanFilesToMigrate();
|
|
2145
2225
|
if (filesToMigrate.length === 0) {
|
|
2146
2226
|
console.log(" No files need code migration.\n");
|
|
2147
2227
|
return result;
|
|
2148
2228
|
}
|
|
2229
|
+
const project = new Project({
|
|
2230
|
+
skipAddingFilesFromTsConfig: true,
|
|
2231
|
+
compilerOptions: {
|
|
2232
|
+
allowJs: true
|
|
2233
|
+
}
|
|
2234
|
+
});
|
|
2149
2235
|
const analyses = [];
|
|
2150
2236
|
for (const filePath of filesToMigrate) {
|
|
2151
2237
|
try {
|
|
2152
|
-
const analysis = analyzeFile(filePath);
|
|
2238
|
+
const analysis = analyzeFile(project, filePath, actionNameMap);
|
|
2153
2239
|
analyses.push(analysis);
|
|
2154
2240
|
} catch (error) {
|
|
2155
2241
|
console.error(` \u2717 Failed to analyze ${filePath}: ${error}`);
|
|
@@ -2167,7 +2253,7 @@ async function migrateCode(options) {
|
|
|
2167
2253
|
});
|
|
2168
2254
|
}
|
|
2169
2255
|
for (const analysis of autoMigratable) {
|
|
2170
|
-
const migrationResult = migrateFile(analysis, options.dryRun);
|
|
2256
|
+
const migrationResult = migrateFile(project, analysis, options.dryRun);
|
|
2171
2257
|
result.autoMigrated.push(migrationResult);
|
|
2172
2258
|
}
|
|
2173
2259
|
return result;
|
|
@@ -2183,17 +2269,17 @@ function getSuggestion(analysis) {
|
|
|
2183
2269
|
}
|
|
2184
2270
|
|
|
2185
2271
|
// src/commands/migration/versions/v001_capability/cleanup.ts
|
|
2186
|
-
import
|
|
2272
|
+
import fs12 from "fs";
|
|
2187
2273
|
import path12 from "path";
|
|
2188
2274
|
function cleanupOldFiles(capabilities, dryRun) {
|
|
2189
2275
|
const deletedFiles = [];
|
|
2190
2276
|
const errors = [];
|
|
2191
2277
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
2192
2278
|
const oldJsonPath = path12.join(capabilitiesDir, "capabilities.json");
|
|
2193
|
-
if (
|
|
2279
|
+
if (fs12.existsSync(oldJsonPath)) {
|
|
2194
2280
|
try {
|
|
2195
2281
|
if (!dryRun) {
|
|
2196
|
-
|
|
2282
|
+
fs12.unlinkSync(oldJsonPath);
|
|
2197
2283
|
}
|
|
2198
2284
|
deletedFiles.push("capabilities.json");
|
|
2199
2285
|
} catch (error) {
|
|
@@ -2202,10 +2288,10 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
2202
2288
|
}
|
|
2203
2289
|
for (const cap of capabilities) {
|
|
2204
2290
|
const tsFilePath = path12.join(capabilitiesDir, `${cap.id}.ts`);
|
|
2205
|
-
if (
|
|
2291
|
+
if (fs12.existsSync(tsFilePath)) {
|
|
2206
2292
|
try {
|
|
2207
2293
|
if (!dryRun) {
|
|
2208
|
-
|
|
2294
|
+
fs12.unlinkSync(tsFilePath);
|
|
2209
2295
|
}
|
|
2210
2296
|
deletedFiles.push(`${cap.id}.ts`);
|
|
2211
2297
|
} catch (error) {
|
|
@@ -2221,7 +2307,7 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
2221
2307
|
}
|
|
2222
2308
|
|
|
2223
2309
|
// src/commands/migration/versions/v001_capability/report-generator.ts
|
|
2224
|
-
import
|
|
2310
|
+
import fs13 from "fs";
|
|
2225
2311
|
import path13 from "path";
|
|
2226
2312
|
var REPORT_FILE = "capability-migration-report.md";
|
|
2227
2313
|
function printSummary(result) {
|
|
@@ -2385,7 +2471,7 @@ async function generateReport(result) {
|
|
|
2385
2471
|
}
|
|
2386
2472
|
lines.push("");
|
|
2387
2473
|
const reportPath = path13.join(getProjectRoot3(), REPORT_FILE);
|
|
2388
|
-
|
|
2474
|
+
fs13.writeFileSync(reportPath, lines.join("\n"), "utf-8");
|
|
2389
2475
|
console.log(`\u{1F4C4} Report generated: ${REPORT_FILE}`);
|
|
2390
2476
|
}
|
|
2391
2477
|
|
|
@@ -2478,7 +2564,7 @@ async function runCapabilityMigration(options = {}) {
|
|
|
2478
2564
|
console.log("\u{1F527} Step 3: Code Migration");
|
|
2479
2565
|
console.log(" Scanning server/ directory...\n");
|
|
2480
2566
|
try {
|
|
2481
|
-
codeResult = await migrateCode(fullOptions);
|
|
2567
|
+
codeResult = await migrateCode(fullOptions, jsonResult.capabilities);
|
|
2482
2568
|
let hasCodeError = false;
|
|
2483
2569
|
for (const file of codeResult.autoMigrated) {
|
|
2484
2570
|
if (file.success) {
|
|
@@ -2904,11 +2990,11 @@ var commands = [
|
|
|
2904
2990
|
|
|
2905
2991
|
// src/index.ts
|
|
2906
2992
|
var envPath = path14.join(process.cwd(), ".env");
|
|
2907
|
-
if (
|
|
2993
|
+
if (fs14.existsSync(envPath)) {
|
|
2908
2994
|
dotenvConfig({ path: envPath });
|
|
2909
2995
|
}
|
|
2910
2996
|
var __dirname = path14.dirname(fileURLToPath3(import.meta.url));
|
|
2911
|
-
var pkg = JSON.parse(
|
|
2997
|
+
var pkg = JSON.parse(fs14.readFileSync(path14.join(__dirname, "../package.json"), "utf-8"));
|
|
2912
2998
|
var cli = new FullstackCLI(pkg.version);
|
|
2913
2999
|
cli.useAll(commands);
|
|
2914
3000
|
cli.run();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/fullstack-cli",
|
|
3
|
-
"version": "1.1.6-alpha.
|
|
3
|
+
"version": "1.1.6-alpha.11",
|
|
4
4
|
"description": "CLI tool for fullstack template management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"commander": "^13.0.0",
|
|
38
38
|
"dotenv": "^16.0.0",
|
|
39
39
|
"drizzle-kit": "0.31.5",
|
|
40
|
+
"ts-morph": "^27.0.0",
|
|
40
41
|
"zod-to-json-schema": "^3.24.1"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|