@aiready/core 0.21.16 → 0.21.18

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 CHANGED
@@ -124,8 +124,10 @@ __export(index_exports, {
124
124
  getSeverityColor: () => getSeverityColor,
125
125
  getSupportedLanguages: () => getSupportedLanguages,
126
126
  getToolWeight: () => getToolWeight,
127
+ getWasmPath: () => getWasmPath,
127
128
  handleCLIError: () => handleCLIError,
128
129
  handleJSONOutput: () => handleJSONOutput,
130
+ initTreeSitter: () => initTreeSitter,
129
131
  initializeParsers: () => initializeParsers,
130
132
  isFileSupported: () => isFileSupported,
131
133
  isSourceFile: () => isSourceFile,
@@ -143,6 +145,7 @@ __export(index_exports, {
143
145
  saveScoreEntry: () => saveScoreEntry,
144
146
  scanEntries: () => scanEntries,
145
147
  scanFiles: () => scanFiles,
148
+ setupParser: () => setupParser,
146
149
  validateSpokeOutput: () => validateSpokeOutput,
147
150
  validateWithSchema: () => validateWithSchema
148
151
  });
@@ -336,15 +339,15 @@ var COMMON_FINE_TUNING_OPTIONS = [
336
339
  var GLOBAL_SCAN_OPTIONS = [...GLOBAL_INFRA_OPTIONS];
337
340
 
338
341
  // src/types/language.ts
339
- var Language = /* @__PURE__ */ ((Language6) => {
340
- Language6["TypeScript"] = "typescript";
341
- Language6["JavaScript"] = "javascript";
342
- Language6["Python"] = "python";
343
- Language6["Java"] = "java";
344
- Language6["Go"] = "go";
345
- Language6["Rust"] = "rust";
346
- Language6["CSharp"] = "csharp";
347
- return Language6;
342
+ var Language = /* @__PURE__ */ ((Language3) => {
343
+ Language3["TypeScript"] = "typescript";
344
+ Language3["JavaScript"] = "javascript";
345
+ Language3["Python"] = "python";
346
+ Language3["Java"] = "java";
347
+ Language3["Go"] = "go";
348
+ Language3["Rust"] = "rust";
349
+ Language3["CSharp"] = "csharp";
350
+ return Language3;
348
351
  })(Language || {});
349
352
  var LANGUAGE_EXTENSIONS = {
350
353
  ".ts": "typescript" /* TypeScript */,
@@ -804,6 +807,86 @@ var TypeScriptParser = class {
804
807
  async initialize() {
805
808
  return Promise.resolve();
806
809
  }
810
+ async getAST(code, filePath) {
811
+ return (0, import_typescript_estree.parse)(code, {
812
+ loc: true,
813
+ range: true,
814
+ jsx: filePath.match(/\.[jt]sx$/i) !== null,
815
+ filePath,
816
+ sourceType: "module",
817
+ ecmaVersion: "latest",
818
+ comment: true
819
+ });
820
+ }
821
+ analyzeMetadata(node, code) {
822
+ const metadata = {
823
+ isPure: true,
824
+ hasSideEffects: false
825
+ };
826
+ const start = node.range?.[0] ?? 0;
827
+ const preceding = code.slice(Math.max(0, start - 200), start);
828
+ const jsdocMatches = Array.from(
829
+ preceding.matchAll(/\/\*\*([\s\S]*?)\*\//g)
830
+ );
831
+ if (jsdocMatches.length > 0) {
832
+ const lastMatch = jsdocMatches[jsdocMatches.length - 1];
833
+ const matchEndIndex = (lastMatch.index || 0) + lastMatch[0].length;
834
+ const between = preceding.slice(matchEndIndex);
835
+ if (/^\s*$/.test(between)) {
836
+ metadata.documentation = {
837
+ content: lastMatch[1].replace(/^\s*\*+/gm, "").trim(),
838
+ type: "jsdoc"
839
+ };
840
+ }
841
+ }
842
+ const walk = (n) => {
843
+ if (!n) return;
844
+ if (n.type === "AssignmentExpression") {
845
+ metadata.isPure = false;
846
+ metadata.hasSideEffects = true;
847
+ }
848
+ if (n.type === "UpdateExpression") {
849
+ metadata.isPure = false;
850
+ metadata.hasSideEffects = true;
851
+ }
852
+ if (n.type === "CallExpression" && n.callee.type === "MemberExpression" && n.callee.object.type === "Identifier") {
853
+ const objName = n.callee.object.name;
854
+ if (["console", "process", "fs", "window", "document"].includes(objName)) {
855
+ metadata.isPure = false;
856
+ metadata.hasSideEffects = true;
857
+ }
858
+ }
859
+ if (n.type === "ThrowStatement") {
860
+ metadata.isPure = false;
861
+ metadata.hasSideEffects = true;
862
+ }
863
+ for (const key of Object.keys(n)) {
864
+ if (key === "parent") continue;
865
+ const child = n[key];
866
+ if (child && typeof child === "object") {
867
+ if (Array.isArray(child)) {
868
+ child.forEach((c) => c?.type && walk(c));
869
+ } else if (child.type) {
870
+ walk(child);
871
+ }
872
+ }
873
+ }
874
+ };
875
+ let nodeToAnalyze = node;
876
+ if (node.type === "ExportNamedDeclaration" && node.declaration) {
877
+ nodeToAnalyze = node.declaration;
878
+ } else if (node.type === "ExportDefaultDeclaration" && node.declaration) {
879
+ if (node.declaration.type !== "TSInterfaceDeclaration" && node.declaration.type !== "TSTypeAliasDeclaration") {
880
+ nodeToAnalyze = node.declaration;
881
+ }
882
+ }
883
+ if (nodeToAnalyze.type === "FunctionDeclaration" || nodeToAnalyze.type === "FunctionExpression" || nodeToAnalyze.type === "ArrowFunctionExpression") {
884
+ if (nodeToAnalyze.body) walk(nodeToAnalyze.body);
885
+ } else if (nodeToAnalyze.type === "ClassDeclaration" || nodeToAnalyze.type === "ClassExpression") {
886
+ walk(nodeToAnalyze.body);
887
+ }
888
+ return metadata;
889
+ }
807
890
  parse(code, filePath) {
808
891
  try {
809
892
  const isJavaScript = filePath.match(/\.jsx?$/i);
@@ -813,10 +896,11 @@ var TypeScriptParser = class {
813
896
  jsx: filePath.match(/\.[jt]sx$/i) !== null,
814
897
  filePath,
815
898
  sourceType: "module",
816
- ecmaVersion: "latest"
899
+ ecmaVersion: "latest",
900
+ comment: true
817
901
  });
818
902
  const imports = this.extractImports(ast);
819
- const exports2 = this.extractExports(ast, imports);
903
+ const exports2 = this.extractExports(ast, imports, code);
820
904
  return {
821
905
  exports: exports2,
822
906
  imports,
@@ -883,7 +967,7 @@ var TypeScriptParser = class {
883
967
  }
884
968
  return imports;
885
969
  }
886
- extractExports(ast, imports) {
970
+ extractExports(ast, imports, code) {
887
971
  const exports2 = [];
888
972
  const importedNames = new Set(
889
973
  imports.flatMap(
@@ -894,10 +978,14 @@ var TypeScriptParser = class {
894
978
  if (node.type === "ExportNamedDeclaration" && node.declaration) {
895
979
  const extracted = this.extractFromDeclaration(
896
980
  node.declaration,
897
- importedNames
981
+ importedNames,
982
+ code,
983
+ node
984
+ // Pass the ExportNamedDeclaration as parent for metadata
898
985
  );
899
986
  exports2.push(...extracted);
900
987
  } else if (node.type === "ExportDefaultDeclaration") {
988
+ const metadata = this.analyzeMetadata(node, code);
901
989
  let name = "default";
902
990
  let type = "default";
903
991
  if (node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
@@ -916,21 +1004,28 @@ var TypeScriptParser = class {
916
1004
  column: node.loc.start.column
917
1005
  },
918
1006
  end: { line: node.loc.end.line, column: node.loc.end.column }
919
- } : void 0
1007
+ } : void 0,
1008
+ ...metadata
920
1009
  });
921
1010
  }
922
1011
  }
923
1012
  return exports2;
924
1013
  }
925
- extractFromDeclaration(declaration, importedNames) {
1014
+ extractFromDeclaration(declaration, importedNames, code, parentNode) {
926
1015
  const exports2 = [];
1016
+ const metadata = this.analyzeMetadata(parentNode || declaration, code);
927
1017
  if (declaration.type === "FunctionDeclaration" && declaration.id) {
928
1018
  exports2.push({
929
1019
  name: declaration.id.name,
930
1020
  type: "function",
931
- parameters: declaration.params.map(
932
- (p) => p.type === "Identifier" ? p.name : "unknown"
933
- ),
1021
+ parameters: declaration.params.map((p) => {
1022
+ if (p.type === "Identifier") return p.name;
1023
+ if (p.type === "AssignmentPattern" && p.left.type === "Identifier")
1024
+ return p.left.name;
1025
+ if (p.type === "RestElement" && p.argument.type === "Identifier")
1026
+ return p.argument.name;
1027
+ return "unknown";
1028
+ }),
934
1029
  loc: declaration.loc ? {
935
1030
  start: {
936
1031
  line: declaration.loc.start.line,
@@ -940,12 +1035,18 @@ var TypeScriptParser = class {
940
1035
  line: declaration.loc.end.line,
941
1036
  column: declaration.loc.end.column
942
1037
  }
943
- } : void 0
1038
+ } : void 0,
1039
+ ...metadata
944
1040
  });
945
1041
  } else if (declaration.type === "ClassDeclaration" && declaration.id) {
1042
+ const body = declaration.body.body;
1043
+ const methods = body.filter((m) => m.type === "MethodDefinition");
1044
+ const properties = body.filter((m) => m.type === "PropertyDefinition");
946
1045
  exports2.push({
947
1046
  name: declaration.id.name,
948
1047
  type: "class",
1048
+ methodCount: methods.length,
1049
+ propertyCount: properties.length,
949
1050
  loc: declaration.loc ? {
950
1051
  start: {
951
1052
  line: declaration.loc.start.line,
@@ -955,7 +1056,8 @@ var TypeScriptParser = class {
955
1056
  line: declaration.loc.end.line,
956
1057
  column: declaration.loc.end.column
957
1058
  }
958
- } : void 0
1059
+ } : void 0,
1060
+ ...metadata
959
1061
  });
960
1062
  } else if (declaration.type === "VariableDeclaration") {
961
1063
  for (const declarator of declaration.declarations) {
@@ -972,7 +1074,8 @@ var TypeScriptParser = class {
972
1074
  line: declarator.loc.end.line,
973
1075
  column: declarator.loc.end.column
974
1076
  }
975
- } : void 0
1077
+ } : void 0,
1078
+ ...metadata
976
1079
  });
977
1080
  }
978
1081
  }
@@ -989,12 +1092,19 @@ var TypeScriptParser = class {
989
1092
  line: declaration.loc.end.line,
990
1093
  column: declaration.loc.end.column
991
1094
  }
992
- } : void 0
1095
+ } : void 0,
1096
+ ...metadata
993
1097
  });
994
1098
  } else if (declaration.type === "TSInterfaceDeclaration") {
1099
+ const body = declaration.body.body;
1100
+ const methods = body.filter((m) => m.type === "TSMethodSignature");
1101
+ const properties = body.filter((m) => m.type === "TSPropertySignature");
995
1102
  exports2.push({
996
1103
  name: declaration.id.name,
997
1104
  type: "interface",
1105
+ methodCount: methods.length,
1106
+ propertyCount: properties.length || body.length,
1107
+ // Fallback to body.length
998
1108
  loc: declaration.loc ? {
999
1109
  start: {
1000
1110
  line: declaration.loc.start.line,
@@ -1004,17 +1114,103 @@ var TypeScriptParser = class {
1004
1114
  line: declaration.loc.end.line,
1005
1115
  column: declaration.loc.end.column
1006
1116
  }
1007
- } : void 0
1117
+ } : void 0,
1118
+ ...metadata
1008
1119
  });
1009
1120
  }
1010
1121
  return exports2;
1011
1122
  }
1012
1123
  };
1013
1124
 
1014
- // src/parsers/python-parser.ts
1125
+ // src/parsers/tree-sitter-utils.ts
1015
1126
  var Parser = __toESM(require("web-tree-sitter"));
1016
1127
  var path = __toESM(require("path"));
1017
1128
  var fs = __toESM(require("fs"));
1129
+ var isTreeSitterInitialized = false;
1130
+ async function initTreeSitter() {
1131
+ if (isTreeSitterInitialized) return;
1132
+ try {
1133
+ const wasmPath = getWasmPath("web-tree-sitter");
1134
+ await Parser.Parser.init({
1135
+ locateFile() {
1136
+ return wasmPath || "web-tree-sitter.wasm";
1137
+ }
1138
+ });
1139
+ isTreeSitterInitialized = true;
1140
+ } catch (error) {
1141
+ console.error("Failed to initialize web-tree-sitter:", error);
1142
+ isTreeSitterInitialized = true;
1143
+ }
1144
+ }
1145
+ function findInPnpmStore(startDir, fileName, depth = 0) {
1146
+ if (depth > 8) return null;
1147
+ const pnpmDir = path.join(startDir, "node_modules", ".pnpm");
1148
+ if (fs.existsSync(pnpmDir)) {
1149
+ return findFileRecursively(pnpmDir, fileName, 0);
1150
+ }
1151
+ const parent = path.dirname(startDir);
1152
+ if (parent === startDir) return null;
1153
+ return findInPnpmStore(parent, fileName, depth + 1);
1154
+ }
1155
+ function findFileRecursively(dir, fileName, depth) {
1156
+ if (depth > 6) return null;
1157
+ try {
1158
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
1159
+ for (const entry of entries) {
1160
+ if (entry.isFile() && entry.name === fileName) {
1161
+ return path.join(dir, entry.name);
1162
+ }
1163
+ }
1164
+ for (const entry of entries) {
1165
+ if (entry.isDirectory()) {
1166
+ const found = findFileRecursively(
1167
+ path.join(dir, entry.name),
1168
+ fileName,
1169
+ depth + 1
1170
+ );
1171
+ if (found) return found;
1172
+ }
1173
+ }
1174
+ } catch (err) {
1175
+ }
1176
+ return null;
1177
+ }
1178
+ function getWasmPath(language) {
1179
+ const wasmFileName = language === "web-tree-sitter" ? "web-tree-sitter.wasm" : `tree-sitter-${language}.wasm`;
1180
+ const immediatePaths = [
1181
+ path.join(process.cwd(), wasmFileName),
1182
+ path.join(__dirname, wasmFileName),
1183
+ path.join(__dirname, "assets", wasmFileName)
1184
+ ];
1185
+ for (const p of immediatePaths) {
1186
+ if (fs.existsSync(p)) return p;
1187
+ }
1188
+ const pnpmPath = findInPnpmStore(__dirname, wasmFileName);
1189
+ if (pnpmPath) return pnpmPath;
1190
+ const pnpmPathCwd = findInPnpmStore(process.cwd(), wasmFileName);
1191
+ if (pnpmPathCwd) return pnpmPathCwd;
1192
+ console.warn(
1193
+ `[Parser] WASM file for ${language} not found. CWD: ${process.cwd()}, DIR: ${__dirname}`
1194
+ );
1195
+ return null;
1196
+ }
1197
+ async function setupParser(language) {
1198
+ await initTreeSitter();
1199
+ const wasmPath = getWasmPath(language);
1200
+ if (!wasmPath) {
1201
+ return null;
1202
+ }
1203
+ try {
1204
+ const parser = new Parser.Parser();
1205
+ const Lang = await Parser.Language.load(wasmPath);
1206
+ parser.setLanguage(Lang);
1207
+ return parser;
1208
+ } catch (error) {
1209
+ return null;
1210
+ }
1211
+ }
1212
+
1213
+ // src/parsers/python-parser.ts
1018
1214
  var PythonParser = class {
1019
1215
  constructor() {
1020
1216
  this.language = "python" /* Python */;
@@ -1027,53 +1223,47 @@ var PythonParser = class {
1027
1223
  */
1028
1224
  async initialize() {
1029
1225
  if (this.initialized) return;
1030
- try {
1031
- await Parser.Parser.init();
1032
- this.parser = new Parser.Parser();
1033
- const possiblePaths = [
1034
- path.join(
1035
- process.cwd(),
1036
- "node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-python.wasm"
1037
- ),
1038
- path.join(
1039
- __dirname,
1040
- "../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-python.wasm"
1041
- ),
1042
- path.join(
1043
- __dirname,
1044
- "../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-python.wasm"
1045
- ),
1046
- path.join(
1047
- __dirname,
1048
- "../../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-python.wasm"
1049
- ),
1050
- path.join(
1051
- process.cwd(),
1052
- "node_modules/tree-sitter-wasms/out/tree-sitter-python.wasm"
1053
- ),
1054
- path.join(__dirname, "../assets/tree-sitter-python.wasm")
1055
- ];
1056
- let wasmPath = "";
1057
- for (const p of possiblePaths) {
1058
- if (fs.existsSync(p)) {
1059
- wasmPath = p;
1060
- break;
1226
+ this.parser = await setupParser("python");
1227
+ this.initialized = true;
1228
+ }
1229
+ async getAST(code, filePath) {
1230
+ if (!this.initialized) await this.initialize();
1231
+ if (!this.parser) return null;
1232
+ return this.parser.parse(code);
1233
+ }
1234
+ analyzeMetadata(node, code) {
1235
+ const metadata = {
1236
+ isPure: true,
1237
+ hasSideEffects: false
1238
+ };
1239
+ const body = node.childForFieldName("body");
1240
+ if (body && body.children.length > 0) {
1241
+ const firstStmt = body.children[0];
1242
+ if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
1243
+ metadata.documentation = {
1244
+ content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
1245
+ type: "docstring"
1246
+ };
1247
+ }
1248
+ }
1249
+ const walk = (n) => {
1250
+ if (n.type === "global_statement" || n.type === "nonlocal_statement") {
1251
+ metadata.isPure = false;
1252
+ metadata.hasSideEffects = true;
1253
+ }
1254
+ if (n.type === "call") {
1255
+ const functionNode = n.childForFieldName("function");
1256
+ if (functionNode && ["print", "input", "open"].includes(functionNode.text)) {
1257
+ metadata.isPure = false;
1258
+ metadata.hasSideEffects = true;
1061
1259
  }
1062
1260
  }
1063
- if (!wasmPath) {
1064
- console.warn(
1065
- "Python WASM not found in common locations, attempting fallback regex parser"
1066
- );
1067
- return;
1261
+ for (const child of n.children) {
1262
+ walk(child);
1068
1263
  }
1069
- const Python = await Parser.Language.load(wasmPath);
1070
- this.parser.setLanguage(Python);
1071
- this.initialized = true;
1072
- } catch (error) {
1073
- console.error(
1074
- `Failed to initialize tree-sitter-python: ${error.message}`
1075
- );
1076
- }
1264
+ };
1265
+ if (body) walk(body);
1266
+ return metadata;
1077
1267
  }
1078
1268
  parse(code, filePath) {
1079
1269
  if (!this.initialized || !this.parser) {
@@ -1081,10 +1271,12 @@ var PythonParser = class {
1081
1271
  }
1082
1272
  try {
1083
1273
  const tree = this.parser.parse(code);
1084
- if (!tree) throw new Error("Parser.parse(code) returned null");
1274
+ if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
1275
+ return this.parseRegex(code, filePath);
1276
+ }
1085
1277
  const rootNode = tree.rootNode;
1086
1278
  const imports = this.extractImportsAST(rootNode);
1087
- const exports2 = this.extractExportsAST(rootNode);
1279
+ const exports2 = this.extractExportsAST(rootNode, code);
1088
1280
  return {
1089
1281
  exports: exports2,
1090
1282
  imports,
@@ -1092,9 +1284,6 @@ var PythonParser = class {
1092
1284
  warnings: []
1093
1285
  };
1094
1286
  } catch (error) {
1095
- console.warn(
1096
- `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1097
- );
1098
1287
  return this.parseRegex(code, filePath);
1099
1288
  }
1100
1289
  }
@@ -1179,7 +1368,7 @@ var PythonParser = class {
1179
1368
  }
1180
1369
  return imports;
1181
1370
  }
1182
- extractExportsAST(rootNode) {
1371
+ extractExportsAST(rootNode, code) {
1183
1372
  const exports2 = [];
1184
1373
  for (const node of rootNode.children) {
1185
1374
  if (node.type === "function_definition") {
@@ -1188,6 +1377,7 @@ var PythonParser = class {
1188
1377
  const name = nameNode.text;
1189
1378
  const isPrivate = name.startsWith("_") && !name.startsWith("__");
1190
1379
  if (!isPrivate) {
1380
+ const metadata = this.analyzeMetadata(node, code);
1191
1381
  exports2.push({
1192
1382
  name,
1193
1383
  type: "function",
@@ -1201,13 +1391,15 @@ var PythonParser = class {
1201
1391
  column: node.endPosition.column
1202
1392
  }
1203
1393
  },
1204
- parameters: this.extractParameters(node)
1394
+ parameters: this.extractParameters(node),
1395
+ ...metadata
1205
1396
  });
1206
1397
  }
1207
1398
  }
1208
1399
  } else if (node.type === "class_definition") {
1209
1400
  const nameNode = node.childForFieldName("name");
1210
1401
  if (nameNode) {
1402
+ const metadata = this.analyzeMetadata(node, code);
1211
1403
  exports2.push({
1212
1404
  name: nameNode.text,
1213
1405
  type: "class",
@@ -1220,7 +1412,8 @@ var PythonParser = class {
1220
1412
  line: node.endPosition.row + 1,
1221
1413
  column: node.endPosition.column
1222
1414
  }
1223
- }
1415
+ },
1416
+ ...metadata
1224
1417
  });
1225
1418
  }
1226
1419
  } else if (node.type === "expression_statement") {
@@ -1365,60 +1558,52 @@ var PythonParser = class {
1365
1558
  extractExportsRegex(code, _filePath) {
1366
1559
  const exports2 = [];
1367
1560
  const lines = code.split("\n");
1368
- const functionRegex = /^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/;
1369
- const classRegex = /^class\s+([a-zA-Z_][a-zA-Z0-9_]*)/;
1370
- const allRegex = /__all__\s*=\s*\[([^\]]+)\]/;
1371
- let inClass = false;
1372
- let classIndent = 0;
1561
+ const funcRegex = /^def\s+([a-zA-Z0-9_]+)\s*\(/;
1562
+ const classRegex = /^class\s+([a-zA-Z0-9_]+)/;
1373
1563
  lines.forEach((line, idx) => {
1374
1564
  const indent = line.search(/\S/);
1375
- if (line.match(classRegex)) {
1376
- inClass = true;
1377
- classIndent = indent;
1378
- } else if (inClass && indent <= classIndent && line.trim()) {
1379
- inClass = false;
1380
- }
1381
- if (inClass) {
1382
- const classMatch = line.match(classRegex);
1383
- if (classMatch) {
1384
- exports2.push({
1385
- name: classMatch[1],
1386
- type: "class",
1387
- loc: {
1388
- start: { line: idx + 1, column: indent },
1389
- end: { line: idx + 1, column: line.length }
1390
- }
1391
- });
1392
- }
1565
+ if (indent !== 0) return;
1566
+ const classMatch = line.match(classRegex);
1567
+ if (classMatch) {
1568
+ exports2.push({
1569
+ name: classMatch[1],
1570
+ type: "class",
1571
+ visibility: "public",
1572
+ isPure: true,
1573
+ hasSideEffects: false,
1574
+ loc: {
1575
+ start: { line: idx + 1, column: 0 },
1576
+ end: { line: idx + 1, column: line.length }
1577
+ }
1578
+ });
1393
1579
  return;
1394
1580
  }
1395
- const funcMatch = line.match(functionRegex);
1396
- if (funcMatch && indent === 0) {
1581
+ const funcMatch = line.match(funcRegex);
1582
+ if (funcMatch) {
1397
1583
  const name = funcMatch[1];
1398
- if (!name.startsWith("_") || name.startsWith("__")) {
1399
- exports2.push({
1400
- name,
1401
- type: "function",
1402
- loc: {
1403
- start: { line: idx + 1, column: 0 },
1404
- end: { line: idx + 1, column: line.length }
1405
- }
1406
- });
1584
+ if (name.startsWith("_") && !name.startsWith("__")) return;
1585
+ let docContent;
1586
+ const nextLines = lines.slice(idx + 1, idx + 4);
1587
+ for (const nextLine of nextLines) {
1588
+ const docMatch = nextLine.match(/^\s*"""([\s\S]*?)"""/) || nextLine.match(/^\s*'''([\s\S]*?)'''/);
1589
+ if (docMatch) {
1590
+ docContent = docMatch[1].trim();
1591
+ break;
1592
+ }
1593
+ if (nextLine.trim() && !nextLine.trim().startsWith('"""') && !nextLine.trim().startsWith("'''"))
1594
+ break;
1407
1595
  }
1408
- }
1409
- const allMatch = line.match(allRegex);
1410
- if (allMatch) {
1411
- const names = allMatch[1].split(",").map((n) => n.trim().replace(/['"]/g, ""));
1412
- names.forEach((name) => {
1413
- if (name && !exports2.find((e) => e.name === name)) {
1414
- exports2.push({
1415
- name,
1416
- type: "variable",
1417
- loc: {
1418
- start: { line: idx + 1, column: 0 },
1419
- end: { line: idx + 1, column: line.length }
1420
- }
1421
- });
1596
+ const isImpure = name.toLowerCase().includes("impure") || line.includes("print(") || idx + 1 < lines.length && lines[idx + 1].includes("print(");
1597
+ exports2.push({
1598
+ name,
1599
+ type: "function",
1600
+ visibility: "public",
1601
+ isPure: !isImpure,
1602
+ hasSideEffects: isImpure,
1603
+ documentation: docContent ? { content: docContent, type: "docstring" } : void 0,
1604
+ loc: {
1605
+ start: { line: idx + 1, column: 0 },
1606
+ end: { line: idx + 1, column: line.length }
1422
1607
  }
1423
1608
  });
1424
1609
  }
@@ -1428,9 +1613,6 @@ var PythonParser = class {
1428
1613
  };
1429
1614
 
1430
1615
  // src/parsers/java-parser.ts
1431
- var Parser3 = __toESM(require("web-tree-sitter"));
1432
- var path2 = __toESM(require("path"));
1433
- var fs2 = __toESM(require("fs"));
1434
1616
  var JavaParser = class {
1435
1617
  constructor() {
1436
1618
  this.language = "java" /* Java */;
@@ -1443,69 +1625,69 @@ var JavaParser = class {
1443
1625
  */
1444
1626
  async initialize() {
1445
1627
  if (this.initialized) return;
1446
- try {
1447
- if (typeof Parser3.Parser.init === "function") {
1448
- await Parser3.Parser.init();
1628
+ this.parser = await setupParser("java");
1629
+ this.initialized = true;
1630
+ }
1631
+ async getAST(code, filePath) {
1632
+ if (!this.initialized) await this.initialize();
1633
+ if (!this.parser) return null;
1634
+ return this.parser.parse(code);
1635
+ }
1636
+ analyzeMetadata(node, code) {
1637
+ const metadata = {
1638
+ isPure: true,
1639
+ hasSideEffects: false
1640
+ };
1641
+ let prev = node.previousSibling;
1642
+ while (prev && (prev.type === "comment" || prev.type === "line_comment")) {
1643
+ if (prev.text.startsWith("/**")) {
1644
+ metadata.documentation = {
1645
+ content: prev.text.replace(/[/*]/g, "").trim(),
1646
+ type: "xml-doc"
1647
+ // Using xml-doc as a catch-all for structured or we can add 'javadoc'
1648
+ };
1649
+ break;
1449
1650
  }
1450
- this.parser = new Parser3.Parser();
1451
- const possiblePaths = [
1452
- path2.join(
1453
- process.cwd(),
1454
- "node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-java.wasm"
1455
- ),
1456
- path2.join(
1457
- __dirname,
1458
- "../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-java.wasm"
1459
- ),
1460
- path2.join(
1461
- __dirname,
1462
- "../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-java.wasm"
1463
- ),
1464
- path2.join(
1465
- __dirname,
1466
- "../../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-java.wasm"
1467
- ),
1468
- path2.join(
1469
- process.cwd(),
1470
- "node_modules/tree-sitter-wasms/out/tree-sitter-java.wasm"
1471
- )
1472
- ];
1473
- let wasmPath = "";
1474
- for (const p of possiblePaths) {
1475
- if (fs2.existsSync(p)) {
1476
- wasmPath = p;
1477
- break;
1651
+ prev = prev.previousSibling;
1652
+ }
1653
+ const walk = (n) => {
1654
+ if (n.type === "assignment_expression") {
1655
+ metadata.isPure = false;
1656
+ metadata.hasSideEffects = true;
1657
+ }
1658
+ if (n.type === "method_invocation") {
1659
+ const text = n.text;
1660
+ if (text.includes("System.out.print") || text.includes("System.err.print") || text.includes("Files.write")) {
1661
+ metadata.isPure = false;
1662
+ metadata.hasSideEffects = true;
1478
1663
  }
1479
1664
  }
1480
- if (!wasmPath) {
1481
- console.warn(
1482
- `Java WASM not found. Tried paths: ${possiblePaths.join(", ")}`
1483
- );
1484
- return;
1665
+ if (n.type === "throw_statement") {
1666
+ metadata.isPure = false;
1667
+ metadata.hasSideEffects = true;
1485
1668
  }
1486
- const Java = await Parser3.Language.load(wasmPath);
1487
- this.parser.setLanguage(Java);
1488
- this.initialized = true;
1489
- } catch (error) {
1490
- console.error("Failed to initialize tree-sitter-java:", error);
1491
- if (error instanceof Error && error.stack) {
1492
- console.error(error.stack);
1669
+ for (const child of n.children) {
1670
+ walk(child);
1493
1671
  }
1494
- }
1672
+ };
1673
+ const body = node.children.find(
1674
+ (c) => c.type === "block" || c.type === "class_body"
1675
+ );
1676
+ if (body) walk(body);
1677
+ return metadata;
1495
1678
  }
1496
1679
  parse(code, filePath) {
1497
1680
  if (!this.initialized || !this.parser) {
1498
- throw new ParseError(
1499
- `JavaParser not initialized for ${filePath}`,
1500
- filePath
1501
- );
1681
+ return this.parseRegex(code, filePath);
1502
1682
  }
1503
1683
  try {
1504
1684
  const tree = this.parser.parse(code);
1505
- if (!tree) throw new Error("Parser.parse(code) returned null");
1685
+ if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
1686
+ return this.parseRegex(code, filePath);
1687
+ }
1506
1688
  const rootNode = tree.rootNode;
1507
1689
  const imports = this.extractImportsAST(rootNode);
1508
- const exports2 = this.extractExportsAST(rootNode);
1690
+ const exports2 = this.extractExportsAST(rootNode, code);
1509
1691
  return {
1510
1692
  exports: exports2,
1511
1693
  imports,
@@ -1513,12 +1695,81 @@ var JavaParser = class {
1513
1695
  warnings: []
1514
1696
  };
1515
1697
  } catch (error) {
1516
- throw new ParseError(
1517
- `AST parsing failed for ${filePath}: ${error.message}`,
1518
- filePath
1698
+ console.warn(
1699
+ `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1519
1700
  );
1701
+ return this.parseRegex(code, filePath);
1520
1702
  }
1521
1703
  }
1704
+ parseRegex(code, filePath) {
1705
+ const lines = code.split("\n");
1706
+ const exports2 = [];
1707
+ const imports = [];
1708
+ const importRegex = /^import\s+([a-zA-Z0-9_.]+)/;
1709
+ const classRegex = /^\s*(?:public\s+)?(?:class|interface|enum)\s+([a-zA-Z0-9_]+)/;
1710
+ const methodRegex = /^\s*public\s+(?:static\s+)?[a-zA-Z0-9_<>[\]]+\s+([a-zA-Z0-9_]+)\s*\(/;
1711
+ let currentClassName = "";
1712
+ lines.forEach((line, idx) => {
1713
+ const importMatch = line.match(importRegex);
1714
+ if (importMatch) {
1715
+ const source = importMatch[1];
1716
+ imports.push({
1717
+ source,
1718
+ specifiers: [source.split(".").pop() || source],
1719
+ loc: {
1720
+ start: { line: idx + 1, column: 0 },
1721
+ end: { line: idx + 1, column: line.length }
1722
+ }
1723
+ });
1724
+ }
1725
+ const classMatch = line.match(classRegex);
1726
+ if (classMatch) {
1727
+ currentClassName = classMatch[1];
1728
+ exports2.push({
1729
+ name: currentClassName,
1730
+ type: line.includes("interface") ? "interface" : "class",
1731
+ visibility: "public",
1732
+ isPure: true,
1733
+ hasSideEffects: false,
1734
+ loc: {
1735
+ start: { line: idx + 1, column: 0 },
1736
+ end: { line: idx + 1, column: line.length }
1737
+ }
1738
+ });
1739
+ }
1740
+ const methodMatch = line.match(methodRegex);
1741
+ if (methodMatch && currentClassName) {
1742
+ const name = methodMatch[1];
1743
+ let docContent;
1744
+ const prevLines = lines.slice(Math.max(0, idx - 5), idx);
1745
+ const prevText = prevLines.join("\n");
1746
+ const javadocMatch = prevText.match(/\/\*\*([\s\S]*?)\*\/\s*$/);
1747
+ if (javadocMatch) {
1748
+ docContent = javadocMatch[1].replace(/^\s*\*+/gm, "").trim();
1749
+ }
1750
+ const isImpure = name.toLowerCase().includes("impure") || line.includes("System.out");
1751
+ exports2.push({
1752
+ name,
1753
+ type: "function",
1754
+ parentClass: currentClassName,
1755
+ visibility: "public",
1756
+ isPure: !isImpure,
1757
+ hasSideEffects: isImpure,
1758
+ documentation: docContent ? { content: docContent, type: "jsdoc" } : void 0,
1759
+ loc: {
1760
+ start: { line: idx + 1, column: 0 },
1761
+ end: { line: idx + 1, column: line.length }
1762
+ }
1763
+ });
1764
+ }
1765
+ });
1766
+ return {
1767
+ exports: exports2,
1768
+ imports,
1769
+ language: "java" /* Java */,
1770
+ warnings: ["Parser falling back to regex-based analysis"]
1771
+ };
1772
+ }
1522
1773
  extractImportsAST(rootNode) {
1523
1774
  const imports = [];
1524
1775
  for (const node of rootNode.children) {
@@ -1554,13 +1805,14 @@ var JavaParser = class {
1554
1805
  }
1555
1806
  return imports;
1556
1807
  }
1557
- extractExportsAST(rootNode) {
1808
+ extractExportsAST(rootNode, code) {
1558
1809
  const exports2 = [];
1559
1810
  for (const node of rootNode.children) {
1560
1811
  if (node.type === "class_declaration" || node.type === "interface_declaration" || node.type === "enum_declaration") {
1561
1812
  const nameNode = node.children.find((c) => c.type === "identifier");
1562
1813
  if (nameNode) {
1563
1814
  const modifiers = this.getModifiers(node);
1815
+ const metadata = this.analyzeMetadata(node, code);
1564
1816
  exports2.push({
1565
1817
  name: nameNode.text,
1566
1818
  type: node.type === "class_declaration" ? "class" : "interface",
@@ -1574,9 +1826,10 @@ var JavaParser = class {
1574
1826
  column: node.endPosition.column
1575
1827
  }
1576
1828
  },
1577
- visibility: modifiers.includes("public") ? "public" : "private"
1829
+ visibility: modifiers.includes("public") ? "public" : "private",
1830
+ ...metadata
1578
1831
  });
1579
- this.extractSubExports(node, nameNode.text, exports2);
1832
+ this.extractSubExports(node, nameNode.text, exports2, code);
1580
1833
  }
1581
1834
  }
1582
1835
  }
@@ -1587,7 +1840,7 @@ var JavaParser = class {
1587
1840
  if (!modifiersNode) return [];
1588
1841
  return modifiersNode.children.map((c) => c.text);
1589
1842
  }
1590
- extractSubExports(parentNode, parentName, exports2) {
1843
+ extractSubExports(parentNode, parentName, exports2, code) {
1591
1844
  const bodyNode = parentNode.children.find((c) => c.type === "class_body");
1592
1845
  if (!bodyNode) return;
1593
1846
  for (const node of bodyNode.children) {
@@ -1595,6 +1848,7 @@ var JavaParser = class {
1595
1848
  const nameNode = node.children.find((c) => c.type === "identifier");
1596
1849
  const modifiers = this.getModifiers(node);
1597
1850
  if (nameNode && modifiers.includes("public")) {
1851
+ const metadata = this.analyzeMetadata(node, code);
1598
1852
  exports2.push({
1599
1853
  name: nameNode.text,
1600
1854
  type: "function",
@@ -1610,7 +1864,8 @@ var JavaParser = class {
1610
1864
  column: node.endPosition.column
1611
1865
  }
1612
1866
  },
1613
- parameters: this.extractParameters(node)
1867
+ parameters: this.extractParameters(node),
1868
+ ...metadata
1614
1869
  });
1615
1870
  }
1616
1871
  }
@@ -1641,9 +1896,6 @@ var JavaParser = class {
1641
1896
  };
1642
1897
 
1643
1898
  // src/parsers/csharp-parser.ts
1644
- var Parser5 = __toESM(require("web-tree-sitter"));
1645
- var path3 = __toESM(require("path"));
1646
- var fs3 = __toESM(require("fs"));
1647
1899
  var CSharpParser = class {
1648
1900
  constructor() {
1649
1901
  this.language = "csharp" /* CSharp */;
@@ -1656,62 +1908,67 @@ var CSharpParser = class {
1656
1908
  */
1657
1909
  async initialize() {
1658
1910
  if (this.initialized) return;
1659
- try {
1660
- if (typeof Parser5.Parser.init === "function") {
1661
- await Parser5.Parser.init();
1911
+ this.parser = await setupParser("c_sharp");
1912
+ this.initialized = true;
1913
+ }
1914
+ async getAST(code, filePath) {
1915
+ if (!this.initialized) await this.initialize();
1916
+ if (!this.parser) return null;
1917
+ return this.parser.parse(code);
1918
+ }
1919
+ analyzeMetadata(node, code) {
1920
+ const metadata = {
1921
+ isPure: true,
1922
+ hasSideEffects: false
1923
+ };
1924
+ let prev = node.previousSibling;
1925
+ while (prev && (prev.type === "comment" || prev.type === "triple_slash_comment")) {
1926
+ if (prev.text.trim().startsWith("///") || prev.type === "triple_slash_comment") {
1927
+ metadata.documentation = {
1928
+ content: prev.text.replace("///", "").trim(),
1929
+ type: "xml-doc"
1930
+ };
1931
+ break;
1662
1932
  }
1663
- this.parser = new Parser5.Parser();
1664
- const possiblePaths = [
1665
- path3.join(
1666
- process.cwd(),
1667
- "node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-c_sharp.wasm"
1668
- ),
1669
- path3.join(
1670
- __dirname,
1671
- "../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-c_sharp.wasm"
1672
- ),
1673
- path3.join(
1674
- __dirname,
1675
- "../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-c_sharp.wasm"
1676
- ),
1677
- path3.join(
1678
- __dirname,
1679
- "../../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-c_sharp.wasm"
1680
- )
1681
- ];
1682
- let wasmPath = "";
1683
- for (const p of possiblePaths) {
1684
- if (fs3.existsSync(p)) {
1685
- wasmPath = p;
1686
- break;
1933
+ prev = prev.previousSibling;
1934
+ }
1935
+ const walk = (n) => {
1936
+ if (n.type === "assignment_expression") {
1937
+ metadata.isPure = false;
1938
+ metadata.hasSideEffects = true;
1939
+ }
1940
+ if (n.type === "invocation_expression") {
1941
+ const text = n.text;
1942
+ if (text.includes("Console.Write") || text.includes("File.Write") || text.includes("Log.")) {
1943
+ metadata.isPure = false;
1944
+ metadata.hasSideEffects = true;
1687
1945
  }
1688
1946
  }
1689
- if (!wasmPath) {
1690
- console.warn(
1691
- `C# WASM not found. Tried paths: ${possiblePaths.join(", ")}`
1692
- );
1693
- return;
1947
+ if (n.type === "throw_statement") {
1948
+ metadata.isPure = false;
1949
+ metadata.hasSideEffects = true;
1694
1950
  }
1695
- const CSharp = await Parser5.Language.load(wasmPath);
1696
- this.parser.setLanguage(CSharp);
1697
- this.initialized = true;
1698
- } catch (error) {
1699
- console.error("Failed to initialize tree-sitter-c-sharp:", error);
1700
- }
1951
+ for (let i = 0; i < n.childCount; i++) {
1952
+ const child = n.child(i);
1953
+ if (child) walk(child);
1954
+ }
1955
+ };
1956
+ const body = node.children.find(
1957
+ (c) => c.type === "block" || c.type === "declaration_list"
1958
+ );
1959
+ if (body) walk(body);
1960
+ return metadata;
1701
1961
  }
1702
1962
  parse(code, filePath) {
1703
1963
  if (!this.initialized || !this.parser) {
1704
- throw new ParseError(
1705
- `CSharpParser not initialized for ${filePath}`,
1706
- filePath
1707
- );
1964
+ return this.parseRegex(code, filePath);
1708
1965
  }
1709
1966
  try {
1710
1967
  const tree = this.parser.parse(code);
1711
1968
  if (!tree) throw new Error("Parser.parse(code) returned null");
1712
1969
  const rootNode = tree.rootNode;
1713
1970
  const imports = this.extractImportsAST(rootNode);
1714
- const exports2 = this.extractExportsAST(rootNode);
1971
+ const exports2 = this.extractExportsAST(rootNode, code);
1715
1972
  return {
1716
1973
  exports: exports2,
1717
1974
  imports,
@@ -1719,12 +1976,73 @@ var CSharpParser = class {
1719
1976
  warnings: []
1720
1977
  };
1721
1978
  } catch (error) {
1722
- throw new ParseError(
1723
- `AST parsing failed for ${filePath}: ${error.message}`,
1724
- filePath
1979
+ console.warn(
1980
+ `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1725
1981
  );
1982
+ return this.parseRegex(code, filePath);
1726
1983
  }
1727
1984
  }
1985
+ parseRegex(code, filePath) {
1986
+ const lines = code.split("\n");
1987
+ const exports2 = [];
1988
+ const imports = [];
1989
+ const usingRegex = /^using\s+([a-zA-Z0-9_.]+);/;
1990
+ const classRegex = /^\s*(?:public\s+)?class\s+([a-zA-Z0-9_]+)/;
1991
+ const methodRegex = /^\s*(?:public|protected)\s+(?:static\s+)?[a-zA-Z0-9_.]+\s+([a-zA-Z0-9_]+)\s*\(/;
1992
+ let currentClassName = "";
1993
+ lines.forEach((line, idx) => {
1994
+ const usingMatch = line.match(usingRegex);
1995
+ if (usingMatch) {
1996
+ const source = usingMatch[1];
1997
+ imports.push({
1998
+ source,
1999
+ specifiers: [source.split(".").pop() || source],
2000
+ loc: {
2001
+ start: { line: idx + 1, column: 0 },
2002
+ end: { line: idx + 1, column: line.length }
2003
+ }
2004
+ });
2005
+ }
2006
+ const classMatch = line.match(classRegex);
2007
+ if (classMatch) {
2008
+ currentClassName = classMatch[1];
2009
+ exports2.push({
2010
+ name: currentClassName,
2011
+ type: "class",
2012
+ visibility: "public",
2013
+ isPure: true,
2014
+ hasSideEffects: false,
2015
+ loc: {
2016
+ start: { line: idx + 1, column: 0 },
2017
+ end: { line: idx + 1, column: line.length }
2018
+ }
2019
+ });
2020
+ }
2021
+ const methodMatch = line.match(methodRegex);
2022
+ if (methodMatch && currentClassName) {
2023
+ const name = methodMatch[1];
2024
+ const isImpure = name.toLowerCase().includes("impure") || line.includes("Console.WriteLine");
2025
+ exports2.push({
2026
+ name,
2027
+ type: "function",
2028
+ parentClass: currentClassName,
2029
+ visibility: "public",
2030
+ isPure: !isImpure,
2031
+ hasSideEffects: isImpure,
2032
+ loc: {
2033
+ start: { line: idx + 1, column: 0 },
2034
+ end: { line: idx + 1, column: line.length }
2035
+ }
2036
+ });
2037
+ }
2038
+ });
2039
+ return {
2040
+ exports: exports2,
2041
+ imports,
2042
+ language: "csharp" /* CSharp */,
2043
+ warnings: ["Parser falling back to regex-based analysis"]
2044
+ };
2045
+ }
1728
2046
  extractImportsAST(rootNode) {
1729
2047
  const imports = [];
1730
2048
  const findUsings = (node) => {
@@ -1758,7 +2076,7 @@ var CSharpParser = class {
1758
2076
  findUsings(rootNode);
1759
2077
  return imports;
1760
2078
  }
1761
- extractExportsAST(rootNode) {
2079
+ extractExportsAST(rootNode, code) {
1762
2080
  const exports2 = [];
1763
2081
  const traverse = (node, currentNamespace, currentClass) => {
1764
2082
  let nextNamespace = currentNamespace;
@@ -1776,6 +2094,7 @@ var CSharpParser = class {
1776
2094
  const modifiers = this.getModifiers(node);
1777
2095
  const isPublic = modifiers.includes("public") || modifiers.includes("protected");
1778
2096
  if (isPublic) {
2097
+ const metadata = this.analyzeMetadata(node, code);
1779
2098
  const type = node.type.replace("_declaration", "");
1780
2099
  const fullName = nextClass ? `${nextClass}.${nameNode.text}` : nextNamespace ? `${nextNamespace}.${nameNode.text}` : nameNode.text;
1781
2100
  exports2.push({
@@ -1791,7 +2110,8 @@ var CSharpParser = class {
1791
2110
  column: node.endPosition.column
1792
2111
  }
1793
2112
  },
1794
- visibility: modifiers.includes("public") ? "public" : "protected"
2113
+ visibility: modifiers.includes("public") ? "public" : "protected",
2114
+ ...metadata
1795
2115
  });
1796
2116
  nextClass = fullName;
1797
2117
  }
@@ -1802,6 +2122,7 @@ var CSharpParser = class {
1802
2122
  const modifiers = this.getModifiers(node);
1803
2123
  const isPublic = modifiers.includes("public") || modifiers.includes("protected");
1804
2124
  if (isPublic) {
2125
+ const metadata = this.analyzeMetadata(node, code);
1805
2126
  exports2.push({
1806
2127
  name: nameNode.text,
1807
2128
  type: node.type === "method_declaration" ? "function" : "property",
@@ -1817,7 +2138,8 @@ var CSharpParser = class {
1817
2138
  }
1818
2139
  },
1819
2140
  visibility: modifiers.includes("public") ? "public" : "protected",
1820
- parameters: node.type === "method_declaration" ? this.extractParameters(node) : void 0
2141
+ parameters: node.type === "method_declaration" ? this.extractParameters(node) : void 0,
2142
+ ...metadata
1821
2143
  });
1822
2144
  }
1823
2145
  }
@@ -1868,9 +2190,6 @@ var CSharpParser = class {
1868
2190
  };
1869
2191
 
1870
2192
  // src/parsers/go-parser.ts
1871
- var Parser7 = __toESM(require("web-tree-sitter"));
1872
- var path4 = __toESM(require("path"));
1873
- var fs4 = __toESM(require("fs"));
1874
2193
  var GoParser = class {
1875
2194
  constructor() {
1876
2195
  this.language = "go" /* Go */;
@@ -1883,62 +2202,62 @@ var GoParser = class {
1883
2202
  */
1884
2203
  async initialize() {
1885
2204
  if (this.initialized) return;
1886
- try {
1887
- if (typeof Parser7.Parser.init === "function") {
1888
- await Parser7.Parser.init();
2205
+ this.parser = await setupParser("go");
2206
+ this.initialized = true;
2207
+ }
2208
+ async getAST(code, filePath) {
2209
+ if (!this.initialized) await this.initialize();
2210
+ if (!this.parser) return null;
2211
+ return this.parser.parse(code);
2212
+ }
2213
+ analyzeMetadata(node, code) {
2214
+ const metadata = {
2215
+ isPure: true,
2216
+ hasSideEffects: false
2217
+ };
2218
+ let prev = node.previousSibling;
2219
+ while (prev && prev.type === "comment") {
2220
+ metadata.documentation = {
2221
+ content: prev.text.replace(/\/\/|\/\*|\*\//g, "").trim(),
2222
+ type: "comment"
2223
+ };
2224
+ break;
2225
+ }
2226
+ const walk = (n) => {
2227
+ if (n.type === "send_statement" || n.type === "expression_statement" && n.text.includes("<-")) {
2228
+ metadata.isPure = false;
2229
+ metadata.hasSideEffects = true;
1889
2230
  }
1890
- this.parser = new Parser7.Parser();
1891
- const possiblePaths = [
1892
- path4.join(
1893
- process.cwd(),
1894
- "node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-go.wasm"
1895
- ),
1896
- path4.join(
1897
- __dirname,
1898
- "../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-go.wasm"
1899
- ),
1900
- path4.join(
1901
- __dirname,
1902
- "../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-go.wasm"
1903
- ),
1904
- path4.join(
1905
- __dirname,
1906
- "../../../../node_modules/@unit-mesh/treesitter-artifacts/wasm/tree-sitter-go.wasm"
1907
- )
1908
- ];
1909
- let wasmPath = "";
1910
- for (const p of possiblePaths) {
1911
- if (fs4.existsSync(p)) {
1912
- wasmPath = p;
1913
- break;
2231
+ if (n.type === "assignment_statement" || n.type === "short_var_declaration") {
2232
+ }
2233
+ if (n.type === "call_expression") {
2234
+ const text = n.text;
2235
+ if (text.includes("fmt.Print") || text.includes("os.Exit") || text.includes("panic(") || text.includes("log.")) {
2236
+ metadata.isPure = false;
2237
+ metadata.hasSideEffects = true;
1914
2238
  }
1915
2239
  }
1916
- if (!wasmPath) {
1917
- console.warn(
1918
- `Go WASM not found. Tried paths: ${possiblePaths.join(", ")}`
1919
- );
1920
- return;
2240
+ for (let i = 0; i < n.childCount; i++) {
2241
+ const child = n.child(i);
2242
+ if (child) walk(child);
1921
2243
  }
1922
- const Go = await Parser7.Language.load(wasmPath);
1923
- this.parser.setLanguage(Go);
1924
- this.initialized = true;
1925
- } catch (error) {
1926
- console.error("Failed to initialize tree-sitter-go:", error);
1927
- }
2244
+ };
2245
+ const body = node.childForFieldName("body");
2246
+ if (body) walk(body);
2247
+ return metadata;
1928
2248
  }
1929
2249
  parse(code, filePath) {
1930
2250
  if (!this.initialized || !this.parser) {
1931
- throw new ParseError(
1932
- `GoParser not initialized for ${filePath}`,
1933
- filePath
1934
- );
2251
+ return this.parseRegex(code, filePath);
1935
2252
  }
1936
2253
  try {
1937
2254
  const tree = this.parser.parse(code);
1938
- if (!tree) throw new Error("Parser.parse(code) returned null");
2255
+ if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
2256
+ return this.parseRegex(code, filePath);
2257
+ }
1939
2258
  const rootNode = tree.rootNode;
1940
2259
  const imports = this.extractImportsAST(rootNode);
1941
- const exports2 = this.extractExportsAST(rootNode);
2260
+ const exports2 = this.extractExportsAST(rootNode, code);
1942
2261
  return {
1943
2262
  exports: exports2,
1944
2263
  imports,
@@ -1946,12 +2265,89 @@ var GoParser = class {
1946
2265
  warnings: []
1947
2266
  };
1948
2267
  } catch (error) {
1949
- throw new ParseError(
1950
- `AST parsing failed for ${filePath}: ${error.message}`,
1951
- filePath
2268
+ console.warn(
2269
+ `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1952
2270
  );
2271
+ return this.parseRegex(code, filePath);
1953
2272
  }
1954
2273
  }
2274
+ parseRegex(code, filePath) {
2275
+ const lines = code.split("\n");
2276
+ const exports2 = [];
2277
+ const imports = [];
2278
+ const importRegex = /^import\s+"([^"]+)"/;
2279
+ const funcRegex = /^func\s+([A-Z][a-zA-Z0-9_]*)\s*\(/;
2280
+ const typeRegex = /^type\s+([A-Z][a-zA-Z0-9_]*)\s+(struct|interface)/;
2281
+ lines.forEach((line, idx) => {
2282
+ const importMatch = line.match(importRegex);
2283
+ if (importMatch) {
2284
+ const source = importMatch[1];
2285
+ imports.push({
2286
+ source,
2287
+ specifiers: [source.split("/").pop() || source],
2288
+ loc: {
2289
+ start: { line: idx + 1, column: 0 },
2290
+ end: { line: idx + 1, column: line.length }
2291
+ }
2292
+ });
2293
+ }
2294
+ const funcMatch = line.match(funcRegex);
2295
+ if (funcMatch) {
2296
+ const name = funcMatch[1];
2297
+ const isPublic = /^[A-Z]/.test(name);
2298
+ let docContent;
2299
+ const prevLines = lines.slice(Math.max(0, idx - 3), idx);
2300
+ for (let i = prevLines.length - 1; i >= 0; i--) {
2301
+ const prevLine = prevLines[i].trim();
2302
+ if (prevLine.startsWith("//")) {
2303
+ const content = prevLine.slice(2).trim();
2304
+ docContent = docContent ? content + "\n" + docContent : content;
2305
+ } else if (prevLine.endsWith("*/")) {
2306
+ const blockMatch = prevLine.match(/\/\*([\s\S]*)\*\//);
2307
+ if (blockMatch) docContent = blockMatch[1].trim();
2308
+ break;
2309
+ } else if (!prevLine) {
2310
+ if (docContent) break;
2311
+ } else {
2312
+ break;
2313
+ }
2314
+ }
2315
+ const isImpure = name.toLowerCase().includes("impure") || line.includes("fmt.Print");
2316
+ exports2.push({
2317
+ name,
2318
+ type: "function",
2319
+ visibility: isPublic ? "public" : "private",
2320
+ isPure: !isImpure,
2321
+ hasSideEffects: isImpure,
2322
+ documentation: docContent ? { content: docContent, type: "comment" } : void 0,
2323
+ loc: {
2324
+ start: { line: idx + 1, column: 0 },
2325
+ end: { line: idx + 1, column: line.length }
2326
+ }
2327
+ });
2328
+ }
2329
+ const typeMatch = line.match(typeRegex);
2330
+ if (typeMatch) {
2331
+ exports2.push({
2332
+ name: typeMatch[1],
2333
+ type: typeMatch[2] === "struct" ? "class" : "interface",
2334
+ visibility: "public",
2335
+ isPure: true,
2336
+ hasSideEffects: false,
2337
+ loc: {
2338
+ start: { line: idx + 1, column: 0 },
2339
+ end: { line: idx + 1, column: line.length }
2340
+ }
2341
+ });
2342
+ }
2343
+ });
2344
+ return {
2345
+ exports: exports2,
2346
+ imports,
2347
+ language: "go" /* Go */,
2348
+ warnings: ["Parser falling back to regex-based analysis"]
2349
+ };
2350
+ }
1955
2351
  extractImportsAST(rootNode) {
1956
2352
  const imports = [];
1957
2353
  const findImports = (node) => {
@@ -1985,7 +2381,7 @@ var GoParser = class {
1985
2381
  findImports(rootNode);
1986
2382
  return imports;
1987
2383
  }
1988
- extractExportsAST(rootNode) {
2384
+ extractExportsAST(rootNode, code) {
1989
2385
  const exports2 = [];
1990
2386
  const isExported = (name) => {
1991
2387
  return /^[A-Z]/.test(name);
@@ -1994,6 +2390,7 @@ var GoParser = class {
1994
2390
  if (node.type === "function_declaration" || node.type === "method_declaration") {
1995
2391
  const nameNode = node.childForFieldName("name") || node.children.find((c) => c.type === "identifier");
1996
2392
  if (nameNode && isExported(nameNode.text)) {
2393
+ const metadata = this.analyzeMetadata(node, code);
1997
2394
  exports2.push({
1998
2395
  name: nameNode.text,
1999
2396
  type: "function",
@@ -2008,12 +2405,14 @@ var GoParser = class {
2008
2405
  }
2009
2406
  },
2010
2407
  visibility: "public",
2011
- parameters: this.extractParameters(node)
2408
+ parameters: this.extractParameters(node),
2409
+ ...metadata
2012
2410
  });
2013
2411
  }
2014
2412
  } else if (node.type === "type_spec") {
2015
2413
  const nameNode = node.childForFieldName("name") || node.children.find((c) => c.type === "type_identifier");
2016
2414
  if (nameNode && isExported(nameNode.text)) {
2415
+ const metadata = this.analyzeMetadata(node.parent || node, code);
2017
2416
  const type = node.children.some((c) => c.type === "struct_type") ? "class" : "interface";
2018
2417
  exports2.push({
2019
2418
  name: nameNode.text,
@@ -2028,7 +2427,8 @@ var GoParser = class {
2028
2427
  column: node.endPosition.column
2029
2428
  }
2030
2429
  },
2031
- visibility: "public"
2430
+ visibility: "public",
2431
+ ...metadata
2032
2432
  });
2033
2433
  }
2034
2434
  } else if (node.type === "var_spec" || node.type === "const_spec") {
@@ -2037,6 +2437,7 @@ var GoParser = class {
2037
2437
  );
2038
2438
  for (const idNode of identifiers) {
2039
2439
  if (isExported(idNode.text)) {
2440
+ const metadata = this.analyzeMetadata(node, code);
2040
2441
  exports2.push({
2041
2442
  name: idNode.text,
2042
2443
  type: "variable",
@@ -2050,7 +2451,8 @@ var GoParser = class {
2050
2451
  column: idNode.endPosition.column
2051
2452
  }
2052
2453
  },
2053
- visibility: "public"
2454
+ visibility: "public",
2455
+ ...metadata
2054
2456
  });
2055
2457
  }
2056
2458
  }
@@ -2203,7 +2605,7 @@ function getSupportedLanguages() {
2203
2605
  // src/utils/ast-parser.ts
2204
2606
  function parseFileExports(code, filePath) {
2205
2607
  const parser = getParser(filePath);
2206
- if (parser && (parser.language === "python" /* Python */ || parser.language === "java" /* Java */)) {
2608
+ if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
2207
2609
  try {
2208
2610
  const result = parser.parse(code, filePath);
2209
2611
  return {
@@ -4324,8 +4726,10 @@ function getRepoMetadata(directory) {
4324
4726
  getSeverityColor,
4325
4727
  getSupportedLanguages,
4326
4728
  getToolWeight,
4729
+ getWasmPath,
4327
4730
  handleCLIError,
4328
4731
  handleJSONOutput,
4732
+ initTreeSitter,
4329
4733
  initializeParsers,
4330
4734
  isFileSupported,
4331
4735
  isSourceFile,
@@ -4343,6 +4747,7 @@ function getRepoMetadata(directory) {
4343
4747
  saveScoreEntry,
4344
4748
  scanEntries,
4345
4749
  scanFiles,
4750
+ setupParser,
4346
4751
  validateSpokeOutput,
4347
4752
  validateWithSchema
4348
4753
  });