@hyphaene/hexa-ts-kit 1.12.0 → 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.
@@ -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 { parse } from "@typescript-eslint/typescript-estree";
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
- let ast;
1065
+ const project = new Project({
1066
+ useInMemoryFileSystem: true,
1067
+ skipAddingFilesFromTsConfig: true
1068
+ });
1069
+ let sourceFile;
1066
1070
  try {
1067
- ast = parse(content, {
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(ast, exportName, sourcePath);
1082
+ return extractConstValues(sourceFile, exportName, sourcePath);
1082
1083
  } else if (extractMode === "zod-keys") {
1083
- return extractZodKeys(ast, exportName, sourcePath);
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(ast, exportName, sourcePath) {
1092
+ function extractConstValues(sourceFile, exportName, sourcePath) {
1092
1093
  const values = [];
1093
1094
  const keyToValue = {};
1094
- for (const node of ast.body) {
1095
- if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
1096
- for (const declarator of node.declaration.declarations) {
1097
- if (declarator.id.type === "Identifier" && declarator.id.name === exportName && declarator.init) {
1098
- let objectExpr = null;
1099
- if (declarator.init.type === "TSAsExpression") {
1100
- const expr = declarator.init.expression;
1101
- if (expr.type === "ObjectExpression") {
1102
- objectExpr = expr;
1103
- }
1104
- } else if (declarator.init.type === "ObjectExpression") {
1105
- objectExpr = declarator.init;
1106
- }
1107
- if (objectExpr) {
1108
- for (const prop of objectExpr.properties) {
1109
- if (prop.type === "Property" && prop.value.type === "Literal" && typeof prop.value.value === "string") {
1110
- const value = prop.value.value;
1111
- values.push(value);
1112
- if (prop.key.type === "Identifier") {
1113
- keyToValue[prop.key.name] = value;
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(ast, exportName, sourcePath) {
1138
+ function extractZodKeys(sourceFile, exportName, sourcePath) {
1137
1139
  const values = [];
1138
- for (const node of ast.body) {
1139
- if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
1140
- for (const declarator of node.declaration.declarations) {
1141
- if (declarator.id.type === "Identifier" && declarator.id.name === exportName && declarator.init) {
1142
- const init = declarator.init;
1143
- if (init.type === "CallExpression" && init.callee.type === "MemberExpression" && init.callee.property.type === "Identifier" && init.callee.property.name === "object") {
1144
- const firstArg = init.arguments[0];
1145
- if (firstArg && firstArg.type === "ObjectExpression") {
1146
- for (const prop of firstArg.properties) {
1147
- if (prop.type === "Property" && prop.key.type === "Identifier") {
1148
- values.push(prop.key.name);
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 { parse as parse2 } from "@typescript-eslint/typescript-estree";
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
- let ast;
1205
+ const project = new Project2({
1206
+ useInMemoryFileSystem: true,
1207
+ skipAddingFilesFromTsConfig: true
1208
+ });
1209
+ let sourceFile;
1202
1210
  try {
1203
- ast = parse2(content, {
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 node of ast.body) {
1217
- if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
1218
- for (const declarator of node.declaration.declarations) {
1219
- if (declarator.id.type === "Identifier") {
1220
- contractName = declarator.id.name;
1221
- const routerCall = findRouterCall(declarator.init);
1222
- if (routerCall) {
1223
- const parsedEndpoints = extractEndpointsFromRouter(
1224
- routerCall,
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 findRouterCall(node) {
1268
+ function findRouterObjectArg(node) {
1269
1269
  if (!node) return null;
1270
- if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier" && node.callee.property.name === "router") {
1271
- return node;
1272
- }
1273
- return null;
1274
- }
1275
- function extractEndpointsFromRouter(routerCall, sourceContent) {
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 firstArg = routerCall.arguments[0];
1278
- if (!firstArg || firstArg.type !== "ObjectExpression") {
1279
- return endpoints;
1280
- }
1281
- const routerObject = firstArg;
1282
- for (const prop of routerObject.properties) {
1283
- if (prop.type !== "Property") continue;
1284
- if (prop.key.type !== "Identifier") continue;
1285
- const endpointName = prop.key.name;
1286
- const endpointLine = prop.loc?.start.line ?? 0;
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
- prop.value,
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, objectExpr, line, sourceContent) {
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 objectExpr.properties) {
1306
- if (prop.type !== "Property") continue;
1307
- if (prop.key.type !== "Identifier") continue;
1308
- const propName = prop.key.name;
1309
- if (propName === "method" && prop.value.type === "Literal") {
1310
- method = String(prop.value.value);
1311
- }
1312
- if (propName === "path" && prop.value.type === "Literal") {
1313
- path = String(prop.value.value);
1314
- }
1315
- if (propName === "metadata") {
1316
- if (prop.value.type === "ObjectExpression" || prop.value.type === "CallExpression") {
1317
- metadata = extractMetadata(prop.value, sourceContent);
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 === "strictStatusCodes" && prop.value.type === "Literal") {
1321
- strictStatusCodes = prop.value.value === true;
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, sourceContent) {
1334
- if (node.type === "ObjectExpression") {
1335
- return parseMetadataObject(node, sourceContent);
1336
- }
1337
- if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "contractMetadata") {
1338
- const firstArg = node.arguments[0];
1339
- if (firstArg && firstArg.type === "ObjectExpression") {
1340
- return parseMetadataObject(firstArg, sourceContent);
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(objectExpr, sourceContent) {
1361
+ function parseMetadataObject(objLiteral) {
1346
1362
  const metadata = {};
1347
- for (const prop of objectExpr.properties) {
1348
- if (prop.type !== "Property") continue;
1349
- if (prop.key.type !== "Identifier") continue;
1350
- const propName = prop.key.name;
1351
- if (propName === "openApiTags" && prop.value.type === "ArrayExpression") {
1352
- metadata.openApiTags = extractStringArray(prop.value);
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
- if (prop.value.type === "Literal" || prop.value.type === "MemberExpression") {
1356
- const permValue = extractPermissionValue(prop.value, sourceContent);
1357
- if (permValue) {
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" && prop.value.type === "Literal") {
1363
- metadata.requiresAuth = prop.value.value === true;
1381
+ if (propName === "requiresAuth") {
1382
+ metadata.requiresAuth = propVal.getKind() === SyntaxKind2.TrueKeyword;
1364
1383
  }
1365
- if (propName === "bff" && prop.value.type === "ObjectExpression") {
1366
- metadata.bff = extractBffConfig(prop.value);
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" && prop.value.type === "ObjectExpression") {
1369
- metadata.openapi = extractLegacyOpenApi(prop.value);
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.elements) {
1377
- if (element?.type === "Literal" && typeof element.value === "string") {
1378
- values.push(element.value);
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, sourceContent) {
1384
- if (node.type === "Literal" && typeof node.value === "string") {
1385
- return node.value;
1409
+ function extractPermissionValue(node) {
1410
+ const strLit = node.asKind(SyntaxKind2.StringLiteral);
1411
+ if (strLit) {
1412
+ return strLit.getLiteralValue();
1386
1413
  }
1387
- if (node.type === "MemberExpression") {
1388
- if (node.range) {
1389
- const [start, end] = node.range;
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(objectExpr) {
1420
+ function extractBffConfig(objLiteral) {
1396
1421
  const bff = {};
1397
- for (const prop of objectExpr.properties) {
1398
- if (prop.type !== "Property") continue;
1399
- if (prop.key.type !== "Identifier") continue;
1400
- if (prop.key.name === "apiServices" && prop.value.type === "ArrayExpression") {
1401
- bff.apiServices = [];
1402
- for (const element of prop.value.elements) {
1403
- if (element?.type === "Literal" && typeof element.value === "string") {
1404
- bff.apiServices.push(element.value);
1405
- }
1406
- if (element?.type === "MemberExpression") {
1407
- if (element.property.type === "Identifier") {
1408
- bff.apiServices.push(element.property.name);
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(objectExpr) {
1447
+ function extractLegacyOpenApi(objLiteral) {
1417
1448
  const openapi = {};
1418
- for (const prop of objectExpr.properties) {
1419
- if (prop.type !== "Property") continue;
1420
- if (prop.key.type !== "Identifier") continue;
1421
- if (prop.key.name === "tags" && prop.value.type === "ArrayExpression") {
1422
- openapi.tags = extractStringArray(prop.value);
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 { parse as parse3 } from "@typescript-eslint/typescript-estree";
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,8 +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 content = readFileSync4(filePath, "utf-8");
2415
- return parse3(content, { loc: true, range: true, comment: true, jsx: false });
2448
+ const project = new Project3({
2449
+ useInMemoryFileSystem: false,
2450
+ skipAddingFilesFromTsConfig: true
2451
+ });
2452
+ project.addSourceFileAtPath(filePath);
2453
+ return project.getSourceFileOrThrow(filePath);
2416
2454
  } catch {
2417
2455
  return null;
2418
2456
  }
@@ -2420,42 +2458,58 @@ function parseFile(filePath) {
2420
2458
  function readFileContent(filePath) {
2421
2459
  return readFileSync4(filePath, "utf-8");
2422
2460
  }
2423
- function getExportedNames(ast) {
2461
+ function getExportedNames(sourceFile) {
2424
2462
  const names = [];
2425
- for (const node of ast.body) {
2426
- if (node.type === "ExportNamedDeclaration") {
2427
- if (node.declaration) {
2428
- if (node.declaration.type === "VariableDeclaration") {
2429
- for (const decl of node.declaration.declarations) {
2430
- if (decl.id.type === "Identifier") {
2431
- names.push(decl.id.name);
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());
2432
2490
  }
2433
2491
  }
2434
2492
  }
2435
- if (node.declaration.type === "TSTypeAliasDeclaration") {
2436
- names.push(node.declaration.id.name);
2437
- }
2438
- if (node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
2439
- names.push(node.declaration.id.name);
2440
- }
2441
2493
  }
2442
- if (node.specifiers) {
2443
- for (const spec of node.specifiers) {
2444
- if (spec.exported.type === "Identifier") {
2445
- names.push(spec.exported.name);
2446
- }
2447
- }
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);
2448
2506
  }
2449
2507
  }
2450
2508
  }
2451
2509
  return names;
2452
2510
  }
2453
- function hasDefaultExport(ast) {
2454
- return ast.body.some(
2455
- (node) => node.type === "ExportDefaultDeclaration" || node.type === "ExportNamedDeclaration" && node.specifiers?.some(
2456
- (s) => s.exported.type === "Identifier" && s.exported.name === "default"
2457
- )
2458
- );
2511
+ function hasDefaultExport(sourceFile) {
2512
+ return sourceFile.getExportedDeclarations().has("default");
2459
2513
  }
2460
2514
  function hasOpenApiDocumentation(content) {
2461
2515
  return /\.describe\s*\(/.test(content) || /\.openapi\s*\(/.test(content);
@@ -2467,44 +2521,66 @@ function hasZodInferTypeExport(content) {
2467
2521
  return /export\s+type\s+\w+\s*=\s*z\.infer/.test(content);
2468
2522
  }
2469
2523
  function hasZodDataSchemas(content) {
2470
- return /(?:const|let|var)\s+\w+\s*=\s*z\.(?:object|enum|array)\s*\(/.test(content);
2524
+ return /(?:const|let|var)\s+\w+\s*=\s*z\.(?:object|enum|array)\s*\(/.test(
2525
+ content
2526
+ );
2471
2527
  }
2472
- function getExportsWithoutDeprecatedJsdoc(ast, content) {
2528
+ function getExportsWithoutDeprecatedJsdoc(sourceFile) {
2473
2529
  const missingDeprecated = [];
2474
- for (const node of ast.body) {
2475
- if (node.type !== "ExportNamedDeclaration" && node.type !== "ExportDefaultDeclaration") {
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) {
2476
2534
  continue;
2477
2535
  }
2478
- let exportName = "default";
2479
- if (node.type === "ExportNamedDeclaration") {
2480
- if (node.declaration) {
2481
- if (node.declaration.type === "VariableDeclaration") {
2482
- const decl = node.declaration.declarations[0];
2483
- if (decl?.id.type === "Identifier") {
2484
- exportName = decl.id.name;
2485
- }
2486
- } else if (node.declaration.type === "TSTypeAliasDeclaration" || node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
2487
- exportName = node.declaration.type === "TSTypeAliasDeclaration" ? node.declaration.id.name : node.declaration.id.name;
2488
- }
2536
+ if (kind === SyntaxKind3.ExportAssignment) {
2537
+ if (!hasDeprecatedComment(statement)) {
2538
+ missingDeprecated.push("default");
2489
2539
  }
2490
- if (node.source) continue;
2540
+ continue;
2491
2541
  }
2492
- const linesBefore = content.substring(0, node.range?.[0] ?? 0);
2493
- const lastCommentBlock = linesBefore.match(/\/\*\*[\s\S]*?\*\/\s*$/);
2494
- if (!lastCommentBlock || !lastCommentBlock[0].includes("@deprecated")) {
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();
2555
+ }
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";
2564
+ }
2565
+ if (!hasDeprecatedComment(statement)) {
2495
2566
  missingDeprecated.push(exportName);
2496
2567
  }
2497
2568
  }
2498
2569
  return missingDeprecated;
2499
2570
  }
2500
- function getNonReexportStatements(ast) {
2571
+ function hasDeprecatedComment(node) {
2572
+ return node.getLeadingCommentRanges().some((comment) => comment.getText().includes("@deprecated"));
2573
+ }
2574
+ function getNonReexportStatements(sourceFile) {
2501
2575
  const violations = [];
2502
- for (const node of ast.body) {
2503
- if (node.type === "ImportDeclaration") continue;
2504
- if (node.type === "ExportAllDeclaration") continue;
2505
- if (node.type === "ExportNamedDeclaration" && node.source) continue;
2506
- if (node.type === "ExportNamedDeclaration" && node.exportKind === "type" && node.source) continue;
2507
- violations.push(node);
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);
2508
2584
  }
2509
2585
  return violations;
2510
2586
  }
@@ -2517,13 +2593,15 @@ async function checkEnumBundleRules(cwd) {
2517
2593
  for (const file of files) {
2518
2594
  const fullPath = `${cwd}/${file}`;
2519
2595
  const content = readFileContent(fullPath);
2520
- const ast = parseFile(fullPath);
2521
- if (!ast) continue;
2522
- const exportedNames = getExportedNames(ast);
2596
+ const sourceFile = parseFile(fullPath);
2597
+ if (!sourceFile) continue;
2598
+ const exportedNames = getExportedNames(sourceFile);
2523
2599
  const fileName = basename5(file, ".enum-bundle.ts");
2524
2600
  const upperName = fileName.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
2525
2601
  const hasSchema = exportedNames.some((n) => n.endsWith("Schema"));
2526
- const hasEnumMapper = exportedNames.some((n) => n === n.toUpperCase() && n.length > 1);
2602
+ const hasEnumMapper = exportedNames.some(
2603
+ (n) => n === n.toUpperCase() && n.length > 1
2604
+ );
2527
2605
  const hasValues = exportedNames.some((n) => n.endsWith("_VALUES"));
2528
2606
  if (!hasSchema || !hasEnumMapper || !hasValues) {
2529
2607
  const missing = [];
@@ -2568,9 +2646,9 @@ async function checkResponseRules(cwd) {
2568
2646
  for (const file of files) {
2569
2647
  const fullPath = `${cwd}/${file}`;
2570
2648
  const content = readFileContent(fullPath);
2571
- const ast = parseFile(fullPath);
2572
- if (!ast) continue;
2573
- const exportedNames = getExportedNames(ast);
2649
+ const sourceFile = parseFile(fullPath);
2650
+ if (!sourceFile) continue;
2651
+ const exportedNames = getExportedNames(sourceFile);
2574
2652
  const fileName = basename5(file, ".response.ts");
2575
2653
  const httpCode = fileName.match(/^(\d{3})$/)?.[1];
2576
2654
  if (httpCode) {
@@ -2584,7 +2662,7 @@ async function checkResponseRules(cwd) {
2584
2662
  });
2585
2663
  }
2586
2664
  }
2587
- if (!hasDefaultExport(ast)) {
2665
+ if (!hasDefaultExport(sourceFile)) {
2588
2666
  results.push({
2589
2667
  ruleId: "CTR-RESPONSE-002",
2590
2668
  severity: "error",
@@ -2614,9 +2692,9 @@ async function checkRequestRules(cwd) {
2614
2692
  for (const file of files) {
2615
2693
  const fullPath = `${cwd}/${file}`;
2616
2694
  const content = readFileContent(fullPath);
2617
- const ast = parseFile(fullPath);
2618
- if (!ast) continue;
2619
- const exportedNames = getExportedNames(ast);
2695
+ const sourceFile = parseFile(fullPath);
2696
+ if (!sourceFile) continue;
2697
+ const exportedNames = getExportedNames(sourceFile);
2620
2698
  const hasTypedSchema = exportedNames.some(
2621
2699
  (n) => /(Query|Body|Headers|Params)Schema$/.test(n)
2622
2700
  );
@@ -2650,9 +2728,9 @@ async function checkContractFileRules(cwd) {
2650
2728
  for (const file of files) {
2651
2729
  const fullPath = `${cwd}/${file}`;
2652
2730
  const content = readFileContent(fullPath);
2653
- const ast = parseFile(fullPath);
2654
- if (!ast) continue;
2655
- const exportedNames = getExportedNames(ast);
2731
+ const sourceFile = parseFile(fullPath);
2732
+ if (!sourceFile) continue;
2733
+ const exportedNames = getExportedNames(sourceFile);
2656
2734
  const hasContractExport = exportedNames.some((n) => n.endsWith("Contract"));
2657
2735
  if (!hasContractExport) {
2658
2736
  results.push({
@@ -2692,16 +2770,16 @@ async function checkIndexRules(cwd) {
2692
2770
  });
2693
2771
  for (const file of files) {
2694
2772
  const fullPath = `${cwd}/${file}`;
2695
- const ast = parseFile(fullPath);
2696
- if (!ast) continue;
2697
- const violations = getNonReexportStatements(ast);
2773
+ const sourceFile = parseFile(fullPath);
2774
+ if (!sourceFile) continue;
2775
+ const violations = getNonReexportStatements(sourceFile);
2698
2776
  if (violations.length > 0) {
2699
2777
  results.push({
2700
2778
  ruleId: "CTR-INDEX-001",
2701
2779
  severity: "error",
2702
2780
  message: `Index file ${file} contains ${violations.length} non-reexport statement(s)`,
2703
2781
  file,
2704
- line: violations[0]?.loc?.start.line,
2782
+ line: violations[0]?.getStartLineNumber(),
2705
2783
  suggestion: "Index files should only contain: export * from '...' or export { X } from '...'"
2706
2784
  });
2707
2785
  }
@@ -2733,12 +2811,19 @@ async function checkNamingRules(cwd) {
2733
2811
  const results = [];
2734
2812
  const files = await fg9("src/**/*.ts", {
2735
2813
  cwd,
2736
- ignore: ["**/node_modules/**", "**/dist/**", "**/lib/**", "**/__tests__/**"]
2814
+ ignore: [
2815
+ "**/node_modules/**",
2816
+ "**/dist/**",
2817
+ "**/lib/**",
2818
+ "**/__tests__/**"
2819
+ ]
2737
2820
  });
2738
2821
  for (const file of files) {
2739
2822
  const fileName = basename5(file);
2740
2823
  if (ALLOWED_SPECIAL_FILES.includes(fileName)) continue;
2741
- const matchesSuffix = ALLOWED_SUFFIXES.some((suffix) => fileName.endsWith(suffix));
2824
+ const matchesSuffix = ALLOWED_SUFFIXES.some(
2825
+ (suffix) => fileName.endsWith(suffix)
2826
+ );
2742
2827
  if (!matchesSuffix) {
2743
2828
  results.push({
2744
2829
  ruleId: "CTR-NAMING-001",
@@ -2759,10 +2844,9 @@ async function checkDeprecatedRules(cwd) {
2759
2844
  });
2760
2845
  for (const file of files) {
2761
2846
  const fullPath = `${cwd}/${file}`;
2762
- const content = readFileContent(fullPath);
2763
- const ast = parseFile(fullPath);
2764
- if (!ast) continue;
2765
- const missing = getExportsWithoutDeprecatedJsdoc(ast, content);
2847
+ const sourceFile = parseFile(fullPath);
2848
+ if (!sourceFile) continue;
2849
+ const missing = getExportsWithoutDeprecatedJsdoc(sourceFile);
2766
2850
  if (missing.length > 0) {
2767
2851
  results.push({
2768
2852
  ruleId: "CTR-DEPRECATED-001",
@@ -2925,7 +3009,7 @@ var contractsChecker = {
2925
3009
  // src/lint/checkers/vault/index.ts
2926
3010
  import { existsSync as existsSync5, readdirSync } from "fs";
2927
3011
  import { join as join3, dirname as dirname4 } from "path";
2928
- import { Project, SyntaxKind } from "ts-morph";
3012
+ import { Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
2929
3013
  var VAULT_PATHS = [
2930
3014
  "src/common/config/vault",
2931
3015
  "server/vault",
@@ -2954,7 +3038,7 @@ function isInsideZodObject(node) {
2954
3038
  if (!node) return false;
2955
3039
  let current = node;
2956
3040
  while (current) {
2957
- if (current.getKind() === SyntaxKind.CallExpression) {
3041
+ if (current.getKind() === SyntaxKind4.CallExpression) {
2958
3042
  const text = current.getText();
2959
3043
  if (text.startsWith("z.object(")) return true;
2960
3044
  }
@@ -2966,7 +3050,7 @@ function checkAstPatterns(sourceFile) {
2966
3050
  const results = [];
2967
3051
  const filePath = sourceFile.getFilePath();
2968
3052
  sourceFile.forEachDescendant((node) => {
2969
- if (node.getKind() === SyntaxKind.CallExpression) {
3053
+ if (node.getKind() === SyntaxKind4.CallExpression) {
2970
3054
  const text = node.getText();
2971
3055
  if (text.startsWith("z.lazy(")) {
2972
3056
  results.push({
@@ -2978,11 +3062,11 @@ function checkAstPatterns(sourceFile) {
2978
3062
  });
2979
3063
  }
2980
3064
  if (text.startsWith("z.enum(")) {
2981
- const callExpr = node.asKind(SyntaxKind.CallExpression);
3065
+ const callExpr = node.asKind(SyntaxKind4.CallExpression);
2982
3066
  const args = callExpr?.getArguments();
2983
3067
  if (args && args.length > 0) {
2984
3068
  const firstArg = args[0];
2985
- if (firstArg?.getKind() === SyntaxKind.Identifier) {
3069
+ if (firstArg?.getKind() === SyntaxKind4.Identifier) {
2986
3070
  results.push({
2987
3071
  ruleId: "VAULT-AST-004",
2988
3072
  severity: getRuleSeverity("VAULT-AST-004"),
@@ -2995,11 +3079,11 @@ function checkAstPatterns(sourceFile) {
2995
3079
  }
2996
3080
  }
2997
3081
  if (text.startsWith("z.object(")) {
2998
- const callExpr = node.asKind(SyntaxKind.CallExpression);
3082
+ const callExpr = node.asKind(SyntaxKind4.CallExpression);
2999
3083
  const args = callExpr?.getArguments();
3000
3084
  if (args && args.length > 0) {
3001
3085
  const firstArg = args[0];
3002
- if (firstArg?.getKind() === SyntaxKind.Identifier) {
3086
+ if (firstArg?.getKind() === SyntaxKind4.Identifier) {
3003
3087
  results.push({
3004
3088
  ruleId: "VAULT-AST-006",
3005
3089
  severity: getRuleSeverity("VAULT-AST-006"),
@@ -3011,11 +3095,11 @@ function checkAstPatterns(sourceFile) {
3011
3095
  }
3012
3096
  }
3013
3097
  }
3014
- if (node.getKind() === SyntaxKind.SpreadAssignment) {
3098
+ if (node.getKind() === SyntaxKind4.SpreadAssignment) {
3015
3099
  if (isInsideZodObject(node)) {
3016
- const spreadExpr = node.asKind(SyntaxKind.SpreadAssignment);
3100
+ const spreadExpr = node.asKind(SyntaxKind4.SpreadAssignment);
3017
3101
  const expr = spreadExpr?.getExpression();
3018
- if (expr?.getKind() === SyntaxKind.ConditionalExpression || expr?.getKind() === SyntaxKind.Identifier) {
3102
+ if (expr?.getKind() === SyntaxKind4.ConditionalExpression || expr?.getKind() === SyntaxKind4.Identifier) {
3019
3103
  results.push({
3020
3104
  ruleId: "VAULT-AST-002",
3021
3105
  severity: getRuleSeverity("VAULT-AST-002"),
@@ -3026,8 +3110,8 @@ function checkAstPatterns(sourceFile) {
3026
3110
  }
3027
3111
  }
3028
3112
  }
3029
- if (node.getKind() === SyntaxKind.FunctionDeclaration || node.getKind() === SyntaxKind.ArrowFunction) {
3030
- const funcNode = node.asKind(SyntaxKind.FunctionDeclaration) || node.asKind(SyntaxKind.ArrowFunction);
3113
+ if (node.getKind() === SyntaxKind4.FunctionDeclaration || node.getKind() === SyntaxKind4.ArrowFunction) {
3114
+ const funcNode = node.asKind(SyntaxKind4.FunctionDeclaration) || node.asKind(SyntaxKind4.ArrowFunction);
3031
3115
  if (funcNode) {
3032
3116
  const body = funcNode.getBody();
3033
3117
  if (body) {
@@ -3059,7 +3143,7 @@ var vaultChecker = {
3059
3143
  }
3060
3144
  const configResult = loadConfig(ctx.cwd);
3061
3145
  const disabledRules = configResult.success ? getDisabledVaultRules(configResult.config) : [];
3062
- const project = new Project({
3146
+ const project = new Project4({
3063
3147
  skipAddingFilesFromTsConfig: true,
3064
3148
  skipFileDependencyResolution: true
3065
3149
  });
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  lintCommand,
6
6
  loadConfig,
7
7
  scaffoldCommand
8
- } from "./chunk-TGZA3GHG.js";
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 { parse } from "@typescript-eslint/typescript-estree";
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
- let ast;
108
+ const project = new Project({ skipAddingFilesFromTsConfig: true });
109
+ let sourceFile;
110
110
  try {
111
- ast = parse(content, { loc: true, range: true, comment: true });
111
+ sourceFile = project.addSourceFileAtPath(controllerPath);
112
112
  } catch {
113
113
  return mappings;
114
114
  }
115
- for (const node of ast.body) {
116
- if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "ClassDeclaration") {
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(classNode, controllerPath, apiServices, content, mappings) {
133
- for (const member of classNode.body.body) {
134
- if (member.type !== "MethodDefinition") continue;
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 method = null;
125
+ let httpMethod = null;
141
126
  let path = null;
142
127
  let contractEndpointName = null;
143
- for (const decorator of decorators) {
144
- if (decorator.expression.type === "CallExpression") {
145
- const callee = decorator.expression.callee;
146
- if (callee.type === "Identifier" && callee.name === "TsRestHandler") {
147
- const arg = decorator.expression.arguments[0];
148
- if (arg?.type === "MemberExpression" && arg.property.type === "Identifier") {
149
- contractEndpointName = arg.property.name;
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
- if (callee.type === "Identifier" && callee.name === "Authorize") {
153
- const arg = decorator.expression.arguments[0];
154
- if (arg?.type === "MemberExpression" && arg.property.type === "Identifier") {
155
- permission = arg.property.name;
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
- if (callee.type === "Identifier" && ["Get", "Post", "Put", "Patch", "Delete"].includes(callee.name)) {
159
- method = callee.name.toUpperCase();
160
- const arg = decorator.expression.arguments[0];
161
- if (arg?.type === "Literal" && typeof arg.value === "string") {
162
- path = arg.value;
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
  }
@@ -3,7 +3,7 @@ import {
3
3
  analyzeCore,
4
4
  lintCore,
5
5
  scaffoldCore
6
- } from "./chunk-TGZA3GHG.js";
6
+ } from "./chunk-4LVIIP2D.js";
7
7
 
8
8
  // src/mcp-server.ts
9
9
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyphaene/hexa-ts-kit",
3
- "version": "1.12.0",
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
  },