@hyphaene/hexa-ts-kit 1.12.1 → 1.12.2
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/{chunk-EB6S5X3P.js → chunk-4LVIIP2D.js} +323 -262
- package/dist/cli.js +31 -46
- package/dist/mcp-server.js +1 -1
- package/package.json +1 -4
|
@@ -1043,7 +1043,7 @@ function getVaultConfig(config) {
|
|
|
1043
1043
|
|
|
1044
1044
|
// src/lib/contracts/permissions-extractor.ts
|
|
1045
1045
|
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
1046
|
-
import {
|
|
1046
|
+
import { Project, SyntaxKind } from "ts-morph";
|
|
1047
1047
|
function extractValues(sourcePath, config) {
|
|
1048
1048
|
if (!existsSync3(sourcePath)) {
|
|
1049
1049
|
return {
|
|
@@ -1062,12 +1062,13 @@ function extractValues(sourcePath, config) {
|
|
|
1062
1062
|
sourcePath
|
|
1063
1063
|
};
|
|
1064
1064
|
}
|
|
1065
|
-
|
|
1065
|
+
const project = new Project({
|
|
1066
|
+
useInMemoryFileSystem: true,
|
|
1067
|
+
skipAddingFilesFromTsConfig: true
|
|
1068
|
+
});
|
|
1069
|
+
let sourceFile;
|
|
1066
1070
|
try {
|
|
1067
|
-
|
|
1068
|
-
loc: true,
|
|
1069
|
-
range: true
|
|
1070
|
-
});
|
|
1071
|
+
sourceFile = project.createSourceFile("temp.ts", content);
|
|
1071
1072
|
} catch (err) {
|
|
1072
1073
|
return {
|
|
1073
1074
|
success: false,
|
|
@@ -1078,9 +1079,9 @@ function extractValues(sourcePath, config) {
|
|
|
1078
1079
|
const exportName = config.export;
|
|
1079
1080
|
const extractMode = config.extract;
|
|
1080
1081
|
if (extractMode === "const-values") {
|
|
1081
|
-
return extractConstValues(
|
|
1082
|
+
return extractConstValues(sourceFile, exportName, sourcePath);
|
|
1082
1083
|
} else if (extractMode === "zod-keys") {
|
|
1083
|
-
return extractZodKeys(
|
|
1084
|
+
return extractZodKeys(sourceFile, exportName, sourcePath);
|
|
1084
1085
|
}
|
|
1085
1086
|
return {
|
|
1086
1087
|
success: false,
|
|
@@ -1088,33 +1089,34 @@ function extractValues(sourcePath, config) {
|
|
|
1088
1089
|
sourcePath
|
|
1089
1090
|
};
|
|
1090
1091
|
}
|
|
1091
|
-
function extractConstValues(
|
|
1092
|
+
function extractConstValues(sourceFile, exportName, sourcePath) {
|
|
1092
1093
|
const values = [];
|
|
1093
1094
|
const keyToValue = {};
|
|
1094
|
-
for (const
|
|
1095
|
-
if (
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1095
|
+
for (const varStmt of sourceFile.getVariableStatements()) {
|
|
1096
|
+
if (!varStmt.isExported()) continue;
|
|
1097
|
+
for (const decl of varStmt.getDeclarations()) {
|
|
1098
|
+
if (decl.getName() !== exportName) continue;
|
|
1099
|
+
const init = decl.getInitializer();
|
|
1100
|
+
if (!init) continue;
|
|
1101
|
+
let objLiteral = init.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
1102
|
+
if (!objLiteral) {
|
|
1103
|
+
const asExpr = init.asKind(SyntaxKind.AsExpression);
|
|
1104
|
+
if (asExpr) {
|
|
1105
|
+
objLiteral = asExpr.getExpression().asKind(SyntaxKind.ObjectLiteralExpression);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
if (!objLiteral) continue;
|
|
1109
|
+
for (const prop of objLiteral.getProperties()) {
|
|
1110
|
+
const propAssign = prop.asKind(SyntaxKind.PropertyAssignment);
|
|
1111
|
+
if (!propAssign) continue;
|
|
1112
|
+
const val = propAssign.getInitializer();
|
|
1113
|
+
const strLiteral = val?.asKind(SyntaxKind.StringLiteral);
|
|
1114
|
+
if (!strLiteral) continue;
|
|
1115
|
+
const value = strLiteral.getLiteralValue();
|
|
1116
|
+
values.push(value);
|
|
1117
|
+
const keyNode = propAssign.getNameNode();
|
|
1118
|
+
if (keyNode.getKind() === SyntaxKind.Identifier) {
|
|
1119
|
+
keyToValue[keyNode.getText()] = value;
|
|
1118
1120
|
}
|
|
1119
1121
|
}
|
|
1120
1122
|
}
|
|
@@ -1133,24 +1135,26 @@ function extractConstValues(ast, exportName, sourcePath) {
|
|
|
1133
1135
|
sourcePath
|
|
1134
1136
|
};
|
|
1135
1137
|
}
|
|
1136
|
-
function extractZodKeys(
|
|
1138
|
+
function extractZodKeys(sourceFile, exportName, sourcePath) {
|
|
1137
1139
|
const values = [];
|
|
1138
|
-
for (const
|
|
1139
|
-
if (
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1140
|
+
for (const varStmt of sourceFile.getVariableStatements()) {
|
|
1141
|
+
if (!varStmt.isExported()) continue;
|
|
1142
|
+
for (const decl of varStmt.getDeclarations()) {
|
|
1143
|
+
if (decl.getName() !== exportName) continue;
|
|
1144
|
+
const init = decl.getInitializer();
|
|
1145
|
+
if (!init) continue;
|
|
1146
|
+
const callExpr = init.asKind(SyntaxKind.CallExpression);
|
|
1147
|
+
if (!callExpr) continue;
|
|
1148
|
+
const callee = callExpr.getExpression();
|
|
1149
|
+
if (!callee.getText().endsWith(".object")) continue;
|
|
1150
|
+
const firstArg = callExpr.getArguments()[0];
|
|
1151
|
+
if (!firstArg) continue;
|
|
1152
|
+
const objLiteral = firstArg.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
1153
|
+
if (!objLiteral) continue;
|
|
1154
|
+
for (const prop of objLiteral.getProperties()) {
|
|
1155
|
+
const propAssign = prop.asKind(SyntaxKind.PropertyAssignment);
|
|
1156
|
+
if (!propAssign) continue;
|
|
1157
|
+
values.push(propAssign.getName());
|
|
1154
1158
|
}
|
|
1155
1159
|
}
|
|
1156
1160
|
}
|
|
@@ -1171,7 +1175,7 @@ function extractZodKeys(ast, exportName, sourcePath) {
|
|
|
1171
1175
|
// src/lib/contracts/contract-parser.ts
|
|
1172
1176
|
import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
|
|
1173
1177
|
import fg7 from "fast-glob";
|
|
1174
|
-
import {
|
|
1178
|
+
import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
1175
1179
|
async function findContractFiles(repoPath) {
|
|
1176
1180
|
const files = await fg7("**/*.contract.ts", {
|
|
1177
1181
|
cwd: repoPath,
|
|
@@ -1198,12 +1202,13 @@ function parseContractFile(filePath) {
|
|
|
1198
1202
|
filePath
|
|
1199
1203
|
};
|
|
1200
1204
|
}
|
|
1201
|
-
|
|
1205
|
+
const project = new Project2({
|
|
1206
|
+
useInMemoryFileSystem: true,
|
|
1207
|
+
skipAddingFilesFromTsConfig: true
|
|
1208
|
+
});
|
|
1209
|
+
let sourceFile;
|
|
1202
1210
|
try {
|
|
1203
|
-
|
|
1204
|
-
loc: true,
|
|
1205
|
-
range: true
|
|
1206
|
-
});
|
|
1211
|
+
sourceFile = project.createSourceFile("contract.ts", content);
|
|
1207
1212
|
} catch (err) {
|
|
1208
1213
|
return {
|
|
1209
1214
|
success: false,
|
|
@@ -1213,20 +1218,15 @@ function parseContractFile(filePath) {
|
|
|
1213
1218
|
}
|
|
1214
1219
|
const endpoints = [];
|
|
1215
1220
|
let contractName = "UnknownContract";
|
|
1216
|
-
for (const
|
|
1217
|
-
if (
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
content
|
|
1226
|
-
);
|
|
1227
|
-
endpoints.push(...parsedEndpoints);
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1221
|
+
for (const varStmt of sourceFile.getVariableStatements()) {
|
|
1222
|
+
if (!varStmt.isExported()) continue;
|
|
1223
|
+
for (const decl of varStmt.getDeclarations()) {
|
|
1224
|
+
contractName = decl.getName();
|
|
1225
|
+
const init = decl.getInitializer();
|
|
1226
|
+
const routerObj = findRouterObjectArg(init);
|
|
1227
|
+
if (routerObj) {
|
|
1228
|
+
const parsedEndpoints = extractEndpointsFromRouter(routerObj);
|
|
1229
|
+
endpoints.push(...parsedEndpoints);
|
|
1230
1230
|
}
|
|
1231
1231
|
}
|
|
1232
1232
|
}
|
|
@@ -1265,31 +1265,33 @@ async function parseContracts(repoPath) {
|
|
|
1265
1265
|
contracts
|
|
1266
1266
|
};
|
|
1267
1267
|
}
|
|
1268
|
-
function
|
|
1268
|
+
function findRouterObjectArg(node) {
|
|
1269
1269
|
if (!node) return null;
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1270
|
+
const callExpr = node.asKind(SyntaxKind2.CallExpression);
|
|
1271
|
+
if (!callExpr) return null;
|
|
1272
|
+
const callee = callExpr.getExpression();
|
|
1273
|
+
const propAccess = callee.asKind(SyntaxKind2.PropertyAccessExpression);
|
|
1274
|
+
if (!propAccess || propAccess.getName() !== "router") return null;
|
|
1275
|
+
const firstArg = callExpr.getArguments()[0];
|
|
1276
|
+
if (!firstArg) return null;
|
|
1277
|
+
return firstArg.asKind(SyntaxKind2.ObjectLiteralExpression) ?? null;
|
|
1278
|
+
}
|
|
1279
|
+
function extractEndpointsFromRouter(routerObj) {
|
|
1276
1280
|
const endpoints = [];
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
if (prop.value.type !== "ObjectExpression") continue;
|
|
1281
|
+
for (const prop of routerObj.getProperties()) {
|
|
1282
|
+
const propAssign = prop.asKind(SyntaxKind2.PropertyAssignment);
|
|
1283
|
+
if (!propAssign) continue;
|
|
1284
|
+
const endpointName = propAssign.getName();
|
|
1285
|
+
const endpointLine = propAssign.getStartLineNumber();
|
|
1286
|
+
const endpointValue = propAssign.getInitializer();
|
|
1287
|
+
const endpointObj = endpointValue?.asKind(
|
|
1288
|
+
SyntaxKind2.ObjectLiteralExpression
|
|
1289
|
+
);
|
|
1290
|
+
if (!endpointObj) continue;
|
|
1288
1291
|
const endpoint = extractEndpointDetails(
|
|
1289
1292
|
endpointName,
|
|
1290
|
-
|
|
1291
|
-
endpointLine
|
|
1292
|
-
sourceContent
|
|
1293
|
+
endpointObj,
|
|
1294
|
+
endpointLine
|
|
1293
1295
|
);
|
|
1294
1296
|
if (endpoint) {
|
|
1295
1297
|
endpoints.push(endpoint);
|
|
@@ -1297,28 +1299,34 @@ function extractEndpointsFromRouter(routerCall, sourceContent) {
|
|
|
1297
1299
|
}
|
|
1298
1300
|
return endpoints;
|
|
1299
1301
|
}
|
|
1300
|
-
function extractEndpointDetails(name,
|
|
1302
|
+
function extractEndpointDetails(name, endpointObj, line) {
|
|
1301
1303
|
let method = "";
|
|
1302
1304
|
let path = "";
|
|
1303
1305
|
let metadata;
|
|
1304
1306
|
let strictStatusCodes;
|
|
1305
|
-
for (const prop of
|
|
1306
|
-
|
|
1307
|
-
if (
|
|
1308
|
-
const propName =
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
if (propName === "
|
|
1316
|
-
|
|
1317
|
-
|
|
1307
|
+
for (const prop of endpointObj.getProperties()) {
|
|
1308
|
+
const propAssign = prop.asKind(SyntaxKind2.PropertyAssignment);
|
|
1309
|
+
if (!propAssign) continue;
|
|
1310
|
+
const propName = propAssign.getName();
|
|
1311
|
+
const propVal = propAssign.getInitializer();
|
|
1312
|
+
if (!propVal) continue;
|
|
1313
|
+
if (propName === "method") {
|
|
1314
|
+
const strLit = propVal.asKind(SyntaxKind2.StringLiteral);
|
|
1315
|
+
if (strLit) method = strLit.getLiteralValue();
|
|
1316
|
+
}
|
|
1317
|
+
if (propName === "path") {
|
|
1318
|
+
const strLit = propVal.asKind(SyntaxKind2.StringLiteral);
|
|
1319
|
+
if (strLit) path = strLit.getLiteralValue();
|
|
1320
|
+
}
|
|
1321
|
+
if (propName === "strictStatusCodes") {
|
|
1322
|
+
if (propVal.getKind() === SyntaxKind2.TrueKeyword) {
|
|
1323
|
+
strictStatusCodes = true;
|
|
1324
|
+
} else if (propVal.getKind() === SyntaxKind2.FalseKeyword) {
|
|
1325
|
+
strictStatusCodes = false;
|
|
1318
1326
|
}
|
|
1319
1327
|
}
|
|
1320
|
-
if (propName === "
|
|
1321
|
-
|
|
1328
|
+
if (propName === "metadata") {
|
|
1329
|
+
metadata = extractMetadata(propVal);
|
|
1322
1330
|
}
|
|
1323
1331
|
}
|
|
1324
1332
|
return {
|
|
@@ -1330,82 +1338,105 @@ function extractEndpointDetails(name, objectExpr, line, sourceContent) {
|
|
|
1330
1338
|
line
|
|
1331
1339
|
};
|
|
1332
1340
|
}
|
|
1333
|
-
function extractMetadata(node
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
+
function extractMetadata(node) {
|
|
1342
|
+
const objLiteral = node.asKind(SyntaxKind2.ObjectLiteralExpression);
|
|
1343
|
+
if (objLiteral) {
|
|
1344
|
+
return parseMetadataObject(objLiteral);
|
|
1345
|
+
}
|
|
1346
|
+
const callExpr = node.asKind(SyntaxKind2.CallExpression);
|
|
1347
|
+
if (callExpr) {
|
|
1348
|
+
const callee = callExpr.getExpression();
|
|
1349
|
+
if (callee.getKind() === SyntaxKind2.Identifier && callee.getText() === "contractMetadata") {
|
|
1350
|
+
const firstArg = callExpr.getArguments()[0];
|
|
1351
|
+
if (firstArg) {
|
|
1352
|
+
const argObj = firstArg.asKind(SyntaxKind2.ObjectLiteralExpression);
|
|
1353
|
+
if (argObj) {
|
|
1354
|
+
return parseMetadataObject(argObj);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1341
1357
|
}
|
|
1342
1358
|
}
|
|
1343
1359
|
return void 0;
|
|
1344
1360
|
}
|
|
1345
|
-
function parseMetadataObject(
|
|
1361
|
+
function parseMetadataObject(objLiteral) {
|
|
1346
1362
|
const metadata = {};
|
|
1347
|
-
for (const prop of
|
|
1348
|
-
|
|
1349
|
-
if (
|
|
1350
|
-
const propName =
|
|
1351
|
-
|
|
1352
|
-
|
|
1363
|
+
for (const prop of objLiteral.getProperties()) {
|
|
1364
|
+
const propAssign = prop.asKind(SyntaxKind2.PropertyAssignment);
|
|
1365
|
+
if (!propAssign) continue;
|
|
1366
|
+
const propName = propAssign.getName();
|
|
1367
|
+
const propVal = propAssign.getInitializer();
|
|
1368
|
+
if (!propVal) continue;
|
|
1369
|
+
if (propName === "openApiTags") {
|
|
1370
|
+
const arr = propVal.asKind(SyntaxKind2.ArrayLiteralExpression);
|
|
1371
|
+
if (arr) {
|
|
1372
|
+
metadata.openApiTags = extractStringArray(arr);
|
|
1373
|
+
}
|
|
1353
1374
|
}
|
|
1354
1375
|
if (propName === "requiredPermission") {
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
metadata.requiredPermission = permValue;
|
|
1359
|
-
}
|
|
1376
|
+
const permValue = extractPermissionValue(propVal);
|
|
1377
|
+
if (permValue) {
|
|
1378
|
+
metadata.requiredPermission = permValue;
|
|
1360
1379
|
}
|
|
1361
1380
|
}
|
|
1362
|
-
if (propName === "requiresAuth"
|
|
1363
|
-
metadata.requiresAuth =
|
|
1381
|
+
if (propName === "requiresAuth") {
|
|
1382
|
+
metadata.requiresAuth = propVal.getKind() === SyntaxKind2.TrueKeyword;
|
|
1364
1383
|
}
|
|
1365
|
-
if (propName === "bff"
|
|
1366
|
-
|
|
1384
|
+
if (propName === "bff") {
|
|
1385
|
+
const bffObj = propVal.asKind(SyntaxKind2.ObjectLiteralExpression);
|
|
1386
|
+
if (bffObj) {
|
|
1387
|
+
metadata.bff = extractBffConfig(bffObj);
|
|
1388
|
+
}
|
|
1367
1389
|
}
|
|
1368
|
-
if (propName === "openapi"
|
|
1369
|
-
|
|
1390
|
+
if (propName === "openapi") {
|
|
1391
|
+
const openapiObj = propVal.asKind(SyntaxKind2.ObjectLiteralExpression);
|
|
1392
|
+
if (openapiObj) {
|
|
1393
|
+
metadata.openapi = extractLegacyOpenApi(openapiObj);
|
|
1394
|
+
}
|
|
1370
1395
|
}
|
|
1371
1396
|
}
|
|
1372
1397
|
return metadata;
|
|
1373
1398
|
}
|
|
1374
1399
|
function extractStringArray(arrayExpr) {
|
|
1375
1400
|
const values = [];
|
|
1376
|
-
for (const element of arrayExpr.
|
|
1377
|
-
|
|
1378
|
-
|
|
1401
|
+
for (const element of arrayExpr.getElements()) {
|
|
1402
|
+
const strLit = element.asKind(SyntaxKind2.StringLiteral);
|
|
1403
|
+
if (strLit) {
|
|
1404
|
+
values.push(strLit.getLiteralValue());
|
|
1379
1405
|
}
|
|
1380
1406
|
}
|
|
1381
1407
|
return values;
|
|
1382
1408
|
}
|
|
1383
|
-
function extractPermissionValue(node
|
|
1384
|
-
|
|
1385
|
-
|
|
1409
|
+
function extractPermissionValue(node) {
|
|
1410
|
+
const strLit = node.asKind(SyntaxKind2.StringLiteral);
|
|
1411
|
+
if (strLit) {
|
|
1412
|
+
return strLit.getLiteralValue();
|
|
1386
1413
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
return sourceContent.slice(start, end);
|
|
1391
|
-
}
|
|
1414
|
+
const propAccess = node.asKind(SyntaxKind2.PropertyAccessExpression);
|
|
1415
|
+
if (propAccess) {
|
|
1416
|
+
return propAccess.getText();
|
|
1392
1417
|
}
|
|
1393
1418
|
return void 0;
|
|
1394
1419
|
}
|
|
1395
|
-
function extractBffConfig(
|
|
1420
|
+
function extractBffConfig(objLiteral) {
|
|
1396
1421
|
const bff = {};
|
|
1397
|
-
for (const prop of
|
|
1398
|
-
|
|
1399
|
-
if (
|
|
1400
|
-
if (
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1422
|
+
for (const prop of objLiteral.getProperties()) {
|
|
1423
|
+
const propAssign = prop.asKind(SyntaxKind2.PropertyAssignment);
|
|
1424
|
+
if (!propAssign) continue;
|
|
1425
|
+
if (propAssign.getName() === "apiServices") {
|
|
1426
|
+
const arr = propAssign.getInitializer()?.asKind(SyntaxKind2.ArrayLiteralExpression);
|
|
1427
|
+
if (arr) {
|
|
1428
|
+
bff.apiServices = [];
|
|
1429
|
+
for (const element of arr.getElements()) {
|
|
1430
|
+
const strLit = element.asKind(SyntaxKind2.StringLiteral);
|
|
1431
|
+
if (strLit) {
|
|
1432
|
+
bff.apiServices.push(strLit.getLiteralValue());
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
const propAccess = element.asKind(
|
|
1436
|
+
SyntaxKind2.PropertyAccessExpression
|
|
1437
|
+
);
|
|
1438
|
+
if (propAccess) {
|
|
1439
|
+
bff.apiServices.push(propAccess.getName());
|
|
1409
1440
|
}
|
|
1410
1441
|
}
|
|
1411
1442
|
}
|
|
@@ -1413,13 +1444,16 @@ function extractBffConfig(objectExpr) {
|
|
|
1413
1444
|
}
|
|
1414
1445
|
return bff;
|
|
1415
1446
|
}
|
|
1416
|
-
function extractLegacyOpenApi(
|
|
1447
|
+
function extractLegacyOpenApi(objLiteral) {
|
|
1417
1448
|
const openapi = {};
|
|
1418
|
-
for (const prop of
|
|
1419
|
-
|
|
1420
|
-
if (
|
|
1421
|
-
if (
|
|
1422
|
-
|
|
1449
|
+
for (const prop of objLiteral.getProperties()) {
|
|
1450
|
+
const propAssign = prop.asKind(SyntaxKind2.PropertyAssignment);
|
|
1451
|
+
if (!propAssign) continue;
|
|
1452
|
+
if (propAssign.getName() === "tags") {
|
|
1453
|
+
const arr = propAssign.getInitializer()?.asKind(SyntaxKind2.ArrayLiteralExpression);
|
|
1454
|
+
if (arr) {
|
|
1455
|
+
openapi.tags = extractStringArray(arr);
|
|
1456
|
+
}
|
|
1423
1457
|
}
|
|
1424
1458
|
}
|
|
1425
1459
|
return openapi;
|
|
@@ -2392,7 +2426,7 @@ function checkSchemaImport(contractFile, _contractDir, imp) {
|
|
|
2392
2426
|
import fg9 from "fast-glob";
|
|
2393
2427
|
import { readFileSync as readFileSync4 } from "fs";
|
|
2394
2428
|
import { basename as basename5 } from "path";
|
|
2395
|
-
import {
|
|
2429
|
+
import { Node, Project as Project3, SyntaxKind as SyntaxKind3 } from "ts-morph";
|
|
2396
2430
|
var ALLOWED_SUFFIXES = [
|
|
2397
2431
|
".enum-bundle.ts",
|
|
2398
2432
|
".schema.ts",
|
|
@@ -2411,13 +2445,12 @@ var ALLOWED_SUFFIXES = [
|
|
|
2411
2445
|
var ALLOWED_SPECIAL_FILES = ["index.ts", "openapi.ts"];
|
|
2412
2446
|
function parseFile(filePath) {
|
|
2413
2447
|
try {
|
|
2414
|
-
const
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
range: true,
|
|
2418
|
-
comment: true,
|
|
2419
|
-
jsx: false
|
|
2448
|
+
const project = new Project3({
|
|
2449
|
+
useInMemoryFileSystem: false,
|
|
2450
|
+
skipAddingFilesFromTsConfig: true
|
|
2420
2451
|
});
|
|
2452
|
+
project.addSourceFileAtPath(filePath);
|
|
2453
|
+
return project.getSourceFileOrThrow(filePath);
|
|
2421
2454
|
} catch {
|
|
2422
2455
|
return null;
|
|
2423
2456
|
}
|
|
@@ -2425,48 +2458,58 @@ function parseFile(filePath) {
|
|
|
2425
2458
|
function readFileContent(filePath) {
|
|
2426
2459
|
return readFileSync4(filePath, "utf-8");
|
|
2427
2460
|
}
|
|
2428
|
-
function getExportedNames(
|
|
2461
|
+
function getExportedNames(sourceFile) {
|
|
2429
2462
|
const names = [];
|
|
2430
|
-
for (const
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2463
|
+
for (const statement of sourceFile.getStatements()) {
|
|
2464
|
+
const kind = statement.getKind();
|
|
2465
|
+
if (kind === SyntaxKind3.ExportDeclaration) {
|
|
2466
|
+
const exportDecl = statement.asKindOrThrow(SyntaxKind3.ExportDeclaration);
|
|
2467
|
+
for (const namedExport of exportDecl.getNamedExports()) {
|
|
2468
|
+
names.push(
|
|
2469
|
+
namedExport.getAliasNode()?.getText() ?? namedExport.getName()
|
|
2470
|
+
);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
if (Node.isModifierable(statement) && statement.hasModifier(SyntaxKind3.ExportKeyword)) {
|
|
2474
|
+
if (kind === SyntaxKind3.VariableStatement) {
|
|
2475
|
+
const varStatement = statement.asKindOrThrow(
|
|
2476
|
+
SyntaxKind3.VariableStatement
|
|
2477
|
+
);
|
|
2478
|
+
for (const decl of varStatement.getDeclarations()) {
|
|
2479
|
+
const nameNode = decl.getNameNode();
|
|
2480
|
+
if (nameNode.getKind() === SyntaxKind3.Identifier) {
|
|
2481
|
+
names.push(nameNode.getText());
|
|
2482
|
+
} else if (nameNode.getKind() === SyntaxKind3.ObjectBindingPattern) {
|
|
2483
|
+
const objectPattern = nameNode.asKindOrThrow(
|
|
2484
|
+
SyntaxKind3.ObjectBindingPattern
|
|
2485
|
+
);
|
|
2486
|
+
for (const element of objectPattern.getElements()) {
|
|
2487
|
+
const propertyName = element.getPropertyNameNode();
|
|
2488
|
+
const elementName = element.getNameNode();
|
|
2489
|
+
names.push(elementName.getText());
|
|
2443
2490
|
}
|
|
2444
2491
|
}
|
|
2445
2492
|
}
|
|
2446
|
-
if (node.declaration.type === "TSTypeAliasDeclaration") {
|
|
2447
|
-
names.push(node.declaration.id.name);
|
|
2448
|
-
}
|
|
2449
|
-
if (node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
|
|
2450
|
-
names.push(node.declaration.id.name);
|
|
2451
|
-
}
|
|
2452
2493
|
}
|
|
2453
|
-
if (
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2494
|
+
if (kind === SyntaxKind3.TypeAliasDeclaration) {
|
|
2495
|
+
const typeAlias = statement.asKindOrThrow(
|
|
2496
|
+
SyntaxKind3.TypeAliasDeclaration
|
|
2497
|
+
);
|
|
2498
|
+
names.push(typeAlias.getName());
|
|
2499
|
+
}
|
|
2500
|
+
if (kind === SyntaxKind3.FunctionDeclaration) {
|
|
2501
|
+
const funcDecl = statement.asKindOrThrow(
|
|
2502
|
+
SyntaxKind3.FunctionDeclaration
|
|
2503
|
+
);
|
|
2504
|
+
const funcName = funcDecl.getName();
|
|
2505
|
+
if (funcName) names.push(funcName);
|
|
2459
2506
|
}
|
|
2460
2507
|
}
|
|
2461
2508
|
}
|
|
2462
2509
|
return names;
|
|
2463
2510
|
}
|
|
2464
|
-
function hasDefaultExport(
|
|
2465
|
-
return
|
|
2466
|
-
(node) => node.type === "ExportDefaultDeclaration" || node.type === "ExportNamedDeclaration" && node.specifiers?.some(
|
|
2467
|
-
(s) => s.exported.type === "Identifier" && s.exported.name === "default"
|
|
2468
|
-
)
|
|
2469
|
-
);
|
|
2511
|
+
function hasDefaultExport(sourceFile) {
|
|
2512
|
+
return sourceFile.getExportedDeclarations().has("default");
|
|
2470
2513
|
}
|
|
2471
2514
|
function hasOpenApiDocumentation(content) {
|
|
2472
2515
|
return /\.describe\s*\(/.test(content) || /\.openapi\s*\(/.test(content);
|
|
@@ -2482,43 +2525,62 @@ function hasZodDataSchemas(content) {
|
|
|
2482
2525
|
content
|
|
2483
2526
|
);
|
|
2484
2527
|
}
|
|
2485
|
-
function getExportsWithoutDeprecatedJsdoc(
|
|
2528
|
+
function getExportsWithoutDeprecatedJsdoc(sourceFile) {
|
|
2486
2529
|
const missingDeprecated = [];
|
|
2487
|
-
for (const
|
|
2488
|
-
|
|
2530
|
+
for (const statement of sourceFile.getStatements()) {
|
|
2531
|
+
const kind = statement.getKind();
|
|
2532
|
+
const isExported = Node.isModifierable(statement) && statement.hasModifier(SyntaxKind3.ExportKeyword);
|
|
2533
|
+
if (kind !== SyntaxKind3.ExportDeclaration && kind !== SyntaxKind3.ExportAssignment && !isExported) {
|
|
2489
2534
|
continue;
|
|
2490
2535
|
}
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2536
|
+
if (kind === SyntaxKind3.ExportAssignment) {
|
|
2537
|
+
if (!hasDeprecatedComment(statement)) {
|
|
2538
|
+
missingDeprecated.push("default");
|
|
2539
|
+
}
|
|
2540
|
+
continue;
|
|
2541
|
+
}
|
|
2542
|
+
if (kind === SyntaxKind3.ExportDeclaration) {
|
|
2543
|
+
const exportDecl = statement.asKindOrThrow(SyntaxKind3.ExportDeclaration);
|
|
2544
|
+
if (exportDecl.getModuleSpecifier() !== void 0) continue;
|
|
2545
|
+
}
|
|
2546
|
+
let exportName = "unknown";
|
|
2547
|
+
if (kind === SyntaxKind3.VariableStatement) {
|
|
2548
|
+
const varStatement = statement.asKindOrThrow(
|
|
2549
|
+
SyntaxKind3.VariableStatement
|
|
2550
|
+
);
|
|
2551
|
+
const declarations = varStatement.getDeclarations();
|
|
2552
|
+
const firstDecl = declarations[0];
|
|
2553
|
+
if (firstDecl) {
|
|
2554
|
+
exportName = firstDecl.getName();
|
|
2502
2555
|
}
|
|
2503
|
-
|
|
2556
|
+
} else if (kind === SyntaxKind3.TypeAliasDeclaration) {
|
|
2557
|
+
const typeAlias = statement.asKindOrThrow(
|
|
2558
|
+
SyntaxKind3.TypeAliasDeclaration
|
|
2559
|
+
);
|
|
2560
|
+
exportName = typeAlias.getName();
|
|
2561
|
+
} else if (kind === SyntaxKind3.FunctionDeclaration) {
|
|
2562
|
+
const funcDecl = statement.asKindOrThrow(SyntaxKind3.FunctionDeclaration);
|
|
2563
|
+
exportName = funcDecl.getName() ?? "anonymous";
|
|
2504
2564
|
}
|
|
2505
|
-
|
|
2506
|
-
const lastCommentBlock = linesBefore.match(/\/\*\*[\s\S]*?\*\/\s*$/);
|
|
2507
|
-
if (!lastCommentBlock || !lastCommentBlock[0].includes("@deprecated")) {
|
|
2565
|
+
if (!hasDeprecatedComment(statement)) {
|
|
2508
2566
|
missingDeprecated.push(exportName);
|
|
2509
2567
|
}
|
|
2510
2568
|
}
|
|
2511
2569
|
return missingDeprecated;
|
|
2512
2570
|
}
|
|
2513
|
-
function
|
|
2571
|
+
function hasDeprecatedComment(node) {
|
|
2572
|
+
return node.getLeadingCommentRanges().some((comment) => comment.getText().includes("@deprecated"));
|
|
2573
|
+
}
|
|
2574
|
+
function getNonReexportStatements(sourceFile) {
|
|
2514
2575
|
const violations = [];
|
|
2515
|
-
for (const
|
|
2516
|
-
|
|
2517
|
-
if (
|
|
2518
|
-
if (
|
|
2519
|
-
|
|
2520
|
-
continue;
|
|
2521
|
-
|
|
2576
|
+
for (const statement of sourceFile.getStatements()) {
|
|
2577
|
+
const kind = statement.getKind();
|
|
2578
|
+
if (kind === SyntaxKind3.ImportDeclaration) continue;
|
|
2579
|
+
if (kind === SyntaxKind3.ExportDeclaration) {
|
|
2580
|
+
const exportDecl = statement.asKindOrThrow(SyntaxKind3.ExportDeclaration);
|
|
2581
|
+
if (exportDecl.getModuleSpecifier() !== void 0) continue;
|
|
2582
|
+
}
|
|
2583
|
+
violations.push(statement);
|
|
2522
2584
|
}
|
|
2523
2585
|
return violations;
|
|
2524
2586
|
}
|
|
@@ -2531,9 +2593,9 @@ async function checkEnumBundleRules(cwd) {
|
|
|
2531
2593
|
for (const file of files) {
|
|
2532
2594
|
const fullPath = `${cwd}/${file}`;
|
|
2533
2595
|
const content = readFileContent(fullPath);
|
|
2534
|
-
const
|
|
2535
|
-
if (!
|
|
2536
|
-
const exportedNames = getExportedNames(
|
|
2596
|
+
const sourceFile = parseFile(fullPath);
|
|
2597
|
+
if (!sourceFile) continue;
|
|
2598
|
+
const exportedNames = getExportedNames(sourceFile);
|
|
2537
2599
|
const fileName = basename5(file, ".enum-bundle.ts");
|
|
2538
2600
|
const upperName = fileName.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
|
|
2539
2601
|
const hasSchema = exportedNames.some((n) => n.endsWith("Schema"));
|
|
@@ -2584,9 +2646,9 @@ async function checkResponseRules(cwd) {
|
|
|
2584
2646
|
for (const file of files) {
|
|
2585
2647
|
const fullPath = `${cwd}/${file}`;
|
|
2586
2648
|
const content = readFileContent(fullPath);
|
|
2587
|
-
const
|
|
2588
|
-
if (!
|
|
2589
|
-
const exportedNames = getExportedNames(
|
|
2649
|
+
const sourceFile = parseFile(fullPath);
|
|
2650
|
+
if (!sourceFile) continue;
|
|
2651
|
+
const exportedNames = getExportedNames(sourceFile);
|
|
2590
2652
|
const fileName = basename5(file, ".response.ts");
|
|
2591
2653
|
const httpCode = fileName.match(/^(\d{3})$/)?.[1];
|
|
2592
2654
|
if (httpCode) {
|
|
@@ -2600,7 +2662,7 @@ async function checkResponseRules(cwd) {
|
|
|
2600
2662
|
});
|
|
2601
2663
|
}
|
|
2602
2664
|
}
|
|
2603
|
-
if (!hasDefaultExport(
|
|
2665
|
+
if (!hasDefaultExport(sourceFile)) {
|
|
2604
2666
|
results.push({
|
|
2605
2667
|
ruleId: "CTR-RESPONSE-002",
|
|
2606
2668
|
severity: "error",
|
|
@@ -2630,9 +2692,9 @@ async function checkRequestRules(cwd) {
|
|
|
2630
2692
|
for (const file of files) {
|
|
2631
2693
|
const fullPath = `${cwd}/${file}`;
|
|
2632
2694
|
const content = readFileContent(fullPath);
|
|
2633
|
-
const
|
|
2634
|
-
if (!
|
|
2635
|
-
const exportedNames = getExportedNames(
|
|
2695
|
+
const sourceFile = parseFile(fullPath);
|
|
2696
|
+
if (!sourceFile) continue;
|
|
2697
|
+
const exportedNames = getExportedNames(sourceFile);
|
|
2636
2698
|
const hasTypedSchema = exportedNames.some(
|
|
2637
2699
|
(n) => /(Query|Body|Headers|Params)Schema$/.test(n)
|
|
2638
2700
|
);
|
|
@@ -2666,9 +2728,9 @@ async function checkContractFileRules(cwd) {
|
|
|
2666
2728
|
for (const file of files) {
|
|
2667
2729
|
const fullPath = `${cwd}/${file}`;
|
|
2668
2730
|
const content = readFileContent(fullPath);
|
|
2669
|
-
const
|
|
2670
|
-
if (!
|
|
2671
|
-
const exportedNames = getExportedNames(
|
|
2731
|
+
const sourceFile = parseFile(fullPath);
|
|
2732
|
+
if (!sourceFile) continue;
|
|
2733
|
+
const exportedNames = getExportedNames(sourceFile);
|
|
2672
2734
|
const hasContractExport = exportedNames.some((n) => n.endsWith("Contract"));
|
|
2673
2735
|
if (!hasContractExport) {
|
|
2674
2736
|
results.push({
|
|
@@ -2708,16 +2770,16 @@ async function checkIndexRules(cwd) {
|
|
|
2708
2770
|
});
|
|
2709
2771
|
for (const file of files) {
|
|
2710
2772
|
const fullPath = `${cwd}/${file}`;
|
|
2711
|
-
const
|
|
2712
|
-
if (!
|
|
2713
|
-
const violations = getNonReexportStatements(
|
|
2773
|
+
const sourceFile = parseFile(fullPath);
|
|
2774
|
+
if (!sourceFile) continue;
|
|
2775
|
+
const violations = getNonReexportStatements(sourceFile);
|
|
2714
2776
|
if (violations.length > 0) {
|
|
2715
2777
|
results.push({
|
|
2716
2778
|
ruleId: "CTR-INDEX-001",
|
|
2717
2779
|
severity: "error",
|
|
2718
2780
|
message: `Index file ${file} contains ${violations.length} non-reexport statement(s)`,
|
|
2719
2781
|
file,
|
|
2720
|
-
line: violations[0]?.
|
|
2782
|
+
line: violations[0]?.getStartLineNumber(),
|
|
2721
2783
|
suggestion: "Index files should only contain: export * from '...' or export { X } from '...'"
|
|
2722
2784
|
});
|
|
2723
2785
|
}
|
|
@@ -2782,10 +2844,9 @@ async function checkDeprecatedRules(cwd) {
|
|
|
2782
2844
|
});
|
|
2783
2845
|
for (const file of files) {
|
|
2784
2846
|
const fullPath = `${cwd}/${file}`;
|
|
2785
|
-
const
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
const missing = getExportsWithoutDeprecatedJsdoc(ast, content);
|
|
2847
|
+
const sourceFile = parseFile(fullPath);
|
|
2848
|
+
if (!sourceFile) continue;
|
|
2849
|
+
const missing = getExportsWithoutDeprecatedJsdoc(sourceFile);
|
|
2789
2850
|
if (missing.length > 0) {
|
|
2790
2851
|
results.push({
|
|
2791
2852
|
ruleId: "CTR-DEPRECATED-001",
|
|
@@ -2948,7 +3009,7 @@ var contractsChecker = {
|
|
|
2948
3009
|
// src/lint/checkers/vault/index.ts
|
|
2949
3010
|
import { existsSync as existsSync5, readdirSync } from "fs";
|
|
2950
3011
|
import { join as join3, dirname as dirname4 } from "path";
|
|
2951
|
-
import { Project, SyntaxKind } from "ts-morph";
|
|
3012
|
+
import { Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
2952
3013
|
var VAULT_PATHS = [
|
|
2953
3014
|
"src/common/config/vault",
|
|
2954
3015
|
"server/vault",
|
|
@@ -2977,7 +3038,7 @@ function isInsideZodObject(node) {
|
|
|
2977
3038
|
if (!node) return false;
|
|
2978
3039
|
let current = node;
|
|
2979
3040
|
while (current) {
|
|
2980
|
-
if (current.getKind() ===
|
|
3041
|
+
if (current.getKind() === SyntaxKind4.CallExpression) {
|
|
2981
3042
|
const text = current.getText();
|
|
2982
3043
|
if (text.startsWith("z.object(")) return true;
|
|
2983
3044
|
}
|
|
@@ -2989,7 +3050,7 @@ function checkAstPatterns(sourceFile) {
|
|
|
2989
3050
|
const results = [];
|
|
2990
3051
|
const filePath = sourceFile.getFilePath();
|
|
2991
3052
|
sourceFile.forEachDescendant((node) => {
|
|
2992
|
-
if (node.getKind() ===
|
|
3053
|
+
if (node.getKind() === SyntaxKind4.CallExpression) {
|
|
2993
3054
|
const text = node.getText();
|
|
2994
3055
|
if (text.startsWith("z.lazy(")) {
|
|
2995
3056
|
results.push({
|
|
@@ -3001,11 +3062,11 @@ function checkAstPatterns(sourceFile) {
|
|
|
3001
3062
|
});
|
|
3002
3063
|
}
|
|
3003
3064
|
if (text.startsWith("z.enum(")) {
|
|
3004
|
-
const callExpr = node.asKind(
|
|
3065
|
+
const callExpr = node.asKind(SyntaxKind4.CallExpression);
|
|
3005
3066
|
const args = callExpr?.getArguments();
|
|
3006
3067
|
if (args && args.length > 0) {
|
|
3007
3068
|
const firstArg = args[0];
|
|
3008
|
-
if (firstArg?.getKind() ===
|
|
3069
|
+
if (firstArg?.getKind() === SyntaxKind4.Identifier) {
|
|
3009
3070
|
results.push({
|
|
3010
3071
|
ruleId: "VAULT-AST-004",
|
|
3011
3072
|
severity: getRuleSeverity("VAULT-AST-004"),
|
|
@@ -3018,11 +3079,11 @@ function checkAstPatterns(sourceFile) {
|
|
|
3018
3079
|
}
|
|
3019
3080
|
}
|
|
3020
3081
|
if (text.startsWith("z.object(")) {
|
|
3021
|
-
const callExpr = node.asKind(
|
|
3082
|
+
const callExpr = node.asKind(SyntaxKind4.CallExpression);
|
|
3022
3083
|
const args = callExpr?.getArguments();
|
|
3023
3084
|
if (args && args.length > 0) {
|
|
3024
3085
|
const firstArg = args[0];
|
|
3025
|
-
if (firstArg?.getKind() ===
|
|
3086
|
+
if (firstArg?.getKind() === SyntaxKind4.Identifier) {
|
|
3026
3087
|
results.push({
|
|
3027
3088
|
ruleId: "VAULT-AST-006",
|
|
3028
3089
|
severity: getRuleSeverity("VAULT-AST-006"),
|
|
@@ -3034,11 +3095,11 @@ function checkAstPatterns(sourceFile) {
|
|
|
3034
3095
|
}
|
|
3035
3096
|
}
|
|
3036
3097
|
}
|
|
3037
|
-
if (node.getKind() ===
|
|
3098
|
+
if (node.getKind() === SyntaxKind4.SpreadAssignment) {
|
|
3038
3099
|
if (isInsideZodObject(node)) {
|
|
3039
|
-
const spreadExpr = node.asKind(
|
|
3100
|
+
const spreadExpr = node.asKind(SyntaxKind4.SpreadAssignment);
|
|
3040
3101
|
const expr = spreadExpr?.getExpression();
|
|
3041
|
-
if (expr?.getKind() ===
|
|
3102
|
+
if (expr?.getKind() === SyntaxKind4.ConditionalExpression || expr?.getKind() === SyntaxKind4.Identifier) {
|
|
3042
3103
|
results.push({
|
|
3043
3104
|
ruleId: "VAULT-AST-002",
|
|
3044
3105
|
severity: getRuleSeverity("VAULT-AST-002"),
|
|
@@ -3049,8 +3110,8 @@ function checkAstPatterns(sourceFile) {
|
|
|
3049
3110
|
}
|
|
3050
3111
|
}
|
|
3051
3112
|
}
|
|
3052
|
-
if (node.getKind() ===
|
|
3053
|
-
const funcNode = node.asKind(
|
|
3113
|
+
if (node.getKind() === SyntaxKind4.FunctionDeclaration || node.getKind() === SyntaxKind4.ArrowFunction) {
|
|
3114
|
+
const funcNode = node.asKind(SyntaxKind4.FunctionDeclaration) || node.asKind(SyntaxKind4.ArrowFunction);
|
|
3054
3115
|
if (funcNode) {
|
|
3055
3116
|
const body = funcNode.getBody();
|
|
3056
3117
|
if (body) {
|
|
@@ -3082,7 +3143,7 @@ var vaultChecker = {
|
|
|
3082
3143
|
}
|
|
3083
3144
|
const configResult = loadConfig(ctx.cwd);
|
|
3084
3145
|
const disabledRules = configResult.success ? getDisabledVaultRules(configResult.config) : [];
|
|
3085
|
-
const project = new
|
|
3146
|
+
const project = new Project4({
|
|
3086
3147
|
skipAddingFilesFromTsConfig: true,
|
|
3087
3148
|
skipFileDependencyResolution: true
|
|
3088
3149
|
});
|
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
lintCommand,
|
|
6
6
|
loadConfig,
|
|
7
7
|
scaffoldCommand
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4LVIIP2D.js";
|
|
9
9
|
import {
|
|
10
10
|
scanForVaultRepos
|
|
11
11
|
} from "./chunk-WXFSGE4N.js";
|
|
@@ -21,7 +21,7 @@ import { resolve } from "path";
|
|
|
21
21
|
// src/lib/contracts/codemod/analyze-bff.ts
|
|
22
22
|
import { readFileSync } from "fs";
|
|
23
23
|
import fg from "fast-glob";
|
|
24
|
-
import {
|
|
24
|
+
import { Project, SyntaxKind } from "ts-morph";
|
|
25
25
|
var MODULE_TO_SERVICE = {
|
|
26
26
|
SeeCoreModule: "seeCore",
|
|
27
27
|
LocusModule: "locus",
|
|
@@ -104,63 +104,48 @@ function extractApiServicesFromModule(modulePath) {
|
|
|
104
104
|
return services;
|
|
105
105
|
}
|
|
106
106
|
function analyzeController(controllerPath, apiServices) {
|
|
107
|
-
const content = readFileSync(controllerPath, "utf-8");
|
|
108
107
|
const mappings = [];
|
|
109
|
-
|
|
108
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true });
|
|
109
|
+
let sourceFile;
|
|
110
110
|
try {
|
|
111
|
-
|
|
111
|
+
sourceFile = project.addSourceFileAtPath(controllerPath);
|
|
112
112
|
} catch {
|
|
113
113
|
return mappings;
|
|
114
114
|
}
|
|
115
|
-
for (const
|
|
116
|
-
|
|
117
|
-
const classNode = node.declaration;
|
|
118
|
-
analyzeClassMethods(
|
|
119
|
-
classNode,
|
|
120
|
-
controllerPath,
|
|
121
|
-
apiServices,
|
|
122
|
-
content,
|
|
123
|
-
mappings
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
if (node.type === "ClassDeclaration") {
|
|
127
|
-
analyzeClassMethods(node, controllerPath, apiServices, content, mappings);
|
|
128
|
-
}
|
|
115
|
+
for (const classDecl of sourceFile.getClasses()) {
|
|
116
|
+
analyzeClassMethods(classDecl, controllerPath, apiServices, mappings);
|
|
129
117
|
}
|
|
130
118
|
return mappings;
|
|
131
119
|
}
|
|
132
|
-
function analyzeClassMethods(
|
|
133
|
-
for (const
|
|
134
|
-
|
|
135
|
-
if (member.key.type !== "Identifier") continue;
|
|
136
|
-
const methodName = member.key.name;
|
|
120
|
+
function analyzeClassMethods(classDecl, controllerPath, apiServices, mappings) {
|
|
121
|
+
for (const method of classDecl.getMethods()) {
|
|
122
|
+
const methodName = method.getName();
|
|
137
123
|
if (methodName === "constructor" || methodName.startsWith("_")) continue;
|
|
138
|
-
const decorators = member.decorators ?? [];
|
|
139
124
|
let permission = null;
|
|
140
|
-
let
|
|
125
|
+
let httpMethod = null;
|
|
141
126
|
let path = null;
|
|
142
127
|
let contractEndpointName = null;
|
|
143
|
-
for (const decorator of
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
for (const decorator of method.getDecorators()) {
|
|
129
|
+
const decoratorName = decorator.getName();
|
|
130
|
+
const args = decorator.getArguments();
|
|
131
|
+
if (decoratorName === "TsRestHandler" && args[0]) {
|
|
132
|
+
const arg = args[0];
|
|
133
|
+
if (arg.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
134
|
+
const propAccess = arg.asKind(SyntaxKind.PropertyAccessExpression);
|
|
135
|
+
contractEndpointName = propAccess.getName();
|
|
151
136
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
137
|
+
}
|
|
138
|
+
if (decoratorName === "Authorize" && args[0]) {
|
|
139
|
+
const arg = args[0];
|
|
140
|
+
if (arg.getKind() === SyntaxKind.PropertyAccessExpression) {
|
|
141
|
+
const propAccess = arg.asKind(SyntaxKind.PropertyAccessExpression);
|
|
142
|
+
permission = propAccess.getName();
|
|
157
143
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
144
|
+
}
|
|
145
|
+
if (["Get", "Post", "Put", "Patch", "Delete"].includes(decoratorName)) {
|
|
146
|
+
httpMethod = decoratorName.toUpperCase();
|
|
147
|
+
if (args[0]?.getKind() === SyntaxKind.StringLiteral) {
|
|
148
|
+
path = args[0].asKind(SyntaxKind.StringLiteral).getLiteralValue();
|
|
164
149
|
}
|
|
165
150
|
}
|
|
166
151
|
}
|
|
@@ -174,7 +159,7 @@ function analyzeClassMethods(classNode, controllerPath, apiServices, content, ma
|
|
|
174
159
|
permissionValue,
|
|
175
160
|
apiModules,
|
|
176
161
|
apiServices,
|
|
177
|
-
method,
|
|
162
|
+
method: httpMethod,
|
|
178
163
|
path
|
|
179
164
|
});
|
|
180
165
|
}
|
package/dist/mcp-server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyphaene/hexa-ts-kit",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.2",
|
|
4
4
|
"description": "TypeScript dev kit for Claude Code agents: architecture linting, scaffolding, knowledge analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -47,8 +47,6 @@
|
|
|
47
47
|
"homepage": "https://github.com/hyphaene/hexa-ts-kit#readme",
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
50
|
-
"@typescript-eslint/parser": "^8.50.1",
|
|
51
|
-
"@typescript-eslint/typescript-estree": "^8.50.1",
|
|
52
50
|
"commander": "^12.1.0",
|
|
53
51
|
"fast-glob": "^3.3.2",
|
|
54
52
|
"gray-matter": "^4.0.3",
|
|
@@ -60,7 +58,6 @@
|
|
|
60
58
|
"picocolors": "^1.1.1",
|
|
61
59
|
"react": "^19.2.4",
|
|
62
60
|
"ts-morph": "^27.0.2",
|
|
63
|
-
"vue-eslint-parser": "^10.2.0",
|
|
64
61
|
"yaml": "^2.8.2",
|
|
65
62
|
"zod": "^4.3.4"
|
|
66
63
|
},
|