ucn 3.1.2 → 3.1.3

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.
@@ -1248,8 +1248,9 @@ function findUsagesInCode(code, name, parser) {
1248
1248
  const usages = [];
1249
1249
 
1250
1250
  traverseTree(tree.rootNode, (node) => {
1251
- // Only look for identifiers with the matching name
1252
- if (node.type !== 'identifier' || node.text !== name) {
1251
+ // Look for both identifier and property_identifier (method names in obj.method() calls)
1252
+ const isIdentifier = node.type === 'identifier' || node.type === 'property_identifier';
1253
+ if (!isIdentifier || node.text !== name) {
1253
1254
  return true;
1254
1255
  }
1255
1256
 
@@ -1318,6 +1319,17 @@ function findUsagesInCode(code, name, parser) {
1318
1319
  // Property access (method call): a.name() - the name after dot
1319
1320
  else if (parent.type === 'member_expression' &&
1320
1321
  parent.childForFieldName('property') === node) {
1322
+ // Skip built-in objects and common module names (JSON.parse, path.parse, etc.)
1323
+ const object = parent.childForFieldName('object');
1324
+ const builtins = [
1325
+ // JS built-in objects
1326
+ 'JSON', 'Math', 'console', 'Object', 'Array', 'String', 'Number', 'Date', 'RegExp', 'Promise', 'Reflect', 'Proxy', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Symbol', 'Intl', 'WebAssembly', 'Atomics', 'SharedArrayBuffer', 'ArrayBuffer', 'DataView', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', 'URL', 'URLSearchParams',
1327
+ // Node.js core modules
1328
+ 'path', 'fs', 'os', 'http', 'https', 'net', 'dgram', 'dns', 'tls', 'crypto', 'zlib', 'stream', 'util', 'events', 'buffer', 'child_process', 'cluster', 'readline', 'repl', 'vm', 'assert', 'querystring', 'url', 'punycode', 'string_decoder', 'timers', 'tty', 'v8', 'perf_hooks', 'worker_threads', 'inspector', 'trace_events', 'async_hooks', 'process'
1329
+ ];
1330
+ if (object && object.type === 'identifier' && builtins.includes(object.text)) {
1331
+ return true; // Skip built-in method calls
1332
+ }
1321
1333
  // Check if this is a method call
1322
1334
  const grandparent = parent.parent;
1323
1335
  if (grandparent && grandparent.type === 'call_expression') {
package/languages/rust.js CHANGED
@@ -910,8 +910,9 @@ function findUsagesInCode(code, name, parser) {
910
910
  const usages = [];
911
911
 
912
912
  traverseTree(tree.rootNode, (node) => {
913
- // Only look for identifiers with the matching name
914
- if (node.type !== 'identifier' || node.text !== name) {
913
+ // Look for both identifier and field_identifier (method names in obj.method() calls)
914
+ const isIdentifier = node.type === 'identifier' || node.type === 'field_identifier';
915
+ if (!isIdentifier || node.text !== name) {
915
916
  return true;
916
917
  }
917
918
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucn",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Code navigation built by AI, for AI. Reduces context usage when working with large codebases.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -4459,6 +4459,82 @@ func (s *ServiceB) Process() error {
4459
4459
  fs.rmSync(tmpDir, { recursive: true, force: true });
4460
4460
  }
4461
4461
  });
4462
+
4463
+ it('should detect JavaScript method calls but filter built-ins', () => {
4464
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ucn-js-method-'));
4465
+ try {
4466
+ fs.writeFileSync(path.join(tmpDir, 'test.js'), `
4467
+ class Service {
4468
+ process() {}
4469
+ }
4470
+
4471
+ function main() {
4472
+ const svc = new Service();
4473
+ svc.process(); // user method - SHOULD be counted
4474
+ JSON.parse('{}'); // built-in - should NOT be counted
4475
+ process(); // direct call - SHOULD be counted
4476
+ }
4477
+ `);
4478
+
4479
+ const index = new ProjectIndex(tmpDir);
4480
+ index.build('**/*.js', { quiet: true });
4481
+
4482
+ const usages = index.usages('process', { codeOnly: true });
4483
+ const calls = usages.filter(u => u.usageType === 'call' && !u.isDefinition);
4484
+
4485
+ // Should find 2 calls: svc.process() and process()
4486
+ assert.strictEqual(calls.length, 2, 'Should find 2 calls (user method + direct)');
4487
+
4488
+ // Should NOT include JSON.parse
4489
+ const hasJsonParse = calls.some(c => c.content && c.content.includes('JSON.parse'));
4490
+ assert.strictEqual(hasJsonParse, false, 'JSON.parse should NOT be counted');
4491
+
4492
+ // Should include svc.process()
4493
+ const hasUserMethod = calls.some(c => c.content && c.content.includes('svc.process'));
4494
+ assert.strictEqual(hasUserMethod, true, 'svc.process() SHOULD be counted');
4495
+ } finally {
4496
+ fs.rmSync(tmpDir, { recursive: true, force: true });
4497
+ }
4498
+ });
4499
+
4500
+ it('should detect Rust method calls in usages', () => {
4501
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ucn-rust-method-'));
4502
+ try {
4503
+ fs.writeFileSync(path.join(tmpDir, 'Cargo.toml'), `[package]
4504
+ name = "test"
4505
+ version = "0.1.0"
4506
+ `);
4507
+
4508
+ fs.writeFileSync(path.join(tmpDir, 'main.rs'), `
4509
+ struct Client {}
4510
+
4511
+ impl Client {
4512
+ fn process(&self) {}
4513
+ }
4514
+
4515
+ fn main() {
4516
+ let c = Client{};
4517
+ c.process();
4518
+ process();
4519
+ }
4520
+ `);
4521
+
4522
+ const index = new ProjectIndex(tmpDir);
4523
+ index.build('**/*.rs', { quiet: true });
4524
+
4525
+ const usages = index.usages('process', { codeOnly: true });
4526
+ const calls = usages.filter(u => u.usageType === 'call' && !u.isDefinition);
4527
+
4528
+ // Should find 2 calls: c.process() and process()
4529
+ assert.ok(calls.length >= 2, 'Should find at least 2 calls');
4530
+
4531
+ // Should include c.process()
4532
+ const hasMethodCall = calls.some(c => c.content && c.content.includes('c.process'));
4533
+ assert.strictEqual(hasMethodCall, true, 'c.process() SHOULD be counted');
4534
+ } finally {
4535
+ fs.rmSync(tmpDir, { recursive: true, force: true });
4536
+ }
4537
+ });
4462
4538
  });
4463
4539
 
4464
4540
  console.log('UCN v3 Test Suite');