ucn 3.7.35 → 3.7.36

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.
Files changed (2) hide show
  1. package/core/project.js +52 -14
  2. package/package.json +1 -1
package/core/project.js CHANGED
@@ -1705,12 +1705,21 @@ class ProjectIndex {
1705
1705
 
1706
1706
  /**
1707
1707
  * Extract type names from a function definition
1708
- * Finds all word-like type identifiers from param types and return type,
1709
- * then filters to only those that exist in the project symbol table.
1708
+ * Finds all word-like type identifiers from param types, return type,
1709
+ * class membership, and function body filters to project-defined types only.
1710
1710
  */
1711
1711
  extractTypeNames(def) {
1712
+ const TYPE_KINDS = ['type', 'interface', 'class', 'struct'];
1712
1713
  const types = new Set();
1713
- // Collect all type annotation strings
1714
+
1715
+ const addIfType = (name) => {
1716
+ const syms = this.symbols.get(name);
1717
+ if (syms && syms.some(s => TYPE_KINDS.includes(s.type))) {
1718
+ types.add(name);
1719
+ }
1720
+ };
1721
+
1722
+ // 1. From param and return type annotations
1714
1723
  const typeStrings = [];
1715
1724
  if (def.paramsStructured) {
1716
1725
  for (const param of def.paramsStructured) {
@@ -1718,17 +1727,30 @@ class ProjectIndex {
1718
1727
  }
1719
1728
  }
1720
1729
  if (def.returnType) typeStrings.push(def.returnType);
1721
-
1722
- // Extract all word-like identifiers from type annotations
1723
- // Handles: Dict[str, Any], Optional[QuoteData], str | None, List[int], CustomType
1724
1730
  for (const ts of typeStrings) {
1725
1731
  const matches = ts.match(/\b([A-Za-z_]\w*)\b/g);
1726
1732
  if (matches) {
1727
- for (const m of matches) {
1728
- // Only include names that exist as type/interface/class/struct in the symbol table
1729
- const syms = this.symbols.get(m);
1730
- if (syms && syms.some(s => ['type', 'interface', 'class', 'struct'].includes(s.type))) {
1731
- types.add(m);
1733
+ for (const m of matches) addIfType(m);
1734
+ }
1735
+ }
1736
+
1737
+ // 2. From the class the method belongs to
1738
+ if (def.className) addIfType(def.className);
1739
+
1740
+ // 3. From function body — scan for project-defined type references
1741
+ // (constructors, type annotations, isinstance checks)
1742
+ if (types.size === 0) {
1743
+ const code = this.extractCode(def);
1744
+ if (code) {
1745
+ // Find capitalized identifiers that match project types
1746
+ const bodyMatches = code.match(/\b([A-Z][A-Za-z0-9_]*)\b/g);
1747
+ if (bodyMatches) {
1748
+ const seen = new Set();
1749
+ for (const m of bodyMatches) {
1750
+ if (!seen.has(m)) {
1751
+ seen.add(m);
1752
+ addIfType(m);
1753
+ }
1732
1754
  }
1733
1755
  }
1734
1756
  }
@@ -2917,12 +2939,16 @@ class ProjectIndex {
2917
2939
  // Get type definitions if requested
2918
2940
  let types = [];
2919
2941
  if (options.withTypes) {
2920
- const typeNames = this.extractTypeNames(primary);
2921
- for (const typeName of typeNames) {
2942
+ const TYPE_KINDS = ['type', 'interface', 'class', 'struct'];
2943
+ const seen = new Set();
2944
+
2945
+ const addType = (typeName) => {
2946
+ if (seen.has(typeName)) return;
2947
+ seen.add(typeName);
2922
2948
  const typeSymbols = this.symbols.get(typeName);
2923
2949
  if (typeSymbols) {
2924
2950
  for (const sym of typeSymbols) {
2925
- if (['type', 'interface', 'class', 'struct'].includes(sym.type)) {
2951
+ if (TYPE_KINDS.includes(sym.type)) {
2926
2952
  types.push({
2927
2953
  name: sym.name,
2928
2954
  type: sym.type,
@@ -2932,6 +2958,18 @@ class ProjectIndex {
2932
2958
  }
2933
2959
  }
2934
2960
  }
2961
+ };
2962
+
2963
+ // From signature annotations
2964
+ const typeNames = this.extractTypeNames(primary);
2965
+ for (const typeName of typeNames) addType(typeName);
2966
+
2967
+ // From callee signatures — types used by functions this function calls
2968
+ if (allCallees) {
2969
+ for (const callee of allCallees) {
2970
+ const calleeTypeNames = this.extractTypeNames(callee);
2971
+ for (const tn of calleeTypeNames) addType(tn);
2972
+ }
2935
2973
  }
2936
2974
  }
2937
2975
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucn",
3
- "version": "3.7.35",
3
+ "version": "3.7.36",
4
4
  "mcpName": "io.github.mleoca/ucn",
5
5
  "description": "Universal Code Navigator — AST-based call graph analysis for AI agents. Find callers, trace impact, detect dead code across JS/TS, Python, Go, Rust, Java, and HTML. CLI, MCP server, and agent skill.",
6
6
  "main": "index.js",